diff --git a/packages/gestalt/src/BannerUpsell.tsx b/packages/gestalt/src/BannerUpsell.tsx
index cdfee6ab32..8fda59a254 100644
--- a/packages/gestalt/src/BannerUpsell.tsx
+++ b/packages/gestalt/src/BannerUpsell.tsx
@@ -1,6 +1,7 @@
import { Children, ComponentProps, ReactElement, ReactNode } from 'react';
import classnames from 'classnames';
import styles from './BannerUpsell.css';
+import VRBannerUpsell from './BannerUpsell/VRBannerUpsell';
import BannerUpsellForm from './BannerUpsellForm';
import Box from './Box';
import Button from './Button';
@@ -11,6 +12,7 @@ import IconButton from './IconButton';
import Image from './Image';
import Mask from './Mask';
import Text from './Text';
+import useInExperiment from './useInExperiment';
import useResponsiveMinWidth from './useResponsiveMinWidth';
export type ActionDataType =
@@ -148,7 +150,10 @@ export default function BannerUpsell({
const hasActions = Boolean(primaryAction || secondaryAction);
const { colorSchemeName } = useColorScheme();
const isDarkMode = colorSchemeName === 'darkMode';
-
+ const isInVRExperiment = useInExperiment({
+ webExperimentName: 'web_gestalt_visualrefresh',
+ mwebExperimentName: 'web_gestalt_visualrefresh',
+ });
let messageElement: ReactNode;
if (typeof message === 'string') {
@@ -177,6 +182,20 @@ export default function BannerUpsell({
);
}
+ if (isInVRExperiment) {
+ return (
+
+ {children}
+
+ );
+ }
return (
['onClick'];
+ rel?: 'none' | 'nofollow';
+ role: 'link';
+ target?: null | 'self' | 'blank';
+ }
+ | {
+ accessibilityLabel: string;
+ disabled?: boolean;
+ label: string;
+ onClick: ComponentProps['onClick'];
+ role?: 'button';
+ };
+
+type UpsellActionProps = {
+ data: ActionDataType;
+ stacked?: boolean;
+ type: string;
+ size?: string;
+};
+
+function UpsellAction({ data, stacked, type, size }: UpsellActionProps) {
+ const color = type === 'primary' ? 'red' : 'gray';
+ const { accessibilityLabel, disabled, label } = data;
+
+ return (
+
+ {data.role === 'link' ? (
+
+ ) : (
+
+ )}
+
+ );
+}
+
+type Props = {
+ /**
+ * To create forms within BannerUpsell, pass BannerUpsell.Form as children.
+ */
+ children?: ReactNode;
+ /**
+ * Adds a dismiss button to the BannerUpsell. The \`accessibilityLabel\` should follow the [Accessibility guidelines](https://gestalt.pinterest.systems/web/bannerupsell#Accessibility).
+ */
+ dismissButton?: {
+ accessibilityLabel?: string;
+ onDismiss: () => void;
+ };
+ /**
+ * Either an [Icon](https://gestalt.pinterest.systems/web/icon) or an [Image](https://gestalt.pinterest.systems/web/image) to render at the start of the banner. Width is not used with Icon. Image width defaults to 128px. See the [Icon](https://gestalt.pinterest.systems/web/bannerupsell#Icon) and [Image](https://gestalt.pinterest.systems/web/bannerupsell#Image) variants for more info.
+ */
+ imageData?: {
+ component: ReactElement;
+ mask?: {
+ rounding?: 'circle' | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
+ wash?: boolean;
+ };
+ width?: number;
+ };
+ /**
+ * Main content of BannerUpsell, explains what is being offered or recommended. Content should be [localized](https://gestalt.pinterest.systems/web/bannerupsell#Localization). See the [Message variant](https://gestalt.pinterest.systems/web/bannerupsell#Message) to learn more.
+ */
+ message: string | ReactElement;
+ /**
+ * Main action for people to take on BannerUpsell. If \`href\` is supplied, the action will serve as a link. See [GlobalEventsHandlerProvider](https://gestalt.pinterest.systems/web/utilities/globaleventshandlerprovider#Link-handlers) to learn more about link navigation.'
+ * If no \`href\` is supplied, the action will be a button.
+ * The \`accessibilityLabel\` should follow the [Accessibility guidelines](https://gestalt.pinterest.systems/web/bannerupsell#Accessibility).
+ */
+ primaryAction?: ActionDataType;
+ /**
+ * Secondary action for people to take on BannerUpsell. If \`href\` is supplied, the action will serve as a link. See [GlobalEventsHandlerProvider](https://gestalt.pinterest.systems/web/utilities/globaleventshandlerprovider#Link-handlers) to learn more about link navigation.'
+ * If no \`href\` is supplied, the action will be a button.
+ * The \`accessibilityLabel\` should follow the [Accessibility guidelines](https://gestalt.pinterest.systems/web/bannerupsell#Accessibility).
+ */
+ secondaryAction?: ActionDataType;
+ /**
+ * Brief title summarizing the BannerUpsell. Content should be [localized](https://gestalt.pinterest.systems/web/bannerupsell#Localization).
+ */
+ title?: string;
+};
+
+/**
+ * [BannerUpsells](https://gestalt.pinterest.systems/web/bannerupsell) are banners that display short messages that focus on promoting an action or upgrading something the user already has.
+ *
+ *
+ * ![BannerUpsell light mode](https://raw.githubusercontent.com/pinterest/gestalt/master/playwright/visual-test/BannerUpsell.spec.ts-snapshots/BannerUpsell-chromium-darwin.png)
+ * ![BannerUpsell dark mode](https://raw.githubusercontent.com/pinterest/gestalt/master/playwright/visual-test/BannerUpsell-dark.spec.ts-snapshots/BannerUpsell-dark-chromium-darwin.png)
+ */
+export default function BannerUpsell({
+ children,
+ dismissButton,
+ imageData,
+ message,
+ primaryAction,
+ secondaryAction,
+ title,
+}: Props) {
+ const isImage = imageData?.component && imageData.component.type === Image;
+ const responsiveMinWidth = useResponsiveMinWidth();
+ const { accessibilityDismissButtonLabel } = useDefaultLabelContext('BannerUpsell');
+ const hasActions = Boolean(primaryAction || secondaryAction);
+ const { colorSchemeName } = useColorScheme();
+ const isDarkMode = colorSchemeName === 'darkMode';
+
+ let messageElement: ReactNode;
+
+ if (typeof message === 'string') {
+ messageElement = (
+ {message}
+ );
+ }
+ // If `text` is a Text component, we need to override any text colors within to ensure they all match
+ if (
+ typeof message !== 'string' &&
+ // @ts-expect-error - TS2339
+ Children.only(message).type.displayName === 'Text'
+ ) {
+ const textColorOverrideStyles = isDarkMode
+ ? styles.textColorOverrideDark
+ : styles.textColorOverrideLight;
+
+ const textAligmentOverrideStyles =
+ responsiveMinWidth === 'xs'
+ ? styles.textAligmentOverrideCenter
+ : styles.textAligmentOverrideStart;
+
+ messageElement = (
+
+ {message}
+
+ );
+ }
+
+ return (
+
+ {/*
+ SM BREAKPOINT
+ */}
+
+
+
+
+ {title && (
+
+ {imageData && (
+
+
+ {imageData.component}
+
+
+ {title}
+
+
+ )}
+
+ )}
+ {messageElement}
+
+ {children && (
+
+ {children}
+
+ )}
+
+ {!children && hasActions && (
+
+ {secondaryAction && responsiveMinWidth !== 'xs' && (
+
+ )}
+ {primaryAction && }
+ {secondaryAction && responsiveMinWidth === 'xs' && (
+
+ )}
+
+ )}
+
+
+
+ {/*
+ MD BREAKPOINT
+ */}
+
+
+ {imageData && (
+
+
+ {imageData.component}
+
+
+ )}
+
+
+ {title && (
+
+
+ {title}
+
+
+ )}
+
+ {messageElement}
+
+ {children && (
+
+ {children}
+
+ )}
+
+
+ {!children && hasActions && (
+
+ {secondaryAction && responsiveMinWidth !== 'xs' && (
+
+ )}
+ {primaryAction && }
+ {secondaryAction && responsiveMinWidth === 'xs' && (
+
+ )}
+
+ )}
+
+
+ {/*
+ LG BREAKPOINT
+ */}
+
+
+ {imageData && (
+
+
+ {imageData.component}
+
+
+ )}
+
+
+ {title && (
+
+
+ {title}
+
+
+ )}
+
+ {messageElement}
+
+ {children && (
+
+ {children}
+
+ )}
+
+ {!children && hasActions && (
+
+ {secondaryAction && responsiveMinWidth !== 'xs' && (
+
+ )}
+ {primaryAction && }
+ {secondaryAction && responsiveMinWidth === 'xs' && (
+
+ )}
+
+ )}
+
+
+
+ {dismissButton && (
+
+
+
+ )}
+
+ );
+}
+
+BannerUpsell.Form = BannerUpsellForm;
+
+BannerUpsell.displayName = 'BannerUpsell';