Skip to content

Commit

Permalink
BannerCallout: responsiveness fixes (#3891)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlbertCarreras authored Nov 25, 2024
1 parent f39b17b commit e09e310
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 79 deletions.
38 changes: 14 additions & 24 deletions packages/gestalt/src/BannerCallout/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ComponentProps, useCallback, useEffect, useRef, useState } from 'react';
import { ComponentProps, useRef } from 'react';
import useIsWrappedContainer from './useIsWrappedContainer';
import Box from '../Box';
import Button from '../Button';
import ButtonLink from '../ButtonLink';
Expand Down Expand Up @@ -114,43 +115,32 @@ type Props = {
checkWrapped?: boolean;
marginTop: 0 | 4 | 6;
buttonSize: 'md' | 'lg';
fullHeight?: boolean;
};

export default function Footer({
secondaryAction,
primaryAction,
fullHeight,
type,
checkWrapped = false,
marginTop,
buttonSize,
}: Props) {
const [isWrapped, setIsWrapped] = useState(false);
const wrappedRef = useRef<null | HTMLDivElement>(null);

const checkWrappedButton = useCallback(() => {
if (wrappedRef.current && !isWrapped && wrappedRef.current.offsetTop > 0) {
setIsWrapped(true);
} else if (wrappedRef.current && isWrapped && !(wrappedRef.current.offsetTop > 0)) {
setIsWrapped(false);
}
}, [isWrapped]);

useEffect(() => {
if (checkWrapped) {
checkWrappedButton();

if (typeof window !== 'undefined') window.addEventListener('resize', checkWrappedButton);
}

return () => {
if (checkWrapped && typeof window !== 'undefined')
window?.removeEventListener('resize', checkWrappedButton);
};
}, [checkWrappedButton, checkWrapped]);
const isWrapped = useIsWrappedContainer(wrappedRef, checkWrapped);

return (
<Box marginTop={marginTop} position="relative">
<Flex gap={2} height="100%" justifyContent="end" wrap>
<Box
alignContent="center"
display="flex"
height={fullHeight ? undefined : '100%'}
justifyContent="end"
marginTop={marginTop}
position="relative"
>
<Flex alignContent="center" gap={2} justifyContent="end" wrap>
{secondaryAction && (
<Flex.Item flex={isWrapped && checkWrapped ? 'grow' : undefined}>
<Action data={secondaryAction} level="secondary" size={buttonSize} type={type} />
Expand Down
41 changes: 21 additions & 20 deletions packages/gestalt/src/BannerCallout/HeaderSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ type Props = {
message: string | ReactElement;
type: 'default' | 'error' | 'info' | 'recommendation' | 'success' | 'warning';
title?: string;
marginBottom?: 4;
iconAccessibilityLabel?: string;
fullWidth?: boolean;
};

export default function HeaderSection({
Expand All @@ -24,7 +24,7 @@ export default function HeaderSection({
message,
type,
iconAccessibilityLabel,
marginBottom,
fullWidth,
}: Props) {
const {
iconAccessibilityLabelError,
Expand Down Expand Up @@ -52,30 +52,31 @@ export default function HeaderSection({
};

return (
<Box marginBottom={marginBottom}>
<Flex gap={gap}>
<Box width="100%">
<Flex gap={gap} width="100%">
<Icon
accessibilityLabel={iconAccessibilityLabel ?? getDefaultIconAccessibilityLabel()}
color={MESSAGING_TYPE_ATTRIBUTES[type]?.iconColor}
icon={MESSAGING_TYPE_ATTRIBUTES[type]?.icon}
size={iconSize}
/>

<Box maxWidth={648}>
{(title || message) && (
<Flex direction="column" gap={2} width="100%">
{title && <Heading size="400">{title}</Heading>}
{message && typeof message === 'string' && <Text>{message}</Text>}
{message &&
typeof message !== 'string' &&
// @ts-expect-error - TS2339
Children.only<ReactElement>(message).type.displayName === 'Text'
? message
: null}
</Flex>
)}
</Box>
</Flex>{' '}
<Flex.Item flex={fullWidth ? 'grow' : undefined}>
<Box maxWidth={648} width="100%">
{(title || message) && (
<Flex direction="column" gap={2} width="100%">
{title && <Heading size="400">{title}</Heading>}
{message && typeof message === 'string' && <Text>{message}</Text>}
{message &&
typeof message !== 'string' &&
// @ts-expect-error - TS2339
Children.only<ReactElement>(message).type.displayName === 'Text'
? message
: null}
</Flex>
)}
</Box>
</Flex.Item>
</Flex>
</Box>
);
}
74 changes: 39 additions & 35 deletions packages/gestalt/src/BannerCallout/VRBannerCallout.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { ComponentProps, ReactElement } from 'react';
import { ComponentProps, ReactElement, useRef } from 'react';
import {
SEMA_SPACE_800,
SEMA_SPACE_1200,
} from 'gestalt-design-tokens/dist/js/vr-theme/constants.es';
import DismissButton from './DismissButton';
import Footer from './Footer';
import HeaderSection from './HeaderSection';
import useIsWrappedContainer from './useIsWrappedContainer';
import Box from '../Box';
import Button from '../Button';
import ButtonLink from '../ButtonLink';
Expand Down Expand Up @@ -69,13 +70,15 @@ export default function BannerCallout({
title,
}: Props) {
const isRtl = typeof document === 'undefined' ? false : document?.dir === 'rtl';

const largePadding = isRtl
? { paddingRight: SEMA_SPACE_800, paddingLeft: SEMA_SPACE_1200 }
: { paddingRight: SEMA_SPACE_1200, paddingLeft: SEMA_SPACE_800 };

const backgroundColor = MESSAGING_TYPE_ATTRIBUTES[type]?.backgroundColor;

const wrappedRef = useRef<null | HTMLDivElement>(null);
const isWrapped = useIsWrappedContainer(wrappedRef, true);

return (
<Box width="100%">
{/*
Expand All @@ -98,7 +101,6 @@ export default function BannerCallout({
gap={3}
iconAccessibilityLabel={iconAccessibilityLabel}
iconSize={24}
marginBottom={primaryAction || secondaryAction ? 4 : undefined}
message={message}
title={title}
type={type}
Expand Down Expand Up @@ -135,16 +137,15 @@ export default function BannerCallout({
width="100%"
>
<Flex direction="column" width="100%">
<Flex.Item minWidth={0}>
<HeaderSection
gap={6}
iconAccessibilityLabel={iconAccessibilityLabel}
iconSize={32}
message={message}
title={title}
type={type}
/>
</Flex.Item>
<HeaderSection
fullWidth
gap={6}
iconAccessibilityLabel={iconAccessibilityLabel}
iconSize={32}
message={message}
title={title}
type={type}
/>

{(primaryAction || secondaryAction) && (
<Flex.Item flex="grow">
Expand Down Expand Up @@ -176,32 +177,35 @@ export default function BannerCallout({
smDisplay="none"
width="100%"
>
<Flex alignItems="center" width="100%" wrap>
<Flex.Item minWidth={0}>
<HeaderSection
gap={6}
iconAccessibilityLabel={iconAccessibilityLabel}
iconSize={32}
message={message}
title={title}
type={type}
/>
</Flex.Item>

{(primaryAction || secondaryAction) && (
<Flex.Item flex="grow">
<Footer
buttonSize="lg"
marginTop={0}
primaryAction={primaryAction}
secondaryAction={secondaryAction}
<Box position="relative">
<Flex height="100%" width="100%" wrap>
<Flex.Item flex={isWrapped ? 'grow' : undefined} minWidth={isWrapped ? undefined : 0}>
<HeaderSection
fullWidth={isWrapped}
gap={6}
iconAccessibilityLabel={iconAccessibilityLabel}
iconSize={32}
message={message}
title={title}
type={type}
/>
</Flex.Item>
)}

{dismissButton && <DismissButton dismissButton={dismissButton} />}
</Flex>
{(primaryAction || secondaryAction) && (
<Flex.Item ref={wrappedRef} flex="grow">
<Footer
buttonSize="lg"
fullHeight={isWrapped}
marginTop={isWrapped ? 6 : 0}
primaryAction={primaryAction}
secondaryAction={secondaryAction}
type={type}
/>
</Flex.Item>
)}
</Flex>
</Box>
{dismissButton && <DismissButton dismissButton={dismissButton} />}
</Box>
</Box>
);
Expand Down
33 changes: 33 additions & 0 deletions packages/gestalt/src/BannerCallout/useIsWrappedContainer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useCallback, useEffect, useState } from 'react';

const useIsWrappedContainer = (
wrappedRef: React.MutableRefObject<HTMLDivElement | null>,
checkWrapped: boolean,
) => {
const [isWrapped, setIsWrapped] = useState(false);

const checkWrappedButton = useCallback(() => {
if (wrappedRef.current && !isWrapped && wrappedRef.current.offsetTop > 0) {
setIsWrapped(true);
} else if (wrappedRef.current && isWrapped && !(wrappedRef.current.offsetTop > 0)) {
setIsWrapped(false);
}
}, [isWrapped, wrappedRef]);

useEffect(() => {
if (checkWrapped) {
checkWrappedButton();

if (typeof window !== 'undefined') window.addEventListener('resize', checkWrappedButton);
}

return () => {
if (checkWrapped && typeof window !== 'undefined')
window?.removeEventListener('resize', checkWrappedButton);
};
}, [checkWrappedButton, checkWrapped]);

return isWrapped;
};

export default useIsWrappedContainer;

0 comments on commit e09e310

Please sign in to comment.