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

feat: add alert ds component #1781

Merged
merged 3 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
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
141 changes: 141 additions & 0 deletions src/blocks/alert/Alert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import type { FC } from 'react';
import styled, { FlattenSimpleInterpolation } from 'styled-components';

import type { TransformedHTMLAttributes } from '../Blocks.types';
import type { AlertVariant } from './Alert.types';
import { alertVariants } from './Alert.utils';
import { Cross } from 'blocks/icons';
import { HoverableSVG } from 'blocks/hoverableSVG';
import { getTextVariantStyles } from 'blocks/Blocks.utils';

export type AlertProps = {
/* Additional prop from styled components to apply custom css to Alert */
css?: FlattenSimpleInterpolation;
/* Sets the variant of the alert */
variant: AlertVariant;
/* Close function to be called on close button click */
onClose?: () => void;
/* Retry function to be called on action button click */
onAction?: () => void;
/* Text to be displayed on the action button */
actionText?: string;
/* Boolean to set the visibility of the icon */
showIcon?: boolean;
/* Header text for the alert */
heading?: string;
/* Description text for the alert */
description?: string;
} & TransformedHTMLAttributes<HTMLDivElement>;

const StyledAlert = styled.div<AlertProps>`
/* Common Alert CSS */

display: flex;
font-family: var(--font-family);
border-radius: var(--radius-sm);
justify-content: center;
white-space: nowrap;
padding: var(--spacing-xs);
justify-content: space-between;
${({ variant }) => `
border: var(--border-sm) solid var(--${alertVariants[variant].borderColor});
background-color: var(--${alertVariants[variant].bgColor});
`}

/* Common icon css added through CSS class */
.icon {
display: flex;
justify-content: center;
margin-right: var(--spacing-xxxs);
color: var(--${({ variant }) => alertVariants[variant].iconColor});
}

/* Custom CSS applied via styled component css prop */
${(props) => props.css || ''}
`;

const StyledLink = styled.div<{ variant: AlertVariant }>`
/* Link CSS */
text-decoration: none;
cursor: pointer;
color: var(--${({ variant }) => alertVariants[variant].ctaColor});
`;

const TextContainer = styled.div`
display: flex;
flex-direction: column;
align-items: flex-start;
gap: var(--spacing-xxxs);
flex: 1 0 0;
`;

const RightContainer = styled.div`
display: flex;
gap: var(--spacing-xs, 12px);
align-items: center;
height: 24px;
`;

const Heading = styled.p`
${() => getTextVariantStyles('h5-semibold', 'components-alert-text-default')}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add font sizes , weight, style and line height for the texts

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check the implementation of the getTextVariantStyles, it will appropriately add the required styles to the text.

`;

const Description = styled.p`
${() => getTextVariantStyles('bs-regular', 'components-alert-text-body')}
`;

const Alert: FC<AlertProps> = ({
description,
heading,
onClose,
onAction,
actionText = 'Try Again',
showIcon = true,
variant = 'info',
...props
}) => {
const { icon: Icon } = alertVariants[variant];

return (
<StyledAlert
role="alert"
{...{ variant }}
{...props}
>
{showIcon && (
<span className="icon">
<Icon size={24} />
</span>
)}
<TextContainer>
{heading && <Heading>{heading}</Heading>}
{description && <Description>{description}</Description>}
</TextContainer>
<RightContainer>
{onAction && (
<StyledLink
variant={variant}
onClick={onAction}
>
{actionText}
</StyledLink>
)}
{onClose && (
<HoverableSVG
icon={
<Cross
size={24}
color="icon-primary"
/>
}
onClick={onClose}
/>
)}
</RightContainer>
</StyledAlert>
);
};

Alert.displayName = 'Alert';

export { Alert };
1 change: 1 addition & 0 deletions src/blocks/alert/Alert.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type AlertVariant = 'success' | 'warning' | 'error' | 'info';
38 changes: 38 additions & 0 deletions src/blocks/alert/Alert.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { AlertVariant } from './Alert.types';
import { IconProps, InfoFilled, TickCircleFilled, WarningCircleFilled } from '../icons';
import { ThemeColors } from 'blocks/theme/Theme.types';
import { FC } from 'react';

export const alertVariants: Record<
AlertVariant,
{ icon: FC<IconProps>; iconColor: ThemeColors; borderColor: ThemeColors; bgColor: ThemeColors; ctaColor: ThemeColors }
> = {
success: {
icon: TickCircleFilled,
iconColor: 'components-alert-icon-success',
borderColor: 'components-alert-stroke-success',
bgColor: 'components-alert-background-success',
ctaColor: 'components-alert-text-cta-success',
},
warning: {
icon: WarningCircleFilled,
iconColor: 'components-alert-icon-warning',
borderColor: 'components-alert-stroke-warning',
bgColor: 'components-alert-background-warning',
ctaColor: 'components-alert-text-cta-warning',
Comment on lines +11 to +22
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check text area component for the color implementation for different variants. This constant isnt needed, it can be done in a much optimised way

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is similar to how we have implemented alertModalIcon in the AlertModal.

},
info: {
icon: InfoFilled,
iconColor: 'components-alert-icon-info',
borderColor: 'components-alert-stroke-info',
bgColor: 'components-alert-background-info',
ctaColor: 'components-alert-text-cta-info',
},
error: {
icon: WarningCircleFilled,
iconColor: 'components-alert-icon-error',
borderColor: 'components-alert-stroke-error',
bgColor: 'components-alert-background-error',
ctaColor: 'components-alert-text-cta-error',
},
};
3 changes: 3 additions & 0 deletions src/blocks/alert/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './Alert';
export * from './Alert.utils';
export * from './Alert.types';
1 change: 1 addition & 0 deletions src/blocks/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { Alert, type AlertProps } from './alert';
export { Box, type BoxProps } from './box';
export { Button, type ButtonProps } from './button';
export { Dropdown, type DropdownProps } from './dropdown';
Expand Down
4 changes: 4 additions & 0 deletions src/blocks/theme/colors/colors.semantics.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { alertSemantics } from '../semantics/semantics.alert';
import {
secondaryButtonSemantics,
dangerButtonSemantics,
Expand All @@ -23,6 +24,7 @@ import { tooltipSemantics } from '../semantics/semantics.tooltip';

// TODO: find a better way to do this in future
type SemanticKeys = {
alert: 'components-alert';
buttonPrimary: 'components-button-primary';
buttonSecondary: 'components-button-secondary';
buttonTertiary: 'components-button-tertiary';
Expand All @@ -46,6 +48,7 @@ type SemanticKeys = {
};

export const semanticKeys: SemanticKeys = {
alert: 'components-alert',
buttonPrimary: 'components-button-primary',
buttonSecondary: 'components-button-secondary',
buttonTertiary: 'components-button-tertiary',
Expand All @@ -69,6 +72,7 @@ export const semanticKeys: SemanticKeys = {
};

export const colorSemantics = {
[semanticKeys.alert]: alertSemantics,
[semanticKeys.buttonPrimary]: primaryButtonSemantics,
[semanticKeys.buttonSecondary]: secondaryButtonSemantics,
[semanticKeys.buttonTertiary]: tertiaryButtonSemantics,
Expand Down
24 changes: 24 additions & 0 deletions src/blocks/theme/semantics/semantics.alert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { colorBrands } from '../colors/colors.brands';
import { colorPrimitives } from '../colors/colors.primitives';
import { textSemantics } from './semantics.text';

export const alertSemantics = {
'text-default': { light: textSemantics['primary'].light, dark: textSemantics['primary'].dark },
'text-body': { light: textSemantics['tertiary'].light, dark: textSemantics['tertiary'].dark },
'icon-success': { light: colorBrands['success-500'], dark: colorBrands['success-300'] },
'icon-warning': { light: colorBrands['warning-700'], dark: colorBrands['warning-100'] },
'icon-error': { light: colorBrands['danger-600'], dark: colorBrands['danger-500'] },
'icon-info': { light: colorPrimitives['blue-700'], dark: colorPrimitives['blue-100'] },
'text-cta-success': { light: colorBrands['success-500'], dark: colorBrands['success-300'] },
'text-cta-warning': { light: colorBrands['warning-700'], dark: colorBrands['warning-100'] },
'text-cta-error': { light: colorBrands['danger-600'], dark: colorBrands['danger-500'] },
'text-cta-info': { light: colorPrimitives['blue-700'], dark: colorPrimitives['blue-100'] },
'background-success': { light: colorBrands['success-100'], dark: colorBrands['success-900'] },
'background-warning': { light: colorBrands['warning-100'], dark: colorBrands['warning-900'] },
'background-error': { light: colorBrands['danger-100'], dark: colorBrands['danger-900'] },
'background-info': { light: colorPrimitives['blue-100'], dark: colorPrimitives['blue-900'] },
'stroke-success': { light: colorBrands['success-300'], dark: colorBrands['success-700'] },
'stroke-warning': { light: colorBrands['warning-300'], dark: colorBrands['warning-700'] },
'stroke-error': { light: colorBrands['danger-300'], dark: colorBrands['danger-700'] },
'stroke-info': { light: colorPrimitives['blue-300'], dark: colorPrimitives['blue-700'] },
};
Loading