33 Commits

Author SHA1 Message Date
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
Davor Peic
3d8c766911 Update index.d.ts (#151) 2022-02-10 14:22:20 +01:00
Abe Tomoaki
3c17b66191 docs(readme): update line number of link to code (#152) 2022-02-10 14:21:55 +01:00
dependabot[bot]
f5447b15a9 Bump tar from 6.1.7 to 6.1.11 (#149)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-08 17:17:14 +01:00
dependabot[bot]
8526d622a5 Bump ansi-regex from 5.0.0 to 5.0.1 (#150)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-08 17:17:06 +01:00
dependabot[bot]
8780dd12f1 Bump semver-regex from 3.1.2 to 3.1.3 (#148)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-08 17:16:58 +01:00
a0e65af081 docfix :) 2022-02-08 17:15:44 +01:00
57dbfbbbd5 release 7.3.0 2022-02-08 17:13:48 +01:00
Oskar Filipowicz
541194819b added customButtonProps (#147) 2022-02-08 17:12:46 +01:00
91d86af611 release 7.2.1 2021-12-28 12:10:14 +01:00
Ron Braha
413abc7fd8 add missing "hideOnDecline" prop to index.d.ts (#145) 2021-12-28 12:07:49 +01:00
2a1e52b24a Fix the TypeScript definition of some properties ( (#144)
Co-authored-by: Souchet Céline <4921914+csouchet@users.noreply.github.com>
2021-12-20 17:49:36 +01:00
775ec9db96 release 7.1.0 2021-12-19 13:30:47 +01:00
eaaf6f8797 Added custom attribute props for content and container 2021-12-19 13:30:42 +01:00
8c86599f24 release 7.0.1 2021-12-11 11:13:55 +01:00
719bb2f496 Switch Library Type from CommonJs2 =&gt; UMD ( (#135)
Co-authored-by: Peter Krieg <pkrieg2@gmail.com>
2021-12-08 17:37:44 +01:00
9a0c974b2a release 6.4.1 2021-09-23 19:16:15 +02:00
43 changed files with 39935 additions and 7504 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"]
}
}

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

1
.prettierignore Normal file
View File

@@ -0,0 +1 @@
build/*

8
.storybook/main.js Normal file
View File

@@ -0,0 +1,8 @@
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.*' },
};

View File

@@ -5,6 +5,67 @@ 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).
## [[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
## [[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.
## [[7.2.1]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.2.1)
- hideOnDecline added to typescript files
- Added .prettieringore
## [[7.2.0]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.2.0)
- Added `onOverlayClick` which allows you to react to a click on the overlay
- Added `acceptOnOverlayClick` which accepts the cookies when the overlay is clicked and runs `onOverlayClick`
## [[7.1.1]](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.1.1)
- `customContentAttributes` and `customContainerAttributes` are now optional in the typing file as they should be
## [[7.1.0](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.1.0)]
- Added custom attribute props for content and container
## [[7.0.1](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.0.1)]
- Configured webpack to remove self from build artefact. Should now work in Nextjs and Gatsby (only tested those..)
## [[7.0.0](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/7.0.0)]
- Switched from CommonJS to UMD module
## [[6.4.1](https://github.com/Mastermindzh/react-cookie-consent/releases/tag/6.4.1))]
- Added missing typing

View File

@@ -138,7 +138,7 @@ 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 |
@@ -159,6 +159,7 @@ That option would be interesting if you want to allow user to change their conse
| 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 |
@@ -174,11 +175,17 @@ That option would be interesting if you want to allow user to change their conse
| 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. |
| 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
@@ -200,7 +207,7 @@ So react-cookie-consent fixes this like so:
- set the fallback cookie (e.g -legacy) first, this will always succeed (on all browsers)
- set the correct cookie second (this will work on modern browsers, fail on older ones)
This happens on lines [186-192](https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L186-L192)
This happens on lines [29-37](https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L29-L37)
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.
@@ -331,11 +338,11 @@ You can also generate a page-obfuscating overlay that will prevent actions other
<!-- links -->
[style]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L18-L29
[buttonstyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L30-L40
[declinebuttonstyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L41-L51
[contentstyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L52-L55
[overlaystyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L62-L69
[style]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L78-L89
[buttonstyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L90-L100
[declinebuttonstyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L101-L111
[contentstyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L112-L115
[overlaystyle]: https://github.com/Mastermindzh/react-cookie-consent/blob/master/src/index.js#L116-L124
## Contributor information

56
build/index.d.ts vendored
View File

@@ -1,56 +0,0 @@
import * as React from "react";
import Cookies from "js-cookie";
export interface CookieConsentProps {
location?: "top" | "bottom" | "none";
sameSite?: "strict" | "lax" | "none";
cookieSecurity?: boolean;
style?: object;
buttonStyle?: object;
declineButtonStyle?: object;
contentStyle?: object;
children?: React.ReactNode;
disableStyles?: boolean;
hideOnAccept?: 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;
ariaAcceptLabel?: string;
ariaDeclineLabel?: string;
acceptOnScroll?: boolean;
acceptOnScrollPercentage?: number;
}
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;
export { Cookies };

View File

@@ -1,743 +0,0 @@
/*! For license information please see index.js.LICENSE.txt */
!(function () {
var e = {
808: function (e, t, n) {
var o, r, i;
void 0 ===
(r =
"function" ==
typeof (o = i =
function () {
function e() {
for (var e = 0, t = {}; e < arguments.length; e++) {
var n = arguments[e];
for (var o in n) t[o] = n[o];
}
return t;
}
function t(e) {
return e.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent);
}
return (function n(o) {
function r() {}
function i(t, n, i) {
if ("undefined" != typeof document) {
"number" == typeof (i = e({ path: "/" }, r.defaults, i)).expires &&
(i.expires = new Date(1 * new Date() + 864e5 * i.expires)),
(i.expires = i.expires ? i.expires.toUTCString() : "");
try {
var c = JSON.stringify(n);
/^[\{\[]/.test(c) && (n = c);
} catch (e) {}
(n = o.write
? o.write(n, t)
: encodeURIComponent(String(n)).replace(
/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,
decodeURIComponent
)),
(t = encodeURIComponent(String(t))
.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent)
.replace(/[\(\)]/g, escape));
var l = "";
for (var a in i)
i[a] && ((l += "; " + a), !0 !== i[a] && (l += "=" + i[a].split(";")[0]));
return (document.cookie = t + "=" + n + l);
}
}
function c(e, n) {
if ("undefined" != typeof document) {
for (
var r = {}, i = document.cookie ? document.cookie.split("; ") : [], c = 0;
c < i.length;
c++
) {
var l = i[c].split("="),
a = l.slice(1).join("=");
n || '"' !== a.charAt(0) || (a = a.slice(1, -1));
try {
var s = t(l[0]);
if (((a = (o.read || o)(a, s) || t(a)), n))
try {
a = JSON.parse(a);
} catch (e) {}
if (((r[s] = a), e === s)) break;
} catch (e) {}
}
return e ? r[e] : r;
}
}
return (
(r.set = i),
(r.get = function (e) {
return c(e, !1);
}),
(r.getJSON = function (e) {
return c(e, !0);
}),
(r.remove = function (t, n) {
i(t, "", e(n, { expires: -1 }));
}),
(r.defaults = {}),
(r.withConverter = n),
r
);
})(function () {});
})
? o.call(t, n, t, e)
: o) || (e.exports = r),
(e.exports = i());
},
703: function (e, t, n) {
"use strict";
var o = n(414);
function r() {}
function i() {}
(i.resetWarningCache = r),
(e.exports = function () {
function e(e, t, n, r, i, c) {
if (c !== o) {
var l = new Error(
"Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types"
);
throw ((l.name = "Invariant Violation"), l);
}
}
function t() {
return e;
}
e.isRequired = e;
var n = {
array: e,
bool: e,
func: e,
number: e,
object: e,
string: e,
symbol: e,
any: e,
arrayOf: t,
element: e,
elementType: e,
instanceOf: t,
node: e,
objectOf: t,
oneOf: t,
oneOfType: t,
shape: t,
exact: t,
checkPropTypes: i,
resetWarningCache: r,
};
return (n.PropTypes = n), n;
});
},
697: function (e, t, n) {
e.exports = n(703)();
},
414: function (e) {
"use strict";
e.exports = "SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";
},
},
t = {};
function n(o) {
var r = t[o];
if (void 0 !== r) return r.exports;
var i = (t[o] = { exports: {} });
return e[o](i, i.exports, n), i.exports;
}
(n.n = function (e) {
var t =
e && e.__esModule
? function () {
return e.default;
}
: function () {
return e;
};
return n.d(t, { a: t }), t;
}),
(n.d = function (e, t) {
for (var o in t)
n.o(t, o) && !n.o(e, o) && Object.defineProperty(e, o, { enumerable: !0, get: t[o] });
}),
(n.o = function (e, t) {
return Object.prototype.hasOwnProperty.call(e, t);
}),
(n.r = function (e) {
"undefined" != typeof Symbol &&
Symbol.toStringTag &&
Object.defineProperty(e, Symbol.toStringTag, { value: "Module" }),
Object.defineProperty(e, "__esModule", { value: !0 });
});
var o = {};
!(function () {
"use strict";
n.r(o),
n.d(o, {
Cookies: function () {
return l();
},
OPTIONS: function () {
return m;
},
SAME_SITE_OPTIONS: function () {
return g;
},
VISIBLE_OPTIONS: function () {
return S;
},
default: function () {
return B;
},
getCookieConsentValue: function () {
return C;
},
resetCookieConsentValue: function () {
return k;
},
});
const e = require("react");
var t = n.n(e),
r = n(697),
i = n.n(r),
c = n(808),
l = n.n(c);
function a(e) {
return (a =
"function" == typeof Symbol && "symbol" == typeof Symbol.iterator
? function (e) {
return typeof e;
}
: function (e) {
return e &&
"function" == typeof Symbol &&
e.constructor === Symbol &&
e !== Symbol.prototype
? "symbol"
: typeof e;
})(e);
}
var s = ["children"];
function u() {
return (u =
Object.assign ||
function (e) {
for (var t = 1; t < arguments.length; t++) {
var n = arguments[t];
for (var o in n) Object.prototype.hasOwnProperty.call(n, o) && (e[o] = n[o]);
}
return e;
}).apply(this, arguments);
}
function p(e, t) {
var n = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var o = Object.getOwnPropertySymbols(e);
t &&
(o = o.filter(function (t) {
return Object.getOwnPropertyDescriptor(e, t).enumerable;
})),
n.push.apply(n, o);
}
return n;
}
function f(e) {
for (var t = 1; t < arguments.length; t++) {
var n = null != arguments[t] ? arguments[t] : {};
t % 2
? p(Object(n), !0).forEach(function (t) {
h(e, t, n[t]);
})
: Object.getOwnPropertyDescriptors
? Object.defineProperties(e, Object.getOwnPropertyDescriptors(n))
: p(Object(n)).forEach(function (t) {
Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(n, t));
});
}
return e;
}
function d(e, t) {
for (var n = 0; n < t.length; n++) {
var o = t[n];
(o.enumerable = o.enumerable || !1),
(o.configurable = !0),
"value" in o && (o.writable = !0),
Object.defineProperty(e, o.key, o);
}
}
function b(e, t) {
return (b =
Object.setPrototypeOf ||
function (e, t) {
return (e.__proto__ = t), e;
})(e, t);
}
function y(e, t) {
if (t && ("object" === a(t) || "function" == typeof t)) return t;
if (void 0 !== t)
throw new TypeError("Derived constructors may only return object or undefined");
return v(e);
}
function v(e) {
if (void 0 === e)
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
return e;
}
function O(e) {
return (O = Object.setPrototypeOf
? Object.getPrototypeOf
: function (e) {
return e.__proto__ || Object.getPrototypeOf(e);
})(e);
}
function h(e, t, n) {
return (
t in e
? Object.defineProperty(e, t, {
value: n,
enumerable: !0,
configurable: !0,
writable: !0,
})
: (e[t] = n),
e
);
}
var m = { TOP: "top", BOTTOM: "bottom", NONE: "none" },
g = { STRICT: "strict", LAX: "lax", NONE: "none" },
S = { HIDDEN: "hidden", SHOW: "show", BY_COOKIE_VALUE: "byCookieValue" },
C = function () {
var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : w,
t = l().get(e);
return void 0 === t && (t = l().get(x(e))), t;
},
k = function () {
var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : w;
l().remove(e);
},
x = function (e) {
return "".concat(e, "-legacy");
},
w = "CookieConsent",
j = function (e) {
var t = e.condition,
n = e.wrapper,
o = e.children;
return t ? n(o) : o;
},
T = (function (e) {
!(function (e, t) {
if ("function" != typeof t && null !== t)
throw new TypeError("Super expression must either be null or a function");
(e.prototype = Object.create(t && t.prototype, {
constructor: { value: e, writable: !0, configurable: !0 },
})),
t && b(e, t);
})(a, e);
var n,
o,
r,
i,
c =
((r = a),
(i = (function () {
if ("undefined" == typeof Reflect || !Reflect.construct) return !1;
if (Reflect.construct.sham) return !1;
if ("function" == typeof Proxy) return !0;
try {
return (
Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})), !0
);
} catch (e) {
return !1;
}
})()),
function () {
var e,
t = O(r);
if (i) {
var n = O(this).constructor;
e = Reflect.construct(t, arguments, n);
} else e = t.apply(this, arguments);
return y(this, e);
});
function a(e) {
var t;
return (
(function (e, t) {
if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function");
})(this, a),
h(v((t = c.call(this, e))), "handleScroll", function () {
var e = t.props.acceptOnScrollPercentage,
n = document.documentElement,
o = document.body,
r = "scrollTop",
i = "scrollHeight";
((n[r] || o[r]) / ((n[i] || o[i]) - n.clientHeight)) * 100 > e && t.accept(!0);
}),
h(v(t), "removeScrollListener", function () {
t.props.acceptOnScroll && window.removeEventListener("scroll", t.handleScroll);
}),
(t.state = {
visible: !1,
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)",
},
}),
t
);
}
return (
(n = a),
(o = [
{
key: "componentDidMount",
value: function () {
var e = this.props.debug;
(void 0 === this.getCookieValue() || e) &&
(this.setState({ visible: !0 }),
this.props.acceptOnScroll &&
window.addEventListener("scroll", this.handleScroll, { passive: !0 }));
},
},
{
key: "componentWillUnmount",
value: function () {
this.removeScrollListener();
},
},
{
key: "accept",
value: function () {
var e = arguments.length > 0 && void 0 !== arguments[0] && arguments[0],
t = this.props,
n = t.cookieName,
o = t.cookieValue,
r = t.hideOnAccept,
i = t.onAccept;
this.setCookie(n, o),
i(null != e && e),
r && (this.setState({ visible: !1 }), this.removeScrollListener());
},
},
{
key: "decline",
value: function () {
var e = this.props,
t = e.cookieName,
n = e.declineCookieValue,
o = e.hideOnDecline,
r = e.onDecline;
e.setDeclineCookie && this.setCookie(t, n),
r(),
o && this.setState({ visible: !1 });
},
},
{
key: "setCookie",
value: function (e, t) {
var n = this.props,
o = n.extraCookieOptions,
r = n.expires,
i = n.sameSite,
c = this.props.cookieSecurity;
void 0 === c && (c = !location || "https:" === location.protocol);
var a = f(f({ expires: r }, o), {}, { sameSite: i, secure: c });
i === g.NONE && l().set(x(e), t, a), l().set(e, t, a);
},
},
{
key: "getCookieValue",
value: function () {
var e = this.props.cookieName;
return C(e);
},
},
{
key: "render",
value: function () {
var e = this;
switch (this.props.visible) {
case S.HIDDEN:
return null;
case S.BY_COOKIE_VALUE:
if (!this.state.visible) return null;
}
var n = this.props,
o = n.location,
r = n.style,
i = n.buttonStyle,
c = n.declineButtonStyle,
l = n.contentStyle,
a = n.disableStyles,
s = n.buttonText,
p = n.declineButtonText,
d = n.containerClasses,
b = n.contentClasses,
y = n.buttonClasses,
v = n.buttonWrapperClasses,
O = n.declineButtonClasses,
h = n.buttonId,
g = n.declineButtonId,
C = n.disableButtonStyles,
k = n.enableDeclineButton,
x = n.flipButtons,
w = n.ButtonComponent,
T = n.overlay,
B = n.overlayClasses,
E = n.overlayStyle,
P = n.ariaAcceptLabel,
D = n.ariaDeclineLabel,
I = {},
_ = {},
N = {},
A = {},
L = {};
switch (
(a
? ((I = u({}, r)),
(_ = u({}, i)),
(N = u({}, c)),
(A = u({}, l)),
(L = u({}, E)))
: ((I = u({}, f(f({}, this.state.style), r))),
(A = u({}, f(f({}, this.state.contentStyle), l))),
(L = u({}, f(f({}, this.state.overlayStyle), E))),
C
? ((_ = u({}, i)), (N = u({}, c)))
: ((_ = u({}, f(f({}, this.state.buttonStyle), i))),
(N = u({}, f(f({}, this.state.declineButtonStyle), c))))),
o)
) {
case m.TOP:
I.top = "0";
break;
case m.BOTTOM:
I.bottom = "0";
}
var R = [];
return (
k &&
R.push(
t().createElement(
w,
{
key: "declineButton",
style: N,
className: O,
id: g,
"aria-label": D,
onClick: function () {
e.decline();
},
},
p
)
),
R.push(
t().createElement(
w,
{
key: "acceptButton",
style: _,
className: y,
id: h,
"aria-label": P,
onClick: function () {
e.accept();
},
},
s
)
),
x && R.reverse(),
t().createElement(
j,
{
condition: T,
wrapper: function (e) {
return t().createElement("div", { style: L, className: B }, e);
},
},
t().createElement(
"div",
{ className: "".concat(d), style: I },
t().createElement("div", { style: A, className: b }, this.props.children),
t().createElement(
"div",
{ className: "".concat(v) },
R.map(function (e) {
return e;
})
)
)
)
);
},
},
]) && d(n.prototype, o),
a
);
})(e.Component);
(T.propTypes = {
location: i().oneOf(
Object.keys(m).map(function (e) {
return m[e];
})
),
visible: i().oneOf(
Object.keys(S).map(function (e) {
return S[e];
})
),
sameSite: i().oneOf(
Object.keys(g).map(function (e) {
return g[e];
})
),
style: i().object,
buttonStyle: i().object,
declineButtonStyle: i().object,
contentStyle: i().object,
children: i().any,
disableStyles: i().bool,
hideOnAccept: i().bool,
hideOnDecline: i().bool,
onAccept: i().func,
onDecline: i().func,
buttonText: i().oneOfType([i().string, i().func, i().element]),
declineButtonText: i().oneOfType([i().string, i().func, i().element]),
cookieName: i().string,
cookieValue: i().oneOfType([i().string, i().bool, i().number]),
declineCookieValue: i().oneOfType([i().string, i().bool, i().number]),
setDeclineCookie: i().bool,
debug: i().bool,
expires: i().number,
containerClasses: i().string,
contentClasses: i().string,
buttonClasses: i().string,
buttonWrapperClasses: i().string,
declineButtonClasses: i().string,
buttonId: i().string,
declineButtonId: i().string,
extraCookieOptions: i().object,
disableButtonStyles: i().bool,
enableDeclineButton: i().bool,
flipButtons: i().bool,
ButtonComponent: i().elementType,
cookieSecurity: i().bool,
overlay: i().bool,
overlayClasses: i().string,
overlayStyle: i().object,
ariaAcceptLabel: i().string,
ariaDeclineLabel: i().string,
acceptOnScroll: i().bool,
acceptOnScrollPercentage: i().number,
}),
(T.defaultProps = {
disableStyles: !1,
hideOnAccept: !0,
hideOnDecline: !0,
location: m.BOTTOM,
visible: S.BY_COOKIE_VALUE,
onAccept: function () {},
onDecline: function () {},
cookieName: w,
cookieValue: !0,
declineCookieValue: !1,
setDeclineCookie: !0,
buttonText: "I understand",
declineButtonText: "I decline",
debug: !1,
expires: 365,
containerClasses: "CookieConsent",
contentClasses: "",
buttonClasses: "",
buttonWrapperClasses: "",
declineButtonClasses: "",
buttonId: "rcc-confirm-button",
declineButtonId: "rcc-decline-button",
extraCookieOptions: {},
disableButtonStyles: !1,
enableDeclineButton: !1,
flipButtons: !1,
sameSite: g.LAX,
ButtonComponent: function (e) {
var n = e.children,
o = (function (e, t) {
if (null == e) return {};
var n,
o,
r = (function (e, t) {
if (null == e) return {};
var n,
o,
r = {},
i = Object.keys(e);
for (o = 0; o < i.length; o++) (n = i[o]), t.indexOf(n) >= 0 || (r[n] = e[n]);
return r;
})(e, t);
if (Object.getOwnPropertySymbols) {
var i = Object.getOwnPropertySymbols(e);
for (o = 0; o < i.length; o++)
(n = i[o]),
t.indexOf(n) >= 0 ||
(Object.prototype.propertyIsEnumerable.call(e, n) && (r[n] = e[n]));
}
return r;
})(e, s);
return t().createElement("button", o, n);
},
overlay: !1,
overlayClasses: "",
ariaAcceptLabel: "Accept cookies",
ariaDeclineLabel: "Decline cookies",
acceptOnScroll: !1,
acceptOnScrollPercentage: 25,
});
const B = T;
})(),
(module.exports = o);
})();

Submodule example deleted from bff8dd76c5

46133
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,74 +1,98 @@
{
"name": "react-cookie-consent",
"author": {
"name": "Rick van Lieshout",
"email": "info@rickvanlieshout.com"
},
"version": "6.4.0",
"version": "8.0.1",
"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",
"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",
"install-husky": "npx husky install",
"publish": "npx np",
"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",
"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" | undefined;
}
const DefaultButtonComponent: FunctionComponent<{ children: ReactNode; [x: string]: any }> = ({
children,
...props
}) => {
return <button {...props}>{children}</button>;
};
export const defaultCookieConsentProps: CookieConsentProps = {
disableStyles: false,
hideOnAccept: true,
hideOnDecline: true,
location: POSITION_OPTIONS.BOTTOM,
visible: VISIBILITY_OPTIONS.BY_COOKIE_VALUE,
onAccept: (_acceptedByScrolling) => {},
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)",
},
};

301
src/CookieConsent.tsx Normal file
View File

@@ -0,0 +1,301 @@
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 } = 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: 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 } = 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;
};

70
src/index.d.ts vendored
View File

@@ -1,70 +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;
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;
ariaAcceptLabel?: string;
ariaDeclineLabel?: string;
acceptOnScroll?: boolean;
acceptOnScrollPercentage?: number;
}
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 };

View File

@@ -1,472 +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();
}
}
/**
* 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,
} = 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
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}>
{children}
</div>
)}
>
<div className={`${containerClasses}`} style={myStyle}>
<div style={myContentStyle} className={contentClasses}>
{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,
ariaAcceptLabel: PropTypes.string,
ariaDeclineLabel: PropTypes.string,
acceptOnScroll: PropTypes.bool,
acceptOnScrollPercentage: PropTypes.number,
};
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: "",
ariaAcceptLabel: "Accept cookies",
ariaDeclineLabel: "Decline cookies",
acceptOnScroll: false,
acceptOnScrollPercentage: 25,
};
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,33 +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",
libraryTarget: "commonjs2", // THIS IS THE MOST IMPORTANT LINE! :mindblow: I wasted more than 2 days until realize this was the line most important in all this guide.
environment: {
arrowFunction: false, // the generated runtime-code should not use arrow functions
},
},
module: {
rules: [
{
test: /\.js$/,
include: path.resolve(__dirname, "src"),
exclude: /(node_modules|bower_components|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" }] })],
};