Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add inline CSS options #187

Merged
merged 4 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/transcend-io/consent-manager-ui.git"
},
"homepage": "https://github.com/transcend-io/consent-manager-ui",
"version": "4.19.1",
"version": "4.20.0",
"license": "MIT",
"main": "build/ui",
"files": [
Expand Down
4 changes: 4 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const {
languages,
dismissedViewState = 'Hidden',
nonce,
inlineCss
} = settings;

/**
Expand Down Expand Up @@ -210,3 +211,6 @@ if (CSP_NONCE) {
delete currentScriptDataset.nonce;
}
}

export const ALLOW_INLINE_CSS = inlineCss !== 'off';
export const EXTERNALIZE_INLINE_CSS = inlineCss === 'data:';
csmccarthy marked this conversation as resolved.
Show resolved Hide resolved
54 changes: 38 additions & 16 deletions src/consent-manager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ import type {
import { App } from './components/App';
import { logger } from './logger';
import { createHTMLElement } from './utils/create-html-element';
import { CSP_NONCE, getMergedConfig } from './config';
import {
ALLOW_INLINE_CSS,
CSP_NONCE,
EXTERNALIZE_INLINE_CSS,
getMergedConfig,
} from './config';
import { CSS_RESET } from './constants';

// The `transcend` API: methods which we'll create inside Preact and pass back out here via callback
let consentManagerAPI: ConsentManagerAPI | null = null;
Expand All @@ -31,6 +37,11 @@ export const injectConsentManagerApp = async (
consentManager.style.zIndex = mergedConfig.config.uiZIndex ?? '2147483647';
consentManager.id = 'transcend-consent-manager';

const attachToDoc = (): void => {
// Append UI container to doc to activate style.sheet
(document.documentElement || document).append(consentManager);
};

try {
const shadowRoot =
consentManager?.attachShadow?.({
Expand All @@ -46,27 +57,38 @@ export const injectConsentManagerApp = async (
appContainer ??= createHTMLElement('div');
shadowRoot.appendChild(appContainer);

// Don't inherit global styles
const style = createHTMLElement<HTMLStyleElement>('style');
if (ALLOW_INLINE_CSS) {
// Don't inherit global styles
const style = createHTMLElement<HTMLStyleElement | HTMLLinkElement>(
EXTERNALIZE_INLINE_CSS ? 'link' : 'style',
);

if (CSP_NONCE) {
style.nonce = CSP_NONCE;
}
if (CSP_NONCE) {
style.nonce = CSP_NONCE;
}

appContainer.appendChild(style);
if (EXTERNALIZE_INLINE_CSS) {
(style as HTMLLinkElement).rel = 'stylesheet';
(style as HTMLLinkElement).href = `data:text/css,${encodeURIComponent(
CSS_RESET,
)}`;
}

// Append UI container to doc to activate style.sheet
(document.documentElement || document).append(consentManager);
// activate stylesheet
// we want to activate AFTER setup for external and BEFORE setup for inline
appContainer.appendChild(style);
attachToDoc();
Comment on lines +79 to +80
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

had to move stuff around to keep this optimal. we want to activate the stylesheet after setup for the external one, and activate it before setup for the inline one

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(hence the two orthogonal ifs with a between step instead of an if else)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just wanted to ask this, makes sense


if (CSP_NONCE) {
style.nonce = CSP_NONCE;
if (!EXTERNALIZE_INLINE_CSS) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
(style as HTMLStyleElement)
.sheet! // 1st rule so subsequent properties are reset
.insertRule(CSS_RESET);
}
} else {
attachToDoc();
}

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
style
.sheet! // 1st rule so subsequent properties are reset
.insertRule(':host { all: initial }');

// Wait for the instantiated Consent Manager API from Preact
consentManagerAPI = await new Promise<ConsentManagerAPI>((resolve) => {
// Render Preact app inside the shadow DOM component
Expand Down
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export const VERSION = process.env.VERSION as string;
export const CONSENT_OPTIONS = { confirmed: true, prompted: true };
export const CSS_RESET = ':host{all:initial}';
Loading