diff --git a/CHANGELOG.md b/CHANGELOG.md index fe8f93e9..b6496179 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## [2.2.0](https://github.com/openmail/system1-cmp/compare/2.1.7...2.1.8) (2021-05-17) + +### Feat + +- [x] Upgrade vendor list and script to download vendor list +- [x] Add relative position modal solution +- [x] Add `updateConfig` API to switch between relative and static position +- [x] Pass theme colors through to anchors + ## [2.1.7](https://github.com/openmail/system1-cmp/compare/2.1.6...2.1.7) (2021-03-05) ### Feat diff --git a/README.md b/README.md index 712e9863..a0eac338 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ Read more about [\_\_tcfapi built-in API](https://github.com/InteractiveAdvertis - [offConsentAllChanged](#offConsentAllChanged) - [showConsentTool](#showConsentTool) - [changeLanguage](#changeLanguage) +- [changeConfig](#changeConfig) ### init @@ -185,6 +186,20 @@ Calling `__tcfapi('changeLanguage', 2, () => {}, language)` will use cached vers __tcfapi('changeLanguage', 2, (store) => {}, 'pt'); // changes to Portuguese ``` +### changeConfig + +Calling `__tcfapi('changeConfig', 2, () => {}, {isSlimMode: true, theme: {isInlineMode: false}})` will update config values and rerender CMP UI + +```js +/** + * @param 'changeConfig' // required string command + * @param apiVersion // required number 2 + * @param callback // required function, called when changeLanguage completes, called with `store` and result + * @param config // required object, merges with existing config object providing during `init()` + */ +__tcfapi('changeConfig', 2, (store) => {}, {theme: {isInlineMode: false}}); // changes config to use inline-mode +``` + ## Configuration / Config Set configuration for your CMP during the `init` phase. @@ -224,6 +239,7 @@ __tcfapi('init', 2, () => {}, { | `shouldUseStacks` | optional boolean | `true` | true uses stacks on Layer1, TODO stacks need purposes/custom-features toggle to be compliant | | `isSlimMode` | optional boolean | `false` | If `true`, initial banner is low profile, full width banner v2.1.4+ | | `shouldShowCloseX` | optional boolean | `false` | If `true`, a × icon will appear in the upper right on layers to accept-all and close v2.1.4+ | +| `insertionNode` | optional string | `
` | UI will be appended to this element using `querySelector`. Default behavior appends to body v2.2.0+ | ### theme @@ -233,6 +249,7 @@ Themeing is a bit limited right now. Pass in a `config.theme` object during init | ----------------------- | ---------------- | -------- | -------------------------------------------------------------------------------------------------------- | | `maxHeightModal` | optional string | `45vh` | CSS style for max height of the CMP UI. Example: `45vh`, `50%`, `350px` | | `maxWidthModal` | optional string | `1024px` | CSS style for max width of the CMP UI. Example: `1024px`, `calc(90% - 100px)` | +| `maxHeightInline` | optional string | `200px` | CSS style to force max-height of CMP UI while in `isBannerInline` mode only. | | `shouldAutoResizeModal` | optional boolean | true | Auto detects Layer1 height to minimize UI. UI resizes to `maxHeightModal` upon interaction | | `primaryColor` | optional string | null | Example: `#0099ff` | | `textLinkColor` | optional string | null | Example: `#0099ff` | @@ -240,6 +257,7 @@ Themeing is a bit limited right now. Pass in a `config.theme` object during init | `featuresColor` | optional string | null | Example: `#d0d3d7` | | `backgroundColor` | optional string | null | Example: `#d0d3d7` Sets the background color of the banners. v2.1.4+ | | `isFullWidth` | optional boolean | false | Removes rounded corners and makes banners full width - matching style layout slimMode v2.1.4+ | +| `isBannerInline` | optional boolean | false | Renders CMP inline instead of overlaying layout. Subsequent CMP views open in modal v2.2.0+ | | `shouldShowDropShadow` | optional boolean | true | When set to `true`, displays the drop shadoq on banners v2.1.4+ | ## Initialize With Euconsent String from URL Param diff --git a/package.json b/package.json index 9a79924a..878575c7 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "system1-cmp", - "version": "2.1.7", - "cmpVersion": 5, + "version": "2.2.0", + "cmpVersion": 6, "description": "System1 Consent Management Platform for TCF 1.1 GDPR Compliance", "scripts": { "clean": "rimraf ./dist", "dev": "yarn dev:s1", - "dev:s1": "cross-env NODE_ENV=development webpack-dev-server --inline --hot --progress --config config/s1.webpack.config.babel.js", + "dev:s1": "cross-env PORT=3030 NODE_ENV=development webpack-dev-server --inline --hot --progress --config config/s1.webpack.config.babel.js", "dev:original": "cross-env NODE_ENV=development webpack-dev-server --inline --hot --progress --config config/webpack.config.babel.js", "start": "serve dist -c 1", "prestart": "npm run build", diff --git a/scripts/run.js b/scripts/run.js index 223b3335..ded872f9 100644 --- a/scripts/run.js +++ b/scripts/run.js @@ -8,7 +8,7 @@ const fs = require('fs'); const https = require('https'); const { LANGUAGES } = require('../src/s1/constants.js'); -const VENDOR_LIST_URL = 'https://vendorlist.consensu.org/v2/vendor-list.json'; +const VENDOR_LIST_URL = 'https://vendor-list.consensu.org/v2/vendor-list.json'; const externalFiles = [ { @@ -50,7 +50,7 @@ const processFiles = () => { LANGUAGES.filter(({ shouldDisablePurposesFetch = false }) => !shouldDisablePurposesFetch).forEach( ({ display, code }) => { downloadFile( - `https://vendorlist.consensu.org/v2/purposes-${code}.json`, + `https://vendor-list.consensu.org/v2/purposes-${code}.json`, `src/s1/config/2.0/purposes/purposes-${code}.json` ) .then(() => { diff --git a/src/s1/components/banner/banner.less b/src/s1/components/banner/banner.less index 1a194cd3..2b915ca7 100644 --- a/src/s1/components/banner/banner.less +++ b/src/s1/components/banner/banner.less @@ -17,26 +17,17 @@ color: @color-textLight; background: #fff; font-size: 16px; - transition: transform 350ms ease-in-out, opacity 350ms linear; + transition: transform 350ms ease-in-out, opacity 350ms linear; margin: auto; + overflow: hidden; &.bannerShadow { box-shadow: 0 -1px 1px rgba(0, 0, 0, 0.12), 0 -2px 2px rgba(0, 0, 0, 0.12), 0 -4px 4px rgba(0, 0, 0, 0.12), 0 -8px 8px rgba(0, 0, 0, 0.12), 0 -16px 16px rgba(0, 0, 0, 0.12); } - &.bannerRounded { - border-top-left-radius: 25px; - border-top-right-radius: 25px; - border-bottom-left-radius: 10px; - border-bottom-right-radius: 10px; - width: calc(100% - 50px); - max-width: 1024px; - } - @media @smartphone { padding: 15px 10px; - width: calc(100% - 20px); } &.hidden { @@ -46,11 +37,6 @@ transition-delay: 250ms; } - &.bannerInline { - position: relative; - box-shadow: none; - } - &.bannerModal { top: 0; display: flex; @@ -104,6 +90,10 @@ margin-bottom: 0; padding: 0 30px 30px; + .message { + padding-bottom: 0; + } + @media @smartphone { padding: 12px 20px 0; @@ -139,6 +129,51 @@ } } + &.bannerInline { + position: relative; + // max-height: 680px; + + &.hidden { + pointer-events: none; + transform: translateY(0px); + opacity: 0; + transition-delay: 250ms; + padding-top: 0; + max-height: 0px; + transition: transform 350ms ease-in-out, opacity 350ms linear, max-height 350ms ease-in-out, padding 350ms ease-in-out; + overflow: hidden; + } + + .content { + margin-bottom: 0px; + + .message { + padding-bottom: 60px; + } + } + + &.bannerSlim { + .content { + .message { + padding-bottom: 0; + } + } + } + } + + &.bannerRounded { + border-top-left-radius: 25px; + border-top-right-radius: 25px; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; + width: calc(100% - 50px); + max-width: 1024px; + + @media @smartphone { + width: calc(100% - 20px); + } + } + .content { max-height: 60vh; padding-left: 30px; @@ -150,6 +185,14 @@ -webkit-overflow-scrolling: touch; transition: max-height 350ms ease-in-out; + &.animated { + overflow: auto; + animation: hide-scroll 500ms backwards; + @keyframes hide-scroll { + from, to { overflow: hidden; } + } + } + @media @smartphone { padding-top: 0px; padding-left: 5px; diff --git a/src/s1/components/banner/bannerSlim.jsx b/src/s1/components/banner/bannerSlim.jsx index 17a2217e..4c134c2c 100644 --- a/src/s1/components/banner/bannerSlim.jsx +++ b/src/s1/components/banner/bannerSlim.jsx @@ -111,7 +111,7 @@ export default class BannerSlim extends Component { handleResize = debounce(() => { const { store } = this.props; - const { maxHeightModal, shouldAutoResizeModal } = store; + const { maxHeightModal, shouldAutoResizeModal} = store; let newMaxHeightModal = maxHeightModal; @@ -136,16 +136,20 @@ export default class BannerSlim extends Component { const { hasScrolled } = state; const { isShowing, store } = props; const { - config: { theme, shouldShowCloseX, }, + config: { theme, shouldShowCloseX}, translations, - maxHeightModal, + maxHeightModal, + minHeightModal } = store; const { isBannerModal, isBannerInline, + isFullWidth, maxWidthModal, + maxHeightInline, // maxHeightModal, // handled in store + // minHeightModal, // handled in store primaryColor, primaryTextColor, backgroundColor, @@ -158,7 +162,10 @@ export default class BannerSlim extends Component { if (!isShowing) { bannerClasses.push(style.hidden); } - if( shouldShowDropShadow ) { + if (!isFullWidth) { + bannerClasses.push(style.bannerRounded); + } + if (shouldShowDropShadow) { bannerClasses.push(style.bannerShadow); } if (isBannerModal) { @@ -167,6 +174,8 @@ export default class BannerSlim extends Component { bannerClasses.push(style.bannerInline); } + const maxHeightStr = (isBannerInline && maxHeightInline ? `min(${maxHeightInline}, ${isNaN(maxHeightModal) ? maxHeightModal : maxHeightModal + 'px'})` : maxHeightModal); + return (