├── .editorconfig ├── .eslintrc ├── .github ├── stale.yml └── workflows │ ├── gh-pages.yml │ ├── main.yml │ └── size.yml ├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .storybook ├── main.js └── preview.js ├── .vscode └── settings.json ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── images ├── css_classes.png ├── default.png ├── flipped.png ├── overlay.png └── rainbow.png ├── package-lock.json ├── package.json ├── src ├── CookieConsent.props.tsx ├── CookieConsent.state.ts ├── CookieConsent.tsx ├── components │ └── ConditionalWrapper.tsx ├── index.tsx ├── models │ └── constants │ │ ├── defaultCookieName.ts │ │ ├── index.ts │ │ ├── positionOptions.ts │ │ ├── sameSiteOptions.ts │ │ └── visibilityOptions.ts └── utilities.ts ├── stale.yml ├── stories ├── defaults │ ├── intro.tsx │ ├── storyProps.ts │ └── template.tsx ├── index.stories.tsx └── stories │ ├── acceptOnScroll.story.tsx │ ├── additionalButtons.story.tsx │ ├── customStyling.story.tsx │ ├── flippedButtons.story.tsx │ ├── muiButtons.story.ts │ ├── onAccept.story.tsx │ ├── overlay.story.tsx │ └── rainbows.story.tsx └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | indent_style = space 9 | indent_size = 2 10 | 11 | [Makefile] 12 | indent_style = tab 13 | indent_size = 8 14 | 15 | [{deps,tools,build}/**] 16 | indent_style = ignore 17 | indent_size = ignore 18 | end_of_line = ignore 19 | trim_trailing_whitespace = ignore 20 | charset = ignore 21 | 22 | [{test/fixtures,deps,build,tools/eslint,tools/gyp,tools/icu,tools/msvs}/**] 23 | insert_final_newline = false 24 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "jest": true, 5 | "es6": true 6 | }, 7 | "plugins": ["import"], 8 | "extends": [ 9 | "react-app", 10 | "prettier/@typescript-eslint", 11 | "plugin:prettier/recommended", 12 | "eslint:recommended", 13 | "prettier" 14 | ], 15 | "parserOptions": { 16 | "ecmaVersion": 2020, 17 | "sourceType": "module" 18 | }, 19 | "rules": { 20 | "react/react-in-jsx-scope": "off", 21 | "no-console": [ 22 | "error", 23 | { 24 | "allow": ["debug", "error"] 25 | } 26 | ], 27 | "no-eval": "error", 28 | "import/first": "error", 29 | "camelcase": [ 30 | "error", 31 | { 32 | "ignoreImports": true, 33 | "ignoreDestructuring": true 34 | } 35 | ], 36 | "consistent-return": "warn", 37 | "constructor-super": "error", 38 | "curly": "error", 39 | "eol-last": "warn", 40 | "eqeqeq": ["error", "smart"], 41 | "import/order": 1, 42 | "new-parens": "error", 43 | "no-debugger": "error", 44 | "no-fallthrough": "off", 45 | "max-len": [ 46 | "warn", 47 | { 48 | "code": 120 49 | } 50 | ], 51 | "no-shadow": [ 52 | "error", 53 | { 54 | "hoist": "all" 55 | } 56 | ], 57 | "no-trailing-spaces": "warn", 58 | "no-underscore-dangle": "error", 59 | "no-unsafe-finally": "error", 60 | "no-var": "error", 61 | "object-shorthand": "error", 62 | "one-var": ["error", "never"], 63 | "prefer-arrow/prefer-arrow-functions": "off", 64 | "prefer-const": "error", 65 | "radix": "off", 66 | "space-in-parens": ["off", "never"] 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 30 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false 18 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy storybook 2 | on: [push] 3 | permissions: 4 | contents: write 5 | jobs: 6 | build-and-deploy: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 🛎️ 10 | uses: actions/checkout@v3 11 | 12 | - name: Install and Build 🔧 13 | run: | 14 | npm install 15 | npm run build-storybook 16 | 17 | - name: Deploy 🚀 18 | uses: JamesIves/github-pages-deploy-action@v4 19 | with: 20 | folder: storybook-static 21 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push] 3 | jobs: 4 | build: 5 | name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }} 6 | 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | matrix: 10 | node: ["10.x", "12.x", "14.x"] 11 | os: [ubuntu-latest, macOS-latest] 12 | 13 | steps: 14 | - name: Checkout repo 15 | uses: actions/checkout@v2 16 | 17 | - name: Use Node ${{ matrix.node }} 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: ${{ matrix.node }} 21 | 22 | - name: Install deps and build (with cache) 23 | uses: bahmutov/npm-install@v1 24 | 25 | - name: Lint 26 | run: yarn lint 27 | 28 | - name: Test 29 | run: yarn test --ci --coverage --maxWorkers=2 30 | 31 | - name: Build 32 | run: yarn build 33 | -------------------------------------------------------------------------------- /.github/workflows/size.yml: -------------------------------------------------------------------------------- 1 | name: size 2 | on: [pull_request] 3 | jobs: 4 | size: 5 | runs-on: ubuntu-latest 6 | env: 7 | CI_JOB_NUMBER: 1 8 | steps: 9 | - uses: actions/checkout@v1 10 | - uses: andresz1/size-limit-action@v1 11 | with: 12 | github_token: ${{ secrets.GITHUB_TOKEN }} 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .DS_Store 3 | .cache 4 | dist 5 | node_modules 6 | storybook-static 7 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npm test 5 | npm run lint 6 | npm run build 7 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | build/* 2 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: ["../stories/**/*.stories.@(ts|tsx|js|jsx)"], 3 | addons: [ 4 | // '@storybook/addon-links', '@storybook/addon-essentials' 5 | ], 6 | // https://storybook.js.org/docs/react/configure/typescript#mainjs-configuration 7 | typescript: { 8 | check: true, // type-check stories during Storybook build 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | // https://storybook.js.org/docs/react/writing-stories/parameters#global-parameters 2 | export const parameters = { 3 | // https://storybook.js.org/docs/react/essentials/actions#automatically-matching-args 4 | actions: { argTypesRegex: '^on.*' }, 5 | }; 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "sonarlint.connectedMode.project": { 3 | "connectionId": "public-sonarcloud", 4 | "projectKey": "Mastermindzh_react-cookie-consent" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [[9.0.0]((https://github.com/Mastermindzh/react-cookie-consent/releases/tag/9.0.0)] 9 | 10 | Made all props optional and fixed documentation. 11 | Fixes [#191](https://github.com/Mastermindzh/react-cookie-consent/issues/191) and [#193](https://github.com/Mastermindzh/react-cookie-consent/issues/193) 12 | 13 | ## [[8.0.1]((https://github.com/Mastermindzh/react-cookie-consent/releases/tag/8.0.1)] 14 | 15 | ~~Second try of [np](https://github.com/sindresorhus/np)...~~ 16 | Removed postinstall 17 | np is not my thing.. reverted to old release strategy 18 | 19 | ## [[8.0.0]((https://github.com/Mastermindzh/react-cookie-consent/releases/tag/8.0.0)] 20 | 21 | - Switched to tsdx and Typescript 22 | - Added storybook with examples from readme 23 | 24 | ## [[7.6.0]](] 25 | 26 | - Added `customButtonWrapperAttributes` prop which allows to add custom attributes to the button wrapper div 27 | 28 | ## [[7.5.0]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.5.0) 29 | 30 | - Added `customDeclineButtonProps` to add custom properties to the decline button 31 | 32 | ## [[7.4.1]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.4.1) 33 | 34 | - Small version error in package.json that actually didn't make it work with React 18 35 | 36 | ## [[7.4.0]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.4.0) 37 | 38 | - Added support for React 18 39 | - Updated example and codebase to use React 18 40 | 41 | ## [[7.3.1]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.3.1) 42 | 43 | - Added type annotations on public functions 44 | 45 | ## [[7.3.0]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.3.0) 46 | 47 | - added `customButtonProps` that allows to use custom props with the button component. Specifically useful for library buttons components, for e.g. MUI Button. 48 | 49 | ## [[7.2.1]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.2.1) 50 | 51 | - hideOnDecline added to typescript files 52 | - Added .prettieringore 53 | 54 | ## [[7.2.0]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.2.0) 55 | 56 | - Added `onOverlayClick` which allows you to react to a click on the overlay 57 | - Added `acceptOnOverlayClick` which accepts the cookies when the overlay is clicked and runs `onOverlayClick` 58 | 59 | ## [[7.1.1]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.1.1) 60 | 61 | - `customContentAttributes` and `customContainerAttributes` are now optional in the typing file as they should be 62 | 63 | ## [[7.1.0](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.1.0)] 64 | 65 | - Added custom attribute props for content and container 66 | 67 | ## [[7.0.1](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.0.1)] 68 | 69 | - Configured webpack to remove self from build artefact. Should now work in Nextjs and Gatsby (only tested those..) 70 | 71 | ## [[7.0.0](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.0.0)] 72 | 73 | - Switched from CommonJS to UMD module 74 | 75 | ## [[6.4.1](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/6.4.1))] 76 | 77 | - Added missing typing 78 | 79 | ## [[6.4.0](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/6.4.0))] 80 | 81 | - Added visible prop 82 | 83 | ## [[6.3.0](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/6.2.3))] 84 | 85 | - Added the (optional) scrolling effect back in as it is declared legal in some countries now. 86 | 87 | ## [6.2.4] 88 | 89 | - version bumps :) 90 | 91 | ## [[6.2.3](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/6.2.3)] 92 | 93 | - Added support for IE11, the webpack generated runtime-code should not use arrow functions 94 | 95 | ## [[6.2.2](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/6.2.2)] 96 | 97 | - Fixed the return type of getCookieConsentValue in the dts file. 98 | 99 | ## [[6.2.1](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/6.2.1)] 100 | 101 | Added the `getCookieConsentValue` to the dts file. 102 | 103 | ## [[6.2.0](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/6.2.0)] 104 | 105 | Added the exported function `getCookieConsentValue` to get the cookie value from custom code 106 | 107 | ## [[6.1.0](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/6.1.0)] 108 | 109 | Added support for React 17 110 | 111 | ## [[6.0.0](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/6.0.0)] 112 | 113 | ### removed 114 | 115 | Accepting by scrolling is no longer allowed and has thus been removed from the package. 116 | For details see [issue 88](https://github.com/Mastermindzh/react-cookie-consent/issues/88) 117 | 118 | ## [[5.2.0](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/5.2.0)] 119 | 120 | ### added 121 | 122 | Added aria labels for both the decline and accept button 123 | 124 | ## [[5.1.4](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/5.1.4)] 125 | 126 | ### changed 127 | 128 | - set default SameSite attribute to "lax" because browsers are already implementing the cookie policy changes. 129 | 130 | ## [[5.1.3](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/5.1.3)] 131 | 132 | ### changed 133 | 134 | - Fix missing buttonWrapperClasses prop in type definition 135 | 136 | ## [5.1.2] 137 | 138 | ### changed 139 | 140 | - Set cookie value before handling side-effects. 141 | - The overlay is now conditional. Meaning that the component behaves exactly as it did prior to 5.1.0 when you do not use the overlay 142 | 143 | ## [5.1.0] 144 | 145 | A new feature! This time it's an "overlay" on the entire website to block access whilst the cookiebar is displayed. 146 | This is all opt-in of course and the README covers it nicely (just add overlay to the props and see what happens). 147 | 148 | We got an update picture, with a cute cat... unfortunately the cat won't be included by default: 149 | 150 | ![overlay example image](https://github.com/Mastermindzh/react-cookie-consent/blob/master/images/overlay.png?raw=true) 151 | 152 | ## [5.0.1] 153 | 154 | - Fixed [Issue 155 | 69](https://github.com/Mastermindzh/react-cookie-consent/issues/69) by 156 | removing location from the proptypes to avoid build-time issues 157 | 158 | ## [5.0.0] 159 | 160 | ### added 161 | 162 | - CookieSecurity prop - allows securing the cookie 163 | - sameSite prop - allows you to set sameSite properties so browser won't warn 164 | about non-secure cookies :) 165 | 166 | ## [4.1.0] 167 | 168 | ### changed 169 | 170 | - Added CookieConsent back in as the default for the containerClasses property. 171 | 172 | ## [4.0.0] 173 | 174 | I decided to update react-cookie-consent to version 4 because this version has a 175 | buttonWrapper which will break appearance. I consider appearance a major feature. 176 | 177 | ### Added 178 | 179 | - Changelog :D 180 | - A wrapper around the buttons so they always stay together. (still possible to 181 | change with css using buttonWrapperClasses) 182 | 183 | ### Changed 184 | 185 | - Default ids for the buttons (rcc stands for react-cookie-consent, 186 | cookie-consent is blocked by some adblockers nowadays so I abbreviated it) 187 | 188 | ### Updated 189 | 190 | #### dependencies 191 | 192 | - js-cookie updated from `2.2.0` to `2.2.1` 193 | 194 | #### peer dependencies 195 | 196 | - react updated from `16.4.0` to `16.13.1` 197 | 198 | #### development dependencies 199 | 200 | - @types/js-cookie updated from `2.2.2` to `2.2.6` 201 | - babel-cli updated from `6.24.1` to `6.26.0` 202 | - babel-preset-env updated from `1.5.1` to `1.7.0` 203 | - react updated from `16.8.6` to `16.13.1` 204 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, 4 | email, or any other method with the owners of this repository before making a changes in order to avoid wasting your time. 5 | 6 | ## scope 7 | 8 | Please keep the scope of a PR down to a single change. 9 | You can make multiple prs to change multiple things though. 10 | 11 | ## builds 12 | 13 | Don't modify anything in the build/ directory please. 14 | This will be done on release. 15 | 16 | ## Pull Request Process 17 | 18 | 1. Code away :D 19 | 2. Update the README.md with details of changes to the interface, this includes new environment 20 | variables, exposed ports, useful file locations and container parameters. 21 | _Please don't change the format of the variable table in the README_ 22 | 3. Add the section "[next]" to the CHANGELOG.md and describe what you changed and why. 23 | 4. Create the PR. yay. 24 | 25 | ## Contributor Covenant Code of Conduct 26 | 27 | ### Our Pledge 28 | 29 | We as members, contributors, and leaders pledge to make participation in our 30 | community a harassment-free experience for everyone, regardless of age, body 31 | size, visible or invisible disability, ethnicity, sex characteristics, gender 32 | identity and expression, level of experience, education, socio-economic status, 33 | nationality, personal appearance, race, religion, or sexual identity 34 | and orientation. 35 | 36 | We pledge to act and interact in ways that contribute to an open, welcoming, 37 | diverse, inclusive, and healthy community. 38 | 39 | ### Our Standards 40 | 41 | Examples of behavior that contributes to a positive environment for our 42 | community include: 43 | 44 | - Demonstrating empathy and kindness toward other people 45 | - Being respectful of differing opinions, viewpoints, and experiences 46 | - Giving and gracefully accepting constructive feedback 47 | - Accepting responsibility and apologizing to those affected by our mistakes, 48 | and learning from the experience 49 | - Focusing on what is best not just for us as individuals, but for the 50 | overall community 51 | 52 | Examples of unacceptable behavior include: 53 | 54 | - The use of sexualized language or imagery, and sexual attention or 55 | advances of any kind 56 | - Trolling, insulting or derogatory comments, and personal or political attacks 57 | - Public or private harassment 58 | - Publishing others' private information, such as a physical or email 59 | address, without their explicit permission 60 | - Other conduct which could reasonably be considered inappropriate in a 61 | professional setting 62 | 63 | ### Enforcement Responsibilities 64 | 65 | Community leaders are responsible for clarifying and enforcing our standards of 66 | acceptable behavior and will take appropriate and fair corrective action in 67 | response to any behavior that they deem inappropriate, threatening, offensive, 68 | or harmful. 69 | 70 | Community leaders have the right and responsibility to remove, edit, or reject 71 | comments, commits, code, wiki edits, issues, and other contributions that are 72 | not aligned to this Code of Conduct, and will communicate reasons for moderation 73 | decisions when appropriate. 74 | 75 | ### Scope 76 | 77 | This Code of Conduct applies within all community spaces, and also applies when 78 | an individual is officially representing the community in public spaces. 79 | Examples of representing our community include using an official e-mail address, 80 | posting via an official social media account, or acting as an appointed 81 | representative at an online or offline event. 82 | 83 | ### Enforcement 84 | 85 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 86 | reported to the community leaders responsible for enforcement at 87 | [info@rickvanlieshout.com](mailto:info@rickvanlieshout.com). 88 | All complaints will be reviewed and investigated fairly. 89 | 90 | All community leaders are obligated to respect the privacy and security of the 91 | reporter of any incident. 92 | 93 | ### Enforcement Guidelines 94 | 95 | Community leaders will follow these Community Impact Guidelines in determining 96 | the consequences for any action they deem in violation of this Code of Conduct: 97 | 98 | #### 1. Correction 99 | 100 | **Community Impact**: Use of inappropriate language or other behavior deemed 101 | unprofessional or unwelcome in the community. 102 | 103 | **Consequence**: A private, written warning from community leaders, providing 104 | clarity around the nature of the violation and an explanation of why the 105 | behavior was inappropriate. A public apology may be requested. 106 | 107 | #### 2. Warning 108 | 109 | **Community Impact**: A violation through a single incident or series 110 | of actions. 111 | 112 | **Consequence**: A warning with consequences for continued behavior. No 113 | interaction with the people involved, including unsolicited interaction with 114 | those enforcing the Code of Conduct, for a specified period of time. This 115 | includes avoiding interactions in community spaces as well as external channels 116 | like social media. Violating these terms may lead to a temporary or 117 | permanent ban. 118 | 119 | #### 3. Temporary Ban 120 | 121 | **Community Impact**: A serious violation of community standards, including 122 | sustained inappropriate behavior. 123 | 124 | **Consequence**: A temporary ban from any sort of interaction or public 125 | communication with the community for a specified period of time. No public or 126 | private interaction with the people involved, including unsolicited interaction 127 | with those enforcing the Code of Conduct, is allowed during this period. 128 | Violating these terms may lead to a permanent ban. 129 | 130 | #### 4. Permanent Ban 131 | 132 | **Community Impact**: Demonstrating a pattern of violation of community 133 | standards, including sustained inappropriate behavior, harassment of an 134 | individual, or aggression toward or disparagement of classes of individuals. 135 | 136 | **Consequence**: A permanent ban from any sort of public interaction within 137 | the community. 138 | 139 | ### Attribution 140 | 141 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 142 | version 2.0, available at 143 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 144 | 145 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 146 | enforcement ladder](https://github.com/mozilla/diversity). 147 | 148 | [homepage]: https://www.contributor-covenant.org 149 | 150 | For answers to common questions about this code of conduct, see the FAQ at 151 | https://www.contributor-covenant.org/faq. Translations are available at 152 | https://www.contributor-covenant.org/translations. 153 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Rick van Lieshout 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :cookie: react-cookie-consent :cookie: 2 | 3 | A small, simple and customizable cookie consent bar for use in React applications. 4 | 5 | [![NPM](https://nodei.co/npm/react-cookie-consent.png)](https://npmjs.org/package/react-cookie-consent) 6 | 7 | Demo (storybook): 8 | 9 | ![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) 10 | 11 | ## Default look 12 | 13 | ![default look](https://raw.githubusercontent.com/Mastermindzh/react-cookie-consent/master/images/default.png) 14 | 15 | ## Table of contents 16 | 17 | 18 | 19 | - [:cookie: react-cookie-consent :cookie:](#cookie-react-cookie-consent-cookie) 20 | - [Default look](#default-look) 21 | - [Table of contents](#table-of-contents) 22 | - [Installation](#installation) 23 | - [Using it](#using-it) 24 | - [getting the cookies value in your own code](#getting-the-cookies-value-in-your-own-code) 25 | - [reset the cookies value in your own code](#reset-the-cookies-value-in-your-own-code) 26 | - [Props](#props) 27 | - [Debugging it](#debugging-it) 28 | - [Why are there two cookies? One of which named "Legacy"](#why-are-there-two-cookies-one-of-which-named-legacy) 29 | - [Styling it](#styling-it) 30 | - [Examples](#examples) 31 | - [Changing the bar background to red](#changing-the-bar-background-to-red) 32 | - [Changing the button font-weight to bold](#changing-the-button-font-weight-to-bold) 33 | - [Using predefined CSS classes](#using-predefined-css-classes) 34 | - [Accept on scroll](#accept-on-scroll) 35 | - [Flipping the buttons](#flipping-the-buttons) 36 | - [Extra cookie options](#extra-cookie-options) 37 | - [Rainbows](#rainbows) 38 | - [Overlay](#overlay) 39 | - [Contributor information](#contributor-information) 40 | - [Projects using react-cookie-consent](#projects-using-react-cookie-consent) 41 | 42 | 43 | 44 | ## Installation 45 | 46 | ```shell 47 | npm install react-cookie-consent 48 | ``` 49 | 50 | or use yarn: 51 | 52 | ```shell 53 | yarn add react-cookie-consent 54 | ``` 55 | 56 | ## Using it 57 | 58 | You can import the cookie bar like this: 59 | 60 | ```js 61 | import CookieConsent from "react-cookie-consent"; 62 | ``` 63 | 64 | If you want to set/remove cookies yourself you can optionally import `Cookies` (straight from js-cookie) like this: 65 | 66 | ```js 67 | import CookieConsent, { Cookies } from "react-cookie-consent"; 68 | ``` 69 | 70 | Then you can use the component anywhere in your React app like so: 71 | 72 | ```jsx 73 | This website uses cookies to enhance the user experience. 74 | ``` 75 | 76 | You can optionally set some props like this (next chapter will show all props): 77 | 78 | ```js 79 | 87 | This website uses cookies to enhance the user experience.{" "} 88 | This bit of text is smaller :O 89 | 90 | ``` 91 | 92 | One of the props (onAccept) is a function, this function will be called after the user has clicked the accept button. It is called with an object containing a boolean property `acceptedByScrolling` to indicate if the acceptance was triggered by the user scrolling You can provide a function like so: 93 | 94 | ```js 95 | { 97 | if (acceptedByScrolling) { 98 | // triggered if user scrolls past threshold 99 | alert("Accept was triggered by user scrolling"); 100 | } else { 101 | alert("Accept was triggered by clicking the Accept button"); 102 | } 103 | }} 104 | > 105 | ``` 106 | 107 | If the decline button is enabled then the (onDecline) prop function can be used, this function will be called after the user has clicked the decline button. You can enable the button and provide a function like so: 108 | 109 | ```js 110 | { 113 | alert("nay!"); 114 | }} 115 | > 116 | ``` 117 | 118 | ### getting the cookies value in your own code 119 | 120 | react-cookie-consent exports a function called `getCookieConsentValue(cookieName: string)`. You can use it in your own code like so: 121 | 122 | ```js 123 | import CookieConsent, { Cookies, getCookieConsentValue } from "react-cookie-consent"; 124 | 125 | console.log(getCookieConsentValue("your_custom_cookie_name")); 126 | ``` 127 | 128 | ### reset the cookies value in your own code 129 | 130 | react-cookie-consent exports a function called `resetCookieConsentValue`. You can use it in order to remove cookie in client-site: 131 | 132 | ```js 133 | import CookieConsent, { Cookies, resetCookieConsentValue } from "react-cookie-consent"; 134 | 135 | console.log(resetCookieConsentValue()); 136 | ``` 137 | 138 | That option would be interesting if you want to allow user to change their consent. If you want to show again the consent bar, you must force "visible" prop to show again the bar. 139 | 140 | ## Props 141 | 142 | | Prop | Type | Default value | Description | 143 | | ----------------------------- | :-----------------------------------------: | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | 144 | | 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. | 145 | | visible | string, "show", "hidden" or "byCookieValue" | "byCookieValue" | Force the consent bar visibility. If "byCookieValue", visibility are defined by cookie consent existence. | 146 | | children | string or React component | | Content to appear inside the bar | 147 | | disableStyles | boolean | false | If enabled the component will have no default style. (you can still supply style through props) | 148 | | 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) | 149 | | buttonText | string or React component | "I understand" | Text to appear on the button | 150 | | declineButtonText | string or React component | "I decline" | Text to appear on the decline button | 151 | | 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. | 152 | | cookieValue | string or boolean or number | true | Value to be saved under the cookieName. | 153 | | declineCookieValue | string or boolean or number | false | Value to be saved under the cookieName when declined. | 154 | | setDeclineCookie | boolean | true | Whether to set a cookie when the user clicks "decline" | 155 | | onAccept | function | `() => {}` | Function to be called after the accept button has been clicked. | 156 | | onDecline | function | `() => {}` | Function to be called after the decline button has been clicked. | 157 | | debug | boolean | undefined | Bar will be drawn regardless of cookie for debugging purposes. | 158 | | expires | number | 365 | Number of days before the cookie expires. | 159 | | extraCookieOptions | object | `{}` | Extra info (apart from expiry date) to add to the cookie | 160 | | overlay | boolean | false | Whether to show a page obscuring overlay or not. | 161 | | containerClasses | string | "" | CSS classes to apply to the surrounding container | 162 | | buttonClasses | string | "" | CSS classes to apply to the button | 163 | | buttonWrapperClasses | string | "" | CSS classes to apply to the div wrapping the buttons | 164 | | customButtonWrapperAttributes | `React.HTMLAttributes` | `{}` | Allows you to set custom (data) attributes on the button wrapper div | 165 | | declineButtonClasses | string | "" | CSS classes to apply to the decline button | 166 | | buttonId | string | "" | Id to apply to the button | 167 | | declineButtonId | string | "" | Id to apply to the decline button | 168 | | contentClasses | string | "" | CSS classes to apply to the content | 169 | | overlayClasses | string | "" | CSS classes to apply to the surrounding overlay | 170 | | style | object | [look at source][style] | React styling object for the bar. | 171 | | buttonStyle | object | [look at source][buttonstyle] | React styling object for the button. | 172 | | declineButtonStyle | object | [look at source][declinebuttonstyle] | React styling object for the decline button. | 173 | | contentStyle | object | [look at source][contentstyle] | React styling object for the content. | 174 | | overlayStyle | object | [look at source][overlaystyle] | React styling object for the overlay. | 175 | | disableButtonStyles | boolean | false | If enabled the button will have no default style. (you can still supply style through props) | 176 | | enableDeclineButton | boolean | false | If enabled the decline button will be rendered | 177 | | flipButtons | boolean | false | If enabled the accept and decline buttons will be flipped | 178 | | ButtonComponent | React component | button | React Component to render as a button. | 179 | | sameSite | string, "strict", "lax" or "none" | none | Cookies sameSite attribute value | 180 | | cookieSecurity | boolean | undefined | Cookie security level. Defaults to true unless running on http. | 181 | | ariaAcceptLabel | string | Accept cookies | Aria label to set on the accept button | 182 | | ariaDeclineLabel | string | Decline cookies | Aria label to set on the decline button | 183 | | acceptOnScroll | boolean | false | Defines whether "accept" should be fired after the user scrolls a certain distance (see acceptOnScrollPercentage) | 184 | | acceptOnScrollPercentage | number | 25 | Percentage of the page height the user has to scroll to trigger the accept function if acceptOnScroll is enabled | 185 | | customContentAttributes | object | `{}` | Allows you to set custom (data) attributes on the content div | 186 | | customContainerAttributes | object | `{}` | Allows you to set custom (data) attributes on the container div | 187 | | onOverlayClick | function | `() => {}` | allows you to react to a click on the overlay | 188 | | acceptOnOverlayClick | boolean | false | Determines whether the cookies should be accepted after clicking on the overlay | 189 | | customButtonProps | object | `{}` | Allows you to set custom props on the button component | 190 | | customDeclineButtonProps | object | `{}` | Allows you to set custom props on the decline button component | 191 | 192 | ## Debugging it 193 | 194 | Because the cookie consent bar will be hidden once accepted, you will have to set the prop `debug={true}` to evaluate styling changes: 195 | 196 | ```js 197 | 198 | ``` 199 | 200 | **Note:** Don't forget to remove the `debug`-property for production. 201 | 202 | ## Why are there two cookies? One of which named "Legacy" 203 | 204 | The short story is that some browsers don't support the SameSite=None attribute. 205 | The modern browsers force you to have SameSite set to something other than none. 206 | 207 | So react-cookie-consent fixes this like so: 208 | 209 | - set the fallback cookie (e.g -legacy) first, this will always succeed (on all browsers) 210 | - set the correct cookie second (this will work on modern browsers, fail on older ones) 211 | 212 | This happens on lines [29-37](https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L29-L37) 213 | 214 | When checking the cookie it'll do it in reverse. If the regular cookie exists, it'll use that. If no regular cookie exists it'll check whether the legacy cookie exists. If both are non-existent no consent was given. 215 | 216 | The long story can be found here: [pull-request#68](https://github.com/Mastermindzh/react-cookie-consent/pull/68) 217 | 218 | ## Styling it 219 | 220 | You can provide styling for the bar, the button and the content. Note that the bar has a `display: flex` property as default and is parent to its children "content" and "button". 221 | 222 | The styling behaves kind of responsive. The minimum content width has been chosen to be "300px" as a default value. If the button does not fit into the same line it is wrapped around into the next line. 223 | 224 | You can style each component by using the `style`, `buttonStyle` and `contentStyle` prop. These will append / replace the default styles of the components. 225 | Alternatively you can provide CSS classnames as `containerClasses`, `buttonClasses` and `contentClasses` to apply predefined CSS classes. 226 | 227 | You can use `disableStyles={true}` to disable any built-in styling. 228 | 229 | ### Examples 230 | 231 | #### Changing the bar background to red 232 | 233 | ```js 234 | 235 | ``` 236 | 237 | #### Changing the button font-weight to bold 238 | 239 | ```js 240 | 241 | ``` 242 | 243 | #### Using predefined CSS classes 244 | 245 | You can pass predefined CSS classes to the components using the `containerClasses`, `buttonClasses` and `contentClasses` props. The example below uses bootstrap classes: 246 | 247 | ```js 248 | 255 | This website uses cookies to enhance the user experience.{" "} 256 | This bit of text is smaller :O 257 | 258 | ``` 259 | 260 | Which results in: 261 | 262 | ![bootstrap styling](https://github.com/Mastermindzh/react-cookie-consent/blob/master/images/css_classes.png?raw=true) 263 | 264 | #### Accept on scroll 265 | 266 | You can make the cookiebar disappear after scrolling a certain percentage using acceptOnScroll and acceptOnScrollPercentage. 267 | It is legal in some use-cases, [Italy](https://www.garanteprivacy.it/web/guest/home/docweb/-/docweb-display/docweb/9679893) being one of them. Consult your legislation on whether this is allowed. 268 | 269 | ```js 270 | { 274 | alert(`consent given. \n\n By scrolling? ${byScroll}`); 275 | }} 276 | > 277 | Hello scroller :) 278 | 279 | ``` 280 | 281 | #### Flipping the buttons 282 | 283 | If you enable the decline button you can pass along the "flipButtons" property to turn the buttons around: 284 | 285 | ```js 286 | 287 | Flipped buttons 288 | 289 | ``` 290 | 291 | Which results in: 292 | 293 | ![flipped buttons](./images/flipped.png) 294 | 295 | #### Extra cookie options 296 | 297 | You can add more cookie options using the extraCookieOptions parameter like so: 298 | 299 | ```js 300 | cookie bar 301 | ``` 302 | 303 | #### Rainbows 304 | 305 | ![rainbows!](https://github.com/Mastermindzh/react-cookie-consent/blob/master/images/rainbow.png?raw=true) 306 | 307 | If you're crazy enough you can even make a rainbow colored bar: 308 | 309 | ```js 310 | 324 | This website uses cookies to enhance the user experience.{" "} 325 | This bit of text is smaller :O 326 | 327 | ``` 328 | 329 | #### Overlay 330 | 331 | ![overlay](https://github.com/Mastermindzh/react-cookie-consent/blob/master/images/overlay.png?raw=true) 332 | 333 | You can also generate a page-obfuscating overlay that will prevent actions other than interacting with the cookie consent button(s). 334 | 335 | ```js 336 | 337 | This website uses cookies to enhance the user experience. 338 | 339 | ``` 340 | 341 | 342 | 343 | [style]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L78-L89 344 | [buttonstyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L90-L100 345 | [declinebuttonstyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L101-L111 346 | [contentstyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L112-L115 347 | [overlaystyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L116-L124 348 | 349 | ## Contributor information 350 | 351 | When making a PR please think about the following things: 352 | 353 | - Update the ChangeLog (or include what you did in the PR and I'll add it, up to you) 354 | - No need to build or update the package.json. I will do both on release. 355 | - Please don't change code convention / style 356 | 357 | ## Projects using react-cookie-consent 358 | 359 | The list below features the projects which use react-cookie-consent (that I know off): 360 | 361 | - [bs-react-cookie-consent](https://github.com/ctbucha/bs-react-cookie-consent) 362 | - [comicrelief's storybook](https://github.com/comicrelief/storybook) 363 | - [inici Gatsby theme](https://github.com/kuworking/gatsby-theme-kuworking-core) 364 | - [Scrivito Example App](https://github.com/Scrivito/scrivito_example_app_js) 365 | -------------------------------------------------------------------------------- /images/css_classes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mastermindzh/react-cookie-consent/a5f421b8bc4373ab59bbae76e76ab8e84a22b8c8/images/css_classes.png -------------------------------------------------------------------------------- /images/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mastermindzh/react-cookie-consent/a5f421b8bc4373ab59bbae76e76ab8e84a22b8c8/images/default.png -------------------------------------------------------------------------------- /images/flipped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mastermindzh/react-cookie-consent/a5f421b8bc4373ab59bbae76e76ab8e84a22b8c8/images/flipped.png -------------------------------------------------------------------------------- /images/overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mastermindzh/react-cookie-consent/a5f421b8bc4373ab59bbae76e76ab8e84a22b8c8/images/overlay.png -------------------------------------------------------------------------------- /images/rainbow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mastermindzh/react-cookie-consent/a5f421b8bc4373ab59bbae76e76ab8e84a22b8c8/images/rainbow.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-cookie-consent", 3 | "version": "9.0.0", 4 | "description": "A small, simple and customizable cookie consent bar for use in React applications.", 5 | "keywords": [ 6 | "react", 7 | "cookie", 8 | "consent", 9 | "cookiebar" 10 | ], 11 | "homepage": "https://github.com/Mastermindzh/react-cookie-consent#readme", 12 | "bugs": { 13 | "url": "https://github.com/Mastermindzh/react-cookie-consent/issues" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/Mastermindzh/react-cookie-consent.git" 18 | }, 19 | "license": "MIT", 20 | "author": { 21 | "name": "Rick van Lieshout", 22 | "email": "info@rickvanlieshout.com" 23 | }, 24 | "main": "dist/index.js", 25 | "module": "dist/react-cookie-consent.esm.js", 26 | "typings": "dist/index.d.ts", 27 | "files": [ 28 | "dist", 29 | "src" 30 | ], 31 | "scripts": { 32 | "analyze": "size-limit --why", 33 | "build": "tsdx build", 34 | "build-storybook": "build-storybook", 35 | "install-husky": "npx husky install", 36 | "lint": "tsdx lint", 37 | "major": "npm --no-git-tag-version version major", 38 | "minor": "npm --no-git-tag-version version minor", 39 | "organize": "npx format-package -w && npx sort-package-json", 40 | "patch": "npm --no-git-tag-version version patch", 41 | "prepare": "tsdx build", 42 | "prettier": "prettier 'src/**/*.{js*,ts*,htm*,md,scss}' --write", 43 | "publish": "npx np", 44 | "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", 45 | "release-major": "npm run major && npm run release", 46 | "release-minor": "npm run minor && npm run release", 47 | "release-patch": "npm run patch && npm run release", 48 | "size": "size-limit", 49 | "start": "tsdx watch", 50 | "storybook": "start-storybook -p 6006", 51 | "test": "tsdx test --passWithNoTests", 52 | "preversion": "grep \"\\[$npm_package_version\\]\" CHANGELOG.md > /dev/null || ( echo 'You need to add an entry in CHANGELOG.md for this version.' && false )" 53 | }, 54 | "lint-staged": { 55 | "*.{js*,ts*,htm*,md,scss}": [ 56 | "prettier --write" 57 | ] 58 | }, 59 | "prettier": "@mastermindzh/prettier-config", 60 | "dependencies": { 61 | "js-cookie": "^2.2.1" 62 | }, 63 | "devDependencies": { 64 | "@emotion/react": "^11.9.3", 65 | "@emotion/styled": "^11.9.3", 66 | "@mastermindzh/prettier-config": "^1.0.0", 67 | "@mui/material": "^5.9.2", 68 | "@size-limit/preset-small-lib": "^7.0.8", 69 | "@storybook/addon-essentials": "^6.5.9", 70 | "@storybook/addons": "^6.5.9", 71 | "@storybook/react": "^6.5.9", 72 | "@types/js-cookie": "^2.2.6", 73 | "@types/react": "^18.0.15", 74 | "@types/react-dom": "^18.0.6", 75 | "babel-loader": "^8.2.5", 76 | "gh-pages": "^4.0.0", 77 | "husky": "^8.0.1", 78 | "prettier": "^2.6.2", 79 | "react": "^18.2.0", 80 | "react-dom": "^18.2.0", 81 | "react-is": "^18.2.0", 82 | "size-limit": "^7.0.8", 83 | "tsdx": "^0.14.1", 84 | "tslib": "^2.4.0", 85 | "typescript": "^3.9.10" 86 | }, 87 | "peerDependencies": { 88 | "react": ">=16" 89 | }, 90 | "engines": { 91 | "node": ">=10" 92 | }, 93 | "size-limit": [ 94 | { 95 | "path": "dist/react-cookie-consent.cjs.production.min.js", 96 | "limit": "10 KB" 97 | }, 98 | { 99 | "path": "dist/react-cookie-consent.esm.js", 100 | "limit": "10 KB" 101 | } 102 | ] 103 | } 104 | -------------------------------------------------------------------------------- /src/CookieConsent.props.tsx: -------------------------------------------------------------------------------- 1 | import React, { FunctionComponent, ReactNode } from "react"; 2 | import { 3 | defaultCookieConsentName, 4 | POSITION_OPTIONS, 5 | SAME_SITE_OPTIONS, 6 | VISIBILITY_OPTIONS, 7 | } from "./models/constants"; 8 | 9 | export interface CookieConsentProps { 10 | children?: ReactNode; 11 | style?: React.CSSProperties; 12 | buttonStyle?: React.CSSProperties; 13 | declineButtonStyle?: React.CSSProperties; 14 | contentStyle?: React.CSSProperties; 15 | disableStyles?: boolean; 16 | hideOnAccept?: boolean; 17 | hideOnDecline?: boolean; 18 | onAccept?: (acceptedByScrolling: boolean) => void; 19 | onDecline?: () => void; 20 | buttonText?: string | ReactNode | Function; 21 | declineButtonText?: string | ReactNode | Function; 22 | cookieName?: string; 23 | cookieValue?: string | object; 24 | declineCookieValue?: string | object; 25 | setDeclineCookie?: boolean; 26 | debug?: boolean; 27 | expires?: number; 28 | containerClasses?: string; 29 | contentClasses?: string; 30 | buttonClasses?: string; 31 | buttonWrapperClasses?: string; 32 | declineButtonClasses?: string; 33 | buttonId?: string; 34 | declineButtonId?: string; 35 | overlayClasses?: string; 36 | ariaAcceptLabel?: string; 37 | ariaDeclineLabel?: string; 38 | disableButtonStyles?: boolean; 39 | enableDeclineButton?: boolean; 40 | flipButtons?: boolean; 41 | cookieSecurity?: boolean; 42 | overlay?: boolean; 43 | acceptOnOverlayClick?: boolean; 44 | acceptOnScroll?: boolean; 45 | acceptOnScrollPercentage?: number; 46 | ButtonComponent?: any; 47 | extraCookieOptions?: Object; 48 | overlayStyle?: Object; 49 | customContentAttributes?: Object; 50 | customContainerAttributes?: Object; 51 | customButtonProps?: Object; 52 | customDeclineButtonProps?: Object; 53 | customButtonWrapperAttributes?: Object; 54 | onOverlayClick?: () => void; 55 | // these should be enums 56 | location?: string; 57 | visible?: string; 58 | sameSite?: "strict" | "Strict" | "lax" | "Lax" | "none" | "None"; 59 | } 60 | 61 | const DefaultButtonComponent: FunctionComponent<{ children: ReactNode; [x: string]: any }> = ({ 62 | children, 63 | ...props 64 | }) => { 65 | return ; 66 | }; 67 | 68 | export const defaultCookieConsentProps = { 69 | disableStyles: false, 70 | hideOnAccept: true, 71 | hideOnDecline: true, 72 | location: POSITION_OPTIONS.BOTTOM, 73 | visible: VISIBILITY_OPTIONS.BY_COOKIE_VALUE, 74 | onAccept: (_acceptedByScrolling: boolean) => {}, 75 | onDecline: () => {}, 76 | cookieName: defaultCookieConsentName, 77 | cookieValue: "true", 78 | declineCookieValue: "false", 79 | setDeclineCookie: true, 80 | buttonText: "I understand", 81 | declineButtonText: "I decline", 82 | debug: false, 83 | expires: 365, 84 | containerClasses: "CookieConsent", 85 | contentClasses: "", 86 | buttonClasses: "", 87 | buttonWrapperClasses: "", 88 | declineButtonClasses: "", 89 | buttonId: "rcc-confirm-button", 90 | declineButtonId: "rcc-decline-button", 91 | extraCookieOptions: {}, 92 | disableButtonStyles: false, 93 | enableDeclineButton: false, 94 | flipButtons: false, 95 | sameSite: SAME_SITE_OPTIONS.LAX, 96 | ButtonComponent: DefaultButtonComponent, 97 | overlay: false, 98 | overlayClasses: "", 99 | onOverlayClick: () => {}, 100 | acceptOnOverlayClick: false, 101 | ariaAcceptLabel: "Accept cookies", 102 | ariaDeclineLabel: "Decline cookies", 103 | acceptOnScroll: false, 104 | acceptOnScrollPercentage: 25, 105 | customContentAttributes: {}, 106 | customContainerAttributes: {}, 107 | customButtonProps: {}, 108 | customDeclineButtonProps: {}, 109 | customButtonWrapperAttributes: {}, 110 | style: {}, 111 | buttonStyle: {}, 112 | declineButtonStyle: {}, 113 | contentStyle: {}, 114 | overlayStyle: {}, 115 | }; 116 | -------------------------------------------------------------------------------- /src/CookieConsent.state.ts: -------------------------------------------------------------------------------- 1 | export interface CookieConsentState { 2 | visible: boolean; 3 | style: React.CSSProperties; 4 | buttonStyle: React.CSSProperties; 5 | declineButtonStyle: React.CSSProperties; 6 | contentStyle: React.CSSProperties; 7 | overlayStyle: React.CSSProperties; 8 | } 9 | 10 | export const defaultState: CookieConsentState = { 11 | visible: false, 12 | style: { 13 | alignItems: "baseline", 14 | background: "#353535", 15 | color: "white", 16 | display: "flex", 17 | flexWrap: "wrap", 18 | justifyContent: "space-between", 19 | left: "0", 20 | position: "fixed", 21 | width: "100%", 22 | zIndex: "999", 23 | }, 24 | buttonStyle: { 25 | background: "#ffd42d", 26 | border: "0", 27 | borderRadius: "0px", 28 | boxShadow: "none", 29 | color: "black", 30 | cursor: "pointer", 31 | flex: "0 0 auto", 32 | padding: "5px 10px", 33 | margin: "15px", 34 | }, 35 | declineButtonStyle: { 36 | background: "#c12a2a", 37 | border: "0", 38 | borderRadius: "0px", 39 | boxShadow: "none", 40 | color: "#e5e5e5", 41 | cursor: "pointer", 42 | flex: "0 0 auto", 43 | padding: "5px 10px", 44 | margin: "15px", 45 | }, 46 | contentStyle: { 47 | flex: "1 0 300px", 48 | margin: "15px", 49 | }, 50 | overlayStyle: { 51 | position: "fixed", 52 | left: 0, 53 | top: 0, 54 | width: "100%", 55 | height: "100%", 56 | zIndex: "999", 57 | backgroundColor: "rgba(0,0,0,0.3)", 58 | }, 59 | }; 60 | -------------------------------------------------------------------------------- /src/CookieConsent.tsx: -------------------------------------------------------------------------------- 1 | import Cookies from "js-cookie"; 2 | import React, { Component, CSSProperties } from "react"; 3 | import { ConditionalWrapper } from "./components/ConditionalWrapper"; 4 | import { CookieConsentProps, defaultCookieConsentProps } from "./CookieConsent.props"; 5 | import { CookieConsentState, defaultState } from "./CookieConsent.state"; 6 | import { POSITION_OPTIONS, SAME_SITE_OPTIONS, VISIBILITY_OPTIONS } from "./models/constants"; 7 | import { getCookieConsentValue, getLegacyCookieName } from "./utilities"; 8 | 9 | export class CookieConsent extends Component { 10 | public static defaultProps = defaultCookieConsentProps; 11 | 12 | state: CookieConsentState = defaultState; 13 | 14 | componentDidMount() { 15 | const { debug } = this.props; 16 | 17 | // if cookie undefined or debug 18 | if (this.getCookieValue() === undefined || debug) { 19 | this.setState({ visible: true }); 20 | // if acceptOnScroll is set to true and (cookie is undefined or debug is set to true), add a listener. 21 | if (this.props.acceptOnScroll) { 22 | window.addEventListener("scroll", this.handleScroll, { passive: true }); 23 | } 24 | } 25 | } 26 | 27 | componentWillUnmount() { 28 | // remove listener if still set 29 | this.removeScrollListener(); 30 | } 31 | 32 | /** 33 | * Set a persistent accept cookie 34 | */ 35 | accept(acceptedByScrolling = false) { 36 | const { cookieName, cookieValue, hideOnAccept, onAccept } = { 37 | ...defaultCookieConsentProps, 38 | ...this.props, 39 | }; 40 | 41 | this.setCookie(cookieName, cookieValue); 42 | 43 | onAccept(acceptedByScrolling ?? false); 44 | 45 | if (hideOnAccept) { 46 | this.setState({ visible: false }); 47 | this.removeScrollListener(); 48 | } 49 | } 50 | 51 | /** 52 | * Handle a click on the overlay 53 | */ 54 | overlayClick() { 55 | const { acceptOnOverlayClick, onOverlayClick } = { 56 | ...defaultCookieConsentProps, 57 | ...this.props, 58 | }; 59 | if (acceptOnOverlayClick) { 60 | this.accept(); 61 | } 62 | onOverlayClick(); 63 | } 64 | 65 | /** 66 | * Set a persistent decline cookie 67 | */ 68 | decline() { 69 | const { cookieName, declineCookieValue, hideOnDecline, onDecline, setDeclineCookie } = { 70 | ...defaultCookieConsentProps, 71 | ...this.props, 72 | }; 73 | 74 | if (setDeclineCookie) { 75 | this.setCookie(cookieName, declineCookieValue); 76 | } 77 | 78 | onDecline(); 79 | 80 | if (hideOnDecline) { 81 | this.setState({ visible: false }); 82 | } 83 | } 84 | 85 | /** 86 | * Function to set the consent cookie based on the provided variables 87 | * Sets two cookies to handle incompatible browsers, more details: 88 | * https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients 89 | */ 90 | setCookie(cookieName: string, cookieValue: string | object) { 91 | const { extraCookieOptions, expires, sameSite } = this.props; 92 | let { cookieSecurity } = this.props; 93 | 94 | if (cookieSecurity === undefined) { 95 | cookieSecurity = window.location ? window.location.protocol === "https:" : true; 96 | } 97 | 98 | const cookieOptions = { expires, ...extraCookieOptions, sameSite, secure: cookieSecurity }; 99 | 100 | // Fallback for older browsers where can not set SameSite=None, 101 | // SEE: https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients 102 | if (sameSite === SAME_SITE_OPTIONS.NONE) { 103 | Cookies.set(getLegacyCookieName(cookieName), cookieValue, cookieOptions); 104 | } 105 | 106 | // set the regular cookie 107 | Cookies.set(cookieName, cookieValue, cookieOptions); 108 | } 109 | 110 | /** 111 | * Returns the value of the consent cookie 112 | * Retrieves the regular value first and if not found the legacy one according 113 | * to: https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients 114 | */ 115 | getCookieValue() { 116 | const { cookieName } = this.props; 117 | return getCookieConsentValue(cookieName); 118 | } 119 | 120 | /** 121 | * checks whether scroll has exceeded set amount and fire accept if so. 122 | */ 123 | handleScroll = () => { 124 | const { acceptOnScrollPercentage } = { ...defaultCookieConsentProps, ...this.props }; 125 | 126 | // (top / height) - height * 100 127 | const rootNode = document.documentElement; 128 | const body = document.body; 129 | const top = "scrollTop"; 130 | const height = "scrollHeight"; 131 | 132 | const percentage = 133 | ((rootNode[top] || body[top]) / 134 | ((rootNode[height] || body[height]) - rootNode.clientHeight)) * 135 | 100; 136 | 137 | if (percentage > acceptOnScrollPercentage) { 138 | this.accept(true); 139 | } 140 | }; 141 | 142 | removeScrollListener = () => { 143 | const { acceptOnScroll } = this.props; 144 | if (acceptOnScroll) { 145 | window.removeEventListener("scroll", this.handleScroll); 146 | } 147 | }; 148 | 149 | render() { 150 | // If the bar shouldn't be visible don't render anything. 151 | switch (this.props.visible) { 152 | case VISIBILITY_OPTIONS.HIDDEN: 153 | return null; 154 | case VISIBILITY_OPTIONS.BY_COOKIE_VALUE: 155 | if (!this.state.visible) { 156 | return null; 157 | } 158 | break; 159 | default: 160 | break; 161 | } 162 | 163 | const { 164 | location, 165 | style, 166 | buttonStyle, 167 | declineButtonStyle, 168 | contentStyle, 169 | disableStyles, 170 | buttonText, 171 | declineButtonText, 172 | containerClasses, 173 | contentClasses, 174 | buttonClasses, 175 | buttonWrapperClasses, 176 | declineButtonClasses, 177 | buttonId, 178 | declineButtonId, 179 | disableButtonStyles, 180 | enableDeclineButton, 181 | flipButtons, 182 | ButtonComponent, 183 | overlay, 184 | overlayClasses, 185 | overlayStyle, 186 | ariaAcceptLabel, 187 | ariaDeclineLabel, 188 | customContainerAttributes, 189 | customContentAttributes, 190 | customButtonProps, 191 | customDeclineButtonProps, 192 | customButtonWrapperAttributes, 193 | } = this.props; 194 | 195 | let myStyle: CSSProperties = {}; 196 | let myButtonStyle: CSSProperties = {}; 197 | let myDeclineButtonStyle: CSSProperties = {}; 198 | let myContentStyle: CSSProperties = {}; 199 | let myOverlayStyle: CSSProperties = {}; 200 | 201 | if (disableStyles) { 202 | // if styles are disabled use the provided styles (or none) 203 | myStyle = Object.assign({}, style); 204 | myButtonStyle = Object.assign({}, buttonStyle); 205 | myDeclineButtonStyle = Object.assign({}, declineButtonStyle); 206 | myContentStyle = Object.assign({}, contentStyle); 207 | myOverlayStyle = Object.assign({}, overlayStyle); 208 | } else { 209 | // if styles aren't disabled merge them with the styles that are provided (or use default styles) 210 | myStyle = Object.assign({}, { ...this.state.style, ...style }); 211 | myContentStyle = Object.assign({}, { ...this.state.contentStyle, ...contentStyle }); 212 | myOverlayStyle = Object.assign({}, { ...this.state.overlayStyle, ...overlayStyle }); 213 | 214 | // switch to disable JUST the button styles 215 | if (disableButtonStyles) { 216 | myButtonStyle = Object.assign({}, buttonStyle); 217 | myDeclineButtonStyle = Object.assign({}, declineButtonStyle); 218 | } else { 219 | myButtonStyle = Object.assign({}, { ...this.state.buttonStyle, ...buttonStyle }); 220 | myDeclineButtonStyle = Object.assign( 221 | {}, 222 | { ...this.state.declineButtonStyle, ...declineButtonStyle } 223 | ); 224 | } 225 | } 226 | 227 | // syntactic sugar to enable user to easily select top / bottom 228 | switch (location) { 229 | case POSITION_OPTIONS.TOP: 230 | myStyle.top = "0"; 231 | break; 232 | 233 | case POSITION_OPTIONS.BOTTOM: 234 | myStyle.bottom = "0"; 235 | break; 236 | } 237 | 238 | const buttonsToRender = []; 239 | 240 | // add decline button 241 | enableDeclineButton && 242 | buttonsToRender.push( 243 | { 250 | this.decline(); 251 | }} 252 | {...customDeclineButtonProps} 253 | > 254 | {declineButtonText} 255 | 256 | ); 257 | 258 | // add accept button 259 | buttonsToRender.push( 260 | { 267 | this.accept(); 268 | }} 269 | {...customButtonProps} 270 | > 271 | {buttonText} 272 | 273 | ); 274 | 275 | if (flipButtons) { 276 | buttonsToRender.reverse(); 277 | } 278 | 279 | return ( 280 | ( 283 |
{ 287 | this.overlayClick(); 288 | }} 289 | > 290 | {children} 291 |
292 | )} 293 | > 294 |
295 |
296 | {this.props.children} 297 |
298 |
299 | {buttonsToRender.map((button) => { 300 | return button; 301 | })} 302 |
303 |
304 |
305 | ); 306 | } 307 | } 308 | 309 | export default CookieConsent; 310 | -------------------------------------------------------------------------------- /src/components/ConditionalWrapper.tsx: -------------------------------------------------------------------------------- 1 | import { FunctionComponent, ReactNode } from "react"; 2 | 3 | type Props = { 4 | condition?: boolean; 5 | wrapper: (_: ReactNode) => any; 6 | children: ReactNode; 7 | }; 8 | 9 | /** 10 | * A function to wrap elements with a "wrapper" on a condition 11 | * @param {object} wrappingOptions 12 | * condition == boolean condition, when to wrap 13 | * wrapper == style to wrap. e.g
{children}
14 | * children == react passes whatever is between tags as children. Don't supply this yourself. 15 | */ 16 | export const ConditionalWrapper: FunctionComponent = ({ condition, wrapper, children }) => { 17 | return condition ? wrapper(children) : children; 18 | }; 19 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import Cookies from "js-cookie"; 2 | import { ConditionalWrapper } from "./components/ConditionalWrapper"; 3 | import { CookieConsent } from "./CookieConsent"; 4 | import { POSITION_OPTIONS, VISIBILITY_OPTIONS } from "./models/constants"; 5 | 6 | export * from "./models/constants"; 7 | export * from "./utilities"; 8 | export { Cookies, CookieConsent, ConditionalWrapper }; 9 | // backwards compatibility exports 10 | export { POSITION_OPTIONS as OPTIONS, VISIBILITY_OPTIONS as VISIBLE_OPTIONS }; 11 | export default CookieConsent; 12 | -------------------------------------------------------------------------------- /src/models/constants/defaultCookieName.ts: -------------------------------------------------------------------------------- 1 | export const defaultCookieConsentName = "CookieConsent"; 2 | -------------------------------------------------------------------------------- /src/models/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./positionOptions"; 2 | export * from "./sameSiteOptions"; 3 | export * from "./visibilityOptions"; 4 | export * from "./defaultCookieName"; 5 | -------------------------------------------------------------------------------- /src/models/constants/positionOptions.ts: -------------------------------------------------------------------------------- 1 | export const POSITION_OPTIONS = { 2 | TOP: "top", 3 | BOTTOM: "bottom", 4 | NONE: "none", 5 | }; 6 | -------------------------------------------------------------------------------- /src/models/constants/sameSiteOptions.ts: -------------------------------------------------------------------------------- 1 | export enum SAME_SITE_OPTIONS { 2 | STRICT = "strict", 3 | LAX = "lax", 4 | NONE = "none", 5 | } 6 | -------------------------------------------------------------------------------- /src/models/constants/visibilityOptions.ts: -------------------------------------------------------------------------------- 1 | export const VISIBILITY_OPTIONS = { 2 | HIDDEN: "hidden", 3 | SHOW: "show", 4 | BY_COOKIE_VALUE: "byCookieValue", 5 | }; 6 | -------------------------------------------------------------------------------- /src/utilities.ts: -------------------------------------------------------------------------------- 1 | import Cookies from "js-cookie"; 2 | import { defaultCookieConsentName } from "./models/constants"; 3 | 4 | /** 5 | * Returns the value of the consent cookie 6 | * Retrieves the regular value first and if not found the legacy one according 7 | * to: https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients 8 | * @param {*} name optional name of the cookie 9 | */ 10 | export const getCookieConsentValue = (name = defaultCookieConsentName) => { 11 | const cookieValue = Cookies.get(name); 12 | 13 | // if the cookieValue is undefined check for the legacy cookie 14 | if (cookieValue === undefined) { 15 | return Cookies.get(getLegacyCookieName(name)); 16 | } 17 | return cookieValue; 18 | }; 19 | 20 | /** 21 | * Reset the consent cookie 22 | * Remove the cookie on browser in order to allow user to change their consent 23 | * @param {*} name optional name of the cookie 24 | */ 25 | export const resetCookieConsentValue = (name = defaultCookieConsentName) => { 26 | Cookies.remove(name); 27 | }; 28 | 29 | /** 30 | * Get the legacy cookie name by the regular cookie name 31 | * @param {string} name of cookie to get 32 | */ 33 | export const getLegacyCookieName = (name: string) => { 34 | return `${name}-legacy`; 35 | }; 36 | -------------------------------------------------------------------------------- /stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 30 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 2 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - good first issue 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: stale 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false 18 | -------------------------------------------------------------------------------- /stories/defaults/intro.tsx: -------------------------------------------------------------------------------- 1 | import { FunctionComponent } from "react"; 2 | 3 | type Props = {}; 4 | 5 | export const Intro: FunctionComponent = () => { 6 | return ( 7 |

8 |

Debug is turned on for all stories so that the bar always shows up

9 |

10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /stories/defaults/storyProps.ts: -------------------------------------------------------------------------------- 1 | import { CookieConsentProps, defaultCookieConsentProps } from "../../src/CookieConsent.props"; 2 | 3 | export const defaultStoryProps: CookieConsentProps = { ...defaultCookieConsentProps, debug: true }; 4 | -------------------------------------------------------------------------------- /stories/defaults/template.tsx: -------------------------------------------------------------------------------- 1 | import { Story } from "@storybook/react"; 2 | import CookieConsent from "../../src"; 3 | import { Intro } from "./intro"; 4 | 5 | export const DefaultTemplate: Story = (args) => ( 6 | <> 7 | 8 | 9 | This website uses cookies to enhance the user experience. 10 | This bit of text is smaller :O 11 | 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /stories/index.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta } from "@storybook/react"; 2 | import { CookieConsent } from "../src"; 3 | import { defaultStoryProps } from "./defaults/storyProps"; 4 | import { DefaultTemplate } from "./defaults/template"; 5 | 6 | const meta: Meta = { 7 | title: "CookieConsent", 8 | component: CookieConsent, 9 | argTypes: { 10 | children: { 11 | control: { 12 | type: "text", 13 | }, 14 | }, 15 | }, 16 | parameters: { 17 | controls: { expanded: true }, 18 | }, 19 | }; 20 | 21 | export default meta; 22 | 23 | export const Default = DefaultTemplate.bind({}); 24 | Default.args = defaultStoryProps; 25 | 26 | // stories 27 | export * from "./stories/acceptOnScroll.story"; 28 | export * from "./stories/additionalButtons.story"; 29 | export * from "./stories/customStyling.story"; 30 | export * from "./stories/flippedButtons.story"; 31 | export * from "./stories/muiButtons.story"; 32 | export * from "./stories/onAccept.story"; 33 | export * from "./stories/overlay.story"; 34 | export * from "./stories/rainbows.story"; 35 | -------------------------------------------------------------------------------- /stories/stories/acceptOnScroll.story.tsx: -------------------------------------------------------------------------------- 1 | import { Story } from "@storybook/react"; 2 | import CookieConsent from "../../src"; 3 | import { CookieConsentProps } from "../../src/CookieConsent.props"; 4 | import { Intro } from "../defaults/intro"; 5 | import { defaultStoryProps } from "../defaults/storyProps"; 6 | 7 | const AcceptOnScrollTemplate: Story = (args) => ( 8 | <> 9 | 10 | {Array.from(Array(25).keys()).map((_something) => ( 11 |

12 | Lorem ipsum dolor sit, amet consectetur adipisicing elit. Voluptates ipsa sequi soluta 13 | mollitia illum, hic quaerat ipsum sint odit delectus magni neque sunt adipisci culpa harum 14 | aut distinctio quisquam ab! 15 |

16 | ))} 17 | 18 | 19 | Scroll for {args.acceptOnScrollPercentage}% and the onAccept will trigger 20 | 21 | 22 | ); 23 | 24 | const AcceptOnScroll = AcceptOnScrollTemplate.bind({}); 25 | AcceptOnScroll.args = { 26 | ...defaultStoryProps, 27 | onAccept: (acceptedByScrolling) => { 28 | alert(`ACCEPTED! By scrolling? ${JSON.stringify(acceptedByScrolling)}`); 29 | }, 30 | acceptOnScroll: true, 31 | acceptOnScrollPercentage: 25, 32 | } as CookieConsentProps; 33 | 34 | export { AcceptOnScroll }; 35 | -------------------------------------------------------------------------------- /stories/stories/additionalButtons.story.tsx: -------------------------------------------------------------------------------- 1 | import { Story } from "@storybook/react"; 2 | import CookieConsent from "../../src"; 3 | import { Intro } from "../defaults/intro"; 4 | import { defaultStoryProps } from "../defaults/storyProps"; 5 | 6 | const AdditionalButtonsTemplate: Story = (args) => ( 7 | <> 8 | 9 | 10 | 11 | This bit of text is smaller :O 12 | 13 | 14 | ); 15 | const AdditionalButtons = AdditionalButtonsTemplate.bind({}); 16 | AdditionalButtons.args = defaultStoryProps; 17 | export { AdditionalButtons }; 18 | -------------------------------------------------------------------------------- /stories/stories/customStyling.story.tsx: -------------------------------------------------------------------------------- 1 | import { CookieConsentProps } from "../../src/CookieConsent.props"; 2 | import { defaultStoryProps } from "../defaults/storyProps"; 3 | import { DefaultTemplate } from "../defaults/template"; 4 | 5 | const CustomStyling = DefaultTemplate.bind({}); 6 | CustomStyling.args = { 7 | ...defaultStoryProps, 8 | style: { background: "red" }, 9 | buttonStyle: { fontWeight: "bold" }, 10 | } as CookieConsentProps; 11 | 12 | export { CustomStyling }; 13 | -------------------------------------------------------------------------------- /stories/stories/flippedButtons.story.tsx: -------------------------------------------------------------------------------- 1 | import { CookieConsentProps } from "../../src/CookieConsent.props"; 2 | import { defaultStoryProps } from "../defaults/storyProps"; 3 | import { DefaultTemplate } from "../defaults/template"; 4 | 5 | const FlippedButtons = DefaultTemplate.bind({}); 6 | FlippedButtons.args = { 7 | ...defaultStoryProps, 8 | flipButtons: true, 9 | enableDeclineButton: true, 10 | } as CookieConsentProps; 11 | 12 | export { FlippedButtons }; 13 | -------------------------------------------------------------------------------- /stories/stories/muiButtons.story.ts: -------------------------------------------------------------------------------- 1 | import { Button } from "@mui/material"; 2 | import { CookieConsentProps } from "../../src/CookieConsent.props"; 3 | import { defaultStoryProps } from "../defaults/storyProps"; 4 | import { DefaultTemplate } from "../defaults/template"; 5 | 6 | const CustomMuiButton = DefaultTemplate.bind({}); 7 | CustomMuiButton.args = { 8 | ...defaultStoryProps, 9 | disableButtonStyles: true, 10 | ButtonComponent: Button, 11 | customButtonProps: { variant: "contained", style: { marginRight: "10px" } }, 12 | } as CookieConsentProps; 13 | 14 | export { CustomMuiButton }; 15 | -------------------------------------------------------------------------------- /stories/stories/onAccept.story.tsx: -------------------------------------------------------------------------------- 1 | import { CookieConsentProps } from "../../src/CookieConsent.props"; 2 | import { defaultStoryProps } from "../defaults/storyProps"; 3 | import { DefaultTemplate } from "../defaults/template"; 4 | 5 | const CustomOnAccept = DefaultTemplate.bind({}); 6 | CustomOnAccept.args = { 7 | ...defaultStoryProps, 8 | onAccept: (acceptedByScrolling) => { 9 | alert(`ACCEPTED! By scrolling? ${JSON.stringify(acceptedByScrolling)}`); 10 | }, 11 | } as CookieConsentProps; 12 | 13 | export { CustomOnAccept }; 14 | -------------------------------------------------------------------------------- /stories/stories/overlay.story.tsx: -------------------------------------------------------------------------------- 1 | import { CookieConsentProps } from "../../src/CookieConsent.props"; 2 | import { defaultStoryProps } from "../defaults/storyProps"; 3 | import { DefaultTemplate } from "../defaults/template"; 4 | 5 | const Overlay = DefaultTemplate.bind({}); 6 | Overlay.args = { 7 | ...defaultStoryProps, 8 | overlay: true, 9 | } as CookieConsentProps; 10 | 11 | export { Overlay }; 12 | -------------------------------------------------------------------------------- /stories/stories/rainbows.story.tsx: -------------------------------------------------------------------------------- 1 | import { CookieConsentProps } from "../../src/CookieConsent.props"; 2 | import { defaultStoryProps } from "../defaults/storyProps"; 3 | import { DefaultTemplate } from "../defaults/template"; 4 | 5 | const Rainbows = DefaultTemplate.bind({}); 6 | Rainbows.args = { 7 | ...defaultStoryProps, 8 | buttonText: "OMG DOUBLE RAINBOW", 9 | 10 | style: { 11 | background: "linear-gradient(to right, orange , yellow, green, cyan, blue, violet)", 12 | textShadow: "2px 2px black", 13 | }, 14 | buttonStyle: { 15 | background: "linear-gradient(to left, orange , yellow, green, cyan, blue, violet)", 16 | color: "white", 17 | fontWeight: "bolder", 18 | textShadow: "2px 2px black", 19 | }, 20 | } as CookieConsentProps; 21 | 22 | export { Rainbows }; 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs 3 | "include": ["src", "types"], 4 | "compilerOptions": { 5 | "module": "esnext", 6 | "lib": ["dom", "esnext"], 7 | "importHelpers": true, 8 | // output .d.ts declaration files for consumers 9 | "declaration": true, 10 | // output .js.map sourcemap files for consumers 11 | "sourceMap": true, 12 | // match output dir to input dir. e.g. dist/index instead of dist/src/index 13 | "rootDir": "./src", 14 | // stricter type-checking for stronger correctness. Recommended by TS 15 | "strict": true, 16 | // linter checks for common issues 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": true, 19 | // noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | // use Node's module resolution algorithm, instead of the legacy TS one 23 | "moduleResolution": "node", 24 | // transpile JSX to React.createElement 25 | "jsx": "react", 26 | // interop between ESM and CJS modules. Recommended by TS 27 | "esModuleInterop": true, 28 | // significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS 29 | "skipLibCheck": true, 30 | // error out if import and file system have a casing mismatch. Recommended by TS 31 | "forceConsistentCasingInFileNames": true, 32 | // `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc` 33 | "noEmit": true, 34 | } 35 | } 36 | --------------------------------------------------------------------------------