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

PROD-1277 Refactor embedded mode to not use A11y dialog #4355

Merged
merged 6 commits into from
Oct 31, 2023
Merged
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -17,6 +17,9 @@ The types of changes are:

## [Unreleased](https://github.com/ethyca/fides/compare/2.23.0...main)

### Changed
- Refactor Fides.js embedded modal to not use A11y dialog [#4355](https://github.com/ethyca/fides/pull/4355)

## [2.23.0](https://github.com/ethyca/fides/compare/2.22.1...2.23.0)

### Added
59 changes: 59 additions & 0 deletions clients/fides-js/src/components/ConsentContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { ComponentChildren, VNode, h } from "preact";
import { HTMLAttributes } from "react";
import { ExperienceConfig } from "../lib/consent-types";

import GpcInfo from "./GpcInfo";
import ExperienceDescription from "./ExperienceDescription";
import { getConsentContext } from "../fides";

export interface ConsentContentProps {
title: HTMLAttributes<HTMLHeadingElement>;
experience: ExperienceConfig;
children: ComponentChildren;
className?: string;
onVendorPageClick?: () => void;
renderModalFooter: () => VNode;
}

const ConsentModal = ({
title,
className,
experience,
renderModalFooter,
children,
onVendorPageClick,
}: ConsentContentProps) => {
const showGpcBadge = getConsentContext().globalPrivacyControl;

return (
<div
data-testid="consent-content"
id="fides-consent-content"
className={className}
>
<div className="fides-modal-body">
<h1
data-testid="fides-modal-title"
{...title}
className="fides-modal-title"
>
{experience.title}
</h1>
<p
data-testid="fides-modal-description"
className="fides-modal-description"
>
<ExperienceDescription
onVendorPageClick={onVendorPageClick}
description={experience.description}
/>
</p>
{showGpcBadge && <GpcInfo />}
{children}
</div>
<div className="fides-modal-footer">{renderModalFooter()}</div>
</div>
);
};

export default ConsentModal;
42 changes: 12 additions & 30 deletions clients/fides-js/src/components/ConsentModal.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,30 @@
import { ComponentChildren, VNode, h } from "preact";
import { VNode, h } from "preact";
import { Attributes } from "../lib/a11y-dialog";
import { ExperienceConfig } from "../lib/consent-types";

import CloseButton from "./CloseButton";
import GpcInfo from "./GpcInfo";
import ExperienceDescription from "./ExperienceDescription";
import { getConsentContext } from "../fides";
import ConsentContent from "./ConsentContent";

const ConsentModal = ({
attributes,
experience,
children,
onVendorPageClick,
renderModalFooter,
renderModalContent,
}: {
attributes: Attributes;
experience: ExperienceConfig;
children: ComponentChildren;
onVendorPageClick?: () => void;
renderModalFooter: () => VNode;
renderModalContent: () => VNode;
}) => {
const { container, overlay, dialog, title, closeButton } = attributes;
const showGpcBadge = getConsentContext().globalPrivacyControl;

return (
// @ts-ignore A11yDialog ref obj type isn't quite the same
<div
data-testid="consent-modal"
{...container}
className={`fides-modal-container ${attributes.container.className}`}
className="fides-modal-container"
>
<div {...overlay} className="fides-modal-overlay" />
<div
@@ -40,27 +36,13 @@ const ConsentModal = ({
<div />
<CloseButton ariaLabel="Close modal" onClick={closeButton.onClick} />
</div>
<div className="fides-modal-body">
<h1
data-testid="fides-modal-title"
{...title}
className="fides-modal-title"
>
{experience.title}
</h1>
<p
data-testid="fides-modal-description"
className="fides-modal-description"
>
<ExperienceDescription
onVendorPageClick={onVendorPageClick}
description={experience.description}
/>
</p>
{showGpcBadge && <GpcInfo />}
{children}
</div>
<div className="fides-modal-footer">{renderModalFooter()}</div>
<ConsentContent
title={title}
experience={experience}
renderModalFooter={renderModalFooter}
>
{renderModalContent()}
</ConsentContent>
</div>
</div>
);
43 changes: 29 additions & 14 deletions clients/fides-js/src/components/Overlay.tsx
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ import ConsentModal from "./ConsentModal";
import { useHasMounted } from "../lib/hooks";
import { dispatchFidesEvent } from "../lib/events";
import { FidesCookie } from "../lib/cookie";
import ConsentContent from "./ConsentContent";

interface RenderBannerProps {
isOpen: boolean;
@@ -55,7 +56,6 @@ const Overlay: FunctionComponent<Props> = ({
const { instance, attributes } = useA11yDialog({
id: "fides-modal",
role: "alertdialog",
className: options.fidesEmbed ? "fides-embed" : "",
title: experience?.experience_config?.title || "",
useOverlowStyling: !options.fidesEmbed,
onClose: dispatchCloseEvent,
@@ -149,19 +149,34 @@ const Overlay: FunctionComponent<Props> = ({
onManagePreferencesClick: handleManagePreferencesClick,
})
: null}
<ConsentModal
attributes={attributes}
experience={experience.experience_config}
onVendorPageClick={onVendorPageClick}
renderModalFooter={() =>
renderModalFooter({
onClose: handleCloseModal,
isMobile: false,
})
}
>
{renderModalContent()}
</ConsentModal>
{options.fidesEmbed ? (
<ConsentContent
title={attributes.title}
className="fides-embed"
experience={experience.experience_config}
renderModalFooter={() =>
renderModalFooter({
onClose: handleCloseModal,
isMobile: false,
})
}
>
{renderModalContent()}
</ConsentContent>
) : (
<ConsentModal
attributes={attributes}
experience={experience.experience_config}
onVendorPageClick={onVendorPageClick}
renderModalFooter={() =>
renderModalFooter({
onClose: handleCloseModal,
isMobile: false,
})
}
renderModalContent={renderModalContent}
/>
)}
</div>
);
};
56 changes: 33 additions & 23 deletions clients/fides-js/src/components/fides.css
Original file line number Diff line number Diff line change
@@ -309,31 +309,36 @@ div.fides-modal-content {

/*Fides Embed*/

div#fides-embed-container:focus-visible,
div#fides-embed-container div#fides-modal:focus-visible {
outline: none;
}

/* Disable "sticky" footer when embedded */
div#fides-embed-container div#fides-modal .fides-modal-footer {
div#fides-embed-container div#fides-consent-content .fides-modal-footer {
position: inherit;
}

div#fides-embed-container .fides-modal-container,
div#fides-embed-container .fides-modal-overlay {
position: initial;
background-color: var(--fides-overlay-embed-background-color);
div#fides-embed-container .fides-modal-body {
padding-top: 1em;
}

div#fides-embed-container .fides-modal-content {
div#fides-embed-container div#fides-consent-content {
position: initial;
transform: none;
border: none;
max-height: none;
}
display: flex;

div#fides-embed-container .fides-close-button {
display: none;
font-family: var(--fides-overlay-font-family);
font-size: var(--fides-overlay-font-size-body);
color: var(--fides-overlay-body-font-color);
box-sizing: border-box;
background-color: var(--fides-overlay-background-color);
border-radius: var(--fides-overlay-container-border-radius);
width: var(--fides-overlay-width);

top: 50%;
left: 50%;

flex-direction: column;
padding: 0px;
overflow: hidden;
}

.fides-modal-container {
@@ -350,7 +355,11 @@ div#fides-modal .fides-modal-header {
justify-content: end;
}

div#fides-modal .fides-modal-title {
div#fides-consent-content {
overflow: scroll;
}

div#fides-consent-content .fides-modal-title {
text-align: center;
margin-top: 0.2em;
margin-bottom: 0.2em;
@@ -359,21 +368,21 @@ div#fides-modal .fides-modal-title {
color: var(--fides-overlay-title-font-color);
}

div#fides-modal .fides-modal-body {
div#fides-consent-content .fides-modal-body {
overflow-y: auto;
padding-inline: var(--fides-overlay-padding);
height: 100%;
scrollbar-gutter: stable;
}

div#fides-modal .fides-modal-footer {
div#fides-consent-content .fides-modal-footer {
display: flex;
flex-direction: column;
z-index: 5;
background-color: var(--fides-overlay-background-color);
}

div#fides-modal .fides-modal-description {
div#fides-consent-content .fides-modal-description {
margin: 1em 0 1em 0;
}

@@ -382,7 +391,7 @@ div#fides-modal .fides-modal-description {
gap: 10px;
}

div#fides-modal .fides-modal-button-group {
div#fides-consent-content .fides-modal-button-group {
display: flex;
width: 100%;
flex-direction: row;
@@ -392,11 +401,12 @@ div#fides-modal .fides-modal-button-group {

/* Responsive overlay */
@media (max-width: 48em) {
div.fides-modal-content {
width: 100%;
div.fides-modal-content,
div#fides-consent-content {
width: 100% !important;
}

div#fides-modal .fides-modal-button-group {
div#fides-consent-content .fides-modal-button-group {
flex-direction: column;
}

@@ -440,7 +450,7 @@ div#fides-banner-inner .fides-privacy-policy {
color: var(--fides-overlay-primary-color);
}

.fides-modal-content .fides-privacy-policy {
div#fides-consent-content .fides-privacy-policy {
display: block;
text-align: center;
margin-bottom: var(--fides-overlay-padding);
3 changes: 0 additions & 3 deletions clients/fides-js/src/lib/a11y-dialog.tsx
Original file line number Diff line number Diff line change
@@ -31,15 +31,13 @@ const useA11yDialogInstance = (addOverlowStyling: Boolean) => {

interface Props {
role: "dialog" | "alertdialog";
className: string;
id: string;
title: string;
useOverlowStyling: Boolean;
onClose?: () => void;
}
export const useA11yDialog = ({
role,
className,
id,
onClose,
useOverlowStyling,
@@ -72,7 +70,6 @@ export const useA11yDialog = ({
attributes: {
container: {
id,
className,
ref,
role,
tabIndex: -1,
4 changes: 2 additions & 2 deletions clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts
Original file line number Diff line number Diff line change
@@ -1144,7 +1144,7 @@ describe("Fides-js TCF", () => {
experience: experience.items[0],
});
});
cy.getByTestId("consent-modal").within(() => {
cy.getByTestId("consent-content").within(() => {
cy.getByTestId(`toggle-${PURPOSE_4.name}-consent`).click();
cy.get("#fides-tab-Features").click();
cy.getByTestId(`toggle-${SPECIAL_FEATURE_1.name}`).click();
@@ -1179,7 +1179,7 @@ describe("Fides-js TCF", () => {
});
});
// embed modal should not close on preferences save
cy.getByTestId("consent-modal").should("exist");
cy.getByTestId("consent-content").should("exist");
// Verify the cookie on save
cy.getCookie(CONSENT_COOKIE_NAME).then((cookie) => {
const cookieKeyConsent: FidesCookie = JSON.parse(