Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | 520x 1x 1x 372x 372x 1x 1x 478x 478x | import { IconName } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { ReactElement, ReactNode } from "react";
import styled from "styled-components";
import { RaisedCard } from "client/components/RaisedCard";
import {
HighlightStyle,
getHighlightColor,
} from "client/components/componentStyles";
interface Props {
children: ReactNode;
onDismiss: () => void;
dismissAriaLabel: string;
icon: IconName;
highlightStyle: HighlightStyle;
"data-testid"?: string;
}
// Shared shell for app-level notification banners: a leading icon, the
// message, and a dismiss button on the right. Built on the same highlighted
// card the app uses for its other notices so the banners read as part of the
// same system. Stickiness comes from the wrapper the app-level bars render in
export const DismissibleBanner = ({
children,
onDismiss,
dismissAriaLabel,
icon,
highlightStyle,
"data-testid": dataTestId,
}: Props): ReactElement => {
return (
<Banner
isHighlighted={true}
highlightStyle={highlightStyle}
data-testid={dataTestId}
>
<BannerIcon
icon={icon}
$highlightStyle={highlightStyle}
aria-hidden={true}
/>
<Content>{children}</Content>
<CloseButton
type="button"
onClick={onDismiss}
aria-label={dismissAriaLabel}
>
<FontAwesomeIcon icon="xmark" />
</CloseButton>
</Banner>
);
};
const Banner = styled(RaisedCard)`
display: flex;
align-items: center;
gap: 12px;
/* Same box metrics as the other app-level bars so their dismiss icons
line up when several are stacked */
margin: 4px 0;
padding: 10px;
`;
const BannerIcon = styled(FontAwesomeIcon)<{
$highlightStyle: HighlightStyle;
}>`
flex-shrink: 0;
font-size: ${(props) => props.theme.iconSizeNormal};
color: ${(props) => getHighlightColor(props.theme, props.$highlightStyle)};
`;
// Lays out the message and any action the banner offers, wrapping onto a
// second row on narrow screens instead of squeezing the text
const Content = styled.div`
display: flex;
flex: 1;
flex-wrap: wrap;
gap: 8px;
align-items: center;
justify-content: space-between;
`;
const CloseButton = styled.button`
flex-shrink: 0;
/* Centers the glyph in the button box: as inline content it would sit off
centre by the font's descender, which shows next to a taller message */
display: flex;
align-items: center;
border: none;
background: none;
padding: 0;
font-size: 18px;
cursor: pointer;
color: ${(props) => props.theme.textLighter};
&:hover,
&:focus {
color: ${(props) => props.theme.textMain};
}
`;
|