diff --git a/docs/examples/bannercallout/main.tsx b/docs/examples/bannercallout/main.tsx index 00bc3fc553..074c154b44 100644 --- a/docs/examples/bannercallout/main.tsx +++ b/docs/examples/bannercallout/main.tsx @@ -4,7 +4,7 @@ import { BannerCallout, Box, Flex } from 'gestalt'; export default function ResponsiveExample() { return ( - + + {}, + }} + message="Inspiration to build the life you love." + primaryAction={{ + accessibilityLabel: 'Log in', + href: 'https://pinterest.com', + label: 'Sign up', + target: 'blank', + role: 'link', + }} + secondaryAction={{ + accessibilityLabel: 'Log in', + href: 'https://pinterest.com', + label: 'Log in', + target: 'blank', + role: 'link', + }} + title="Pinterest is the place for inspiration" + type="default" + /> + + ); +} diff --git a/docs/pages/web/bannercallout.tsx b/docs/pages/web/bannercallout.tsx index 5d884d10bb..99998cbad9 100644 --- a/docs/pages/web/bannercallout.tsx +++ b/docs/pages/web/bannercallout.tsx @@ -16,6 +16,7 @@ import localizationLabels from '../../examples/bannercallout/localizationLabels' import main from '../../examples/bannercallout/main'; import placeAtTop from '../../examples/bannercallout/placeAtTop'; import productMessages from '../../examples/bannercallout/productMessages'; +import variantDefault from '../../examples/bannercallout/variantDefault'; import variantError from '../../examples/bannercallout/variantError'; import variantInfo from '../../examples/bannercallout/variantInfo'; import variantMessage from '../../examples/bannercallout/variantMessage'; @@ -146,7 +147,6 @@ export default function DocsPage({ generatedDocGen }: { generatedDocGen: DocGen code={accessibilityExample} layout="column" name="BannerCallout labels" - // hideEditor /> } /> @@ -160,6 +160,15 @@ export default function DocsPage({ generatedDocGen }: { generatedDocGen: DocGen /> + + + } + /> + + + } /> @@ -188,7 +192,6 @@ export default function DocsPage({ generatedDocGen }: { generatedDocGen: DocGen code={variantRecommendation} layout="column" name="Variants - Recommendation" - // hideEditor /> } /> @@ -200,12 +203,7 @@ export default function DocsPage({ generatedDocGen }: { generatedDocGen: DocGen + } /> @@ -221,7 +219,6 @@ export default function DocsPage({ generatedDocGen }: { generatedDocGen: DocGen code={variantWarning} layout="column" name="Variants - Warning" - // hideEditor previewHeight={460} /> } @@ -239,7 +236,6 @@ export default function DocsPage({ generatedDocGen }: { generatedDocGen: DocGen code={variantError} layout="column" name="Variants - Error" - // hideEditor previewHeight={380} /> } @@ -262,12 +258,7 @@ export default function DocsPage({ generatedDocGen }: { generatedDocGen: DocGen + } /> @@ -289,7 +280,6 @@ export default function DocsPage({ generatedDocGen }: { generatedDocGen: DocGen code={dismissibleExample} layout="column" name="Dismissable BannerCallout" - // hideEditor /> } /> diff --git a/packages/gestalt/src/BannerCallout.css b/packages/gestalt/src/BannerCallout.css index 9c25f7e1d7..c03130ba39 100644 --- a/packages/gestalt/src/BannerCallout.css +++ b/packages/gestalt/src/BannerCallout.css @@ -1,11 +1,33 @@ +.dismissButton { + position: absolute; +} + html[dir="rtl"] .rtlPos { left: 0; - position: absolute; top: 0; } html:not([dir="rtl"]) .rtlPos { - position: absolute; right: 0; top: 0; } + +html[dir="rtl"] .smRtlVRPos { + left: var(--sema-space-300); + top: var(--sema-space-500); +} + +html:not([dir="rtl"]) .smRtlVRPos { + right: var(--sema-space-300); + top: var(--sema-space-500); +} + +html[dir="rtl"] .lgRtlVRPos { + left: var(--sema-space-400); + top: var(--sema-space-400); +} + +html:not([dir="rtl"]) .lgRtlVRPos { + right: var(--sema-space-400); + top: var(--sema-space-400); +} diff --git a/packages/gestalt/src/BannerCallout.tsx b/packages/gestalt/src/BannerCallout.tsx index 6b0d803598..100ef2a969 100644 --- a/packages/gestalt/src/BannerCallout.tsx +++ b/packages/gestalt/src/BannerCallout.tsx @@ -1,6 +1,7 @@ import { Children, ComponentProps, ReactElement } from 'react'; import classnames from 'classnames'; import styles from './BannerCallout.css'; +import VRBannerCallout from './BannerCallout/VRBannerCallout'; import Box from './Box'; import Button from './Button'; import ButtonLink from './ButtonLink'; @@ -9,6 +10,7 @@ import Icon from './Icon'; import IconButton from './IconButton'; import MESSAGING_TYPE_ATTRIBUTES from './MESSAGING_TYPE_ATTRIBUTES'; import Text from './Text'; +import useInExperiment from './useInExperiment'; import useResponsiveMinWidth from './useResponsiveMinWidth'; export type ActionDataType = @@ -98,7 +100,7 @@ type Props = { /** * The category of BannerCallout. See [Variants](https://gestalt.pinterest.systems/web/bannercallout#Variants) to learn more. */ - type: 'error' | 'info' | 'recommendation' | 'success' | 'warning'; + type: 'default' | 'error' | 'info' | 'recommendation' | 'success' | 'warning'; /** * Brief title summarizing BannerCallout. Content should be [localized](https://gestalt.pinterest.systems/web/bannercallout#Localization). */ @@ -108,13 +110,24 @@ type Props = { function BannerCalloutAction({ data, stacked, + level, type, }: { data: ActionDataType; stacked?: boolean; - type: string; + level: string; + type: 'default' | 'error' | 'info' | 'recommendation' | 'success' | 'warning'; }) { - const color = type === 'primary' ? 'white' : 'transparent'; + const primaryColor: ComponentProps['color'] = 'white'; + + let secondaryColor: 'white' | 'transparent' | 'gray' = 'transparent'; + + if (type === 'default') { + secondaryColor = 'gray'; + } + + const color: ComponentProps['color'] = + level === 'primary' ? primaryColor : secondaryColor; const { accessibilityLabel, disabled, label } = data; @@ -123,7 +136,7 @@ function BannerCalloutAction({ alignItems="center" display="block" justifyContent="center" - marginTop={type === 'secondary' && stacked ? 2 : undefined} + marginTop={level === 'secondary' && stacked ? 2 : undefined} paddingX={1} smDisplay="flex" smMarginBottom="auto" @@ -183,6 +196,11 @@ export default function BannerCallout({ iconAccessibilityLabelWarning, } = useDefaultLabelContext('BannerCallout'); + const isInVRExperiment = useInExperiment({ + webExperimentName: 'web_gestalt_visualRefresh', + mwebExperimentName: 'web_gestalt_visualRefresh', + }); + const getDefaultIconAccessibilityLabel = () => { switch (type) { case 'success': @@ -200,13 +218,28 @@ export default function BannerCallout({ } }; + if (isInVRExperiment) { + return ( + + ); + } + return ( @@ -253,9 +284,9 @@ export default function BannerCallout({ )} - {typeof message === 'string' ? ( + {typeof message === 'string' && ( {message} - ) : null} + )} {typeof message !== 'string' && // @ts-expect-error - TS2339 Children.only(message).type.displayName === 'Text' @@ -267,21 +298,24 @@ export default function BannerCallout({ {(primaryAction || secondaryAction) && ( {secondaryAction && responsiveMinWidth !== 'xs' && ( - + + )} + {primaryAction && ( + )} - {primaryAction && } {secondaryAction && responsiveMinWidth === 'xs' && ( )} )} {dismissButton && ( -
+
void; + }; +}; + +export default function DismissButton({ dismissButton, size = 'lg' }: Props) { + const { accessibilityDismissButtonLabel } = useDefaultLabelContext('BannerCallout'); + + return ( +
+ +
+ ); +} diff --git a/packages/gestalt/src/BannerCallout/Footer.tsx b/packages/gestalt/src/BannerCallout/Footer.tsx new file mode 100644 index 0000000000..c1470dd868 --- /dev/null +++ b/packages/gestalt/src/BannerCallout/Footer.tsx @@ -0,0 +1,169 @@ +import { ComponentProps, useCallback, useEffect, useRef, useState } from 'react'; +import Box from '../Box'; +import Button from '../Button'; +import ButtonLink from '../ButtonLink'; +import Flex from '../Flex'; + +type ActionDataType = + | { + accessibilityLabel: string; + disabled?: boolean; + href: string; + label: string; + onClick?: ComponentProps['onClick']; + rel?: 'none' | 'nofollow'; + role: 'link'; + target?: null | 'self' | 'blank'; + } + | { + accessibilityLabel: string; + disabled?: boolean; + label: string; + onClick?: ComponentProps['onClick']; + role?: 'button'; + }; + +function Action({ + data, + level, + type, + size = 'lg', +}: { + data: ActionDataType; + level: string; + size?: 'md' | 'lg'; + type: 'default' | 'error' | 'info' | 'recommendation' | 'success' | 'warning'; +}) { + const primaryColor: ComponentProps['color'] = 'red'; + + let secondaryColor: 'white' | 'transparent' | 'gray' = 'white'; + + if (type === 'default') { + secondaryColor = 'gray'; + } + + const color: ComponentProps['color'] = + level === 'primary' ? primaryColor : secondaryColor; + + const { accessibilityLabel, disabled, label } = data; + + return data.role === 'link' ? ( + + ) : ( +