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(components): theme alert #99

Merged
merged 1 commit into from
May 16, 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
50 changes: 47 additions & 3 deletions packages/components/src/Alert/Alert.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,64 @@ export default {
export const Success: StoryObj<AlertProps> = {
args: {
status: 'success',
children: 'Transaction was succesful!'
children: 'Transaction was succesful!',
onClose: undefined
}
};

export const Info: StoryObj<AlertProps> = {
args: {
status: 'info',
children: 'This is some useful information!',
onClose: undefined
}
};

export const Warning: StoryObj<AlertProps> = {
args: {
status: 'warning',
children: 'This is a warning message...'
children: 'This is a warning message...',
onClose: undefined
}
};

export const Error: StoryObj<AlertProps> = {
args: {
status: 'error',
children: 'Error happened, please contact our support.'
children: 'Error happened, please contact our support.',
onClose: undefined
}
};

export const Outlined: StoryObj<AlertProps> = {
args: {
variant: 'outlined',
children: 'Transaction was succesful!',
onClose: undefined
}
};

export const Filled: StoryObj<AlertProps> = {
args: {
variant: 'filled',
children: 'Transaction was succesful!',
onClose: undefined
}
};

export const WithTitle: StoryObj<AlertProps> = {
args: {
status: 'success',
title: 'This is a successful alert',
children: 'Transaction was succesful!',
onClose: undefined
}
};

export const Closable: StoryObj<AlertProps> = {
args: {
status: 'success',
children: 'Transaction was succesful!',
onClose: () => {}
}
};
86 changes: 73 additions & 13 deletions packages/components/src/Alert/Alert.style.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,98 @@
import { CheckCircle, InformationCircle, Warning } from '@interlay/icons';
import { CheckCircle, ExclamationCircle, InformationCircle, Warning } from '@interlay/icons';
import { AlertStatus, AlertVariant, Rounded } from '@interlay/theme';
import styled, { css } from 'styled-components';
import { AlertStatus } from '@interlay/theme';

import { Button } from '../Button';
import { Flex } from '../Flex';

type StyledAlertProps = {
$status: AlertStatus;
$variant: AlertVariant;
$rounded?: Rounded;
};

// FIXME: waiting on JAy
const StyledAlert = styled(Flex)<StyledAlertProps>`
${({ $status, theme }) => css`
${({ $status, $variant, $rounded, theme }) => css`
${theme.alert.base}
${theme.alert.status[$status]}
${theme.alert.status[$status][$variant].base}
border-radius: ${$rounded && theme.rounded($rounded)};
`}
`;

const StyledAlertTitle = styled.div<StyledAlertProps>`
${({ $status, $variant, theme }) => css`
${theme.alert.title}
${theme.alert.status[$status][$variant].title}
`}
`;

const StyledInformationCircle = styled(InformationCircle)<StyledAlertProps>`
${({ $status, theme }) => css`
${theme.alert.status[$status]}
${({ $status, $variant, theme }) => css`
${theme.alert.status[$status][$variant].icon}
`}
`;

const StyledCheckCircle = styled(CheckCircle)<StyledAlertProps>`
${({ $status, theme }) => css`
${theme.alert.base}
${theme.alert.status[$status]}
${({ $status, $variant, theme }) => css`
${theme.alert.status[$status][$variant].icon}
`}
`;

const StyledWarning = styled(Warning)<StyledAlertProps>`
${({ $status, theme }) => css`
${theme.alert.status[$status].color}
${({ $status, $variant, theme }) => css`
${theme.alert.status[$status][$variant].icon}
`}
`;

const StyledExclamationCircle = styled(ExclamationCircle)<StyledAlertProps>`
${({ $status, $variant, theme }) => css`
${theme.alert.status[$status][$variant].icon}
`}
`;

const StyledIconWrapper = styled.div`
display: flex;

${({ theme }) => css`
${theme.alert.icon}
`}
`;

export { StyledAlert, StyledInformationCircle, StyledCheckCircle, StyledWarning };
const StyledContent = styled.div`
min-width: 0px;
overflow: auto;

${({ theme }) => css`
${theme.alert.content}
`}
`;

const StyledButton = styled(Button)`
margin-left: auto;
color: inherit;

${({ theme }) => css`
${theme.alert.closeBtn}
`};
`;

const StyledButtonWrapper = styled.div`
margin-left: auto;
padding-left: ${({ theme }) => theme.spacing('xl')};
${({ theme }) => css`
${theme.alert.closeBtnWrapper}
`};
`;

export {
StyledAlert,
StyledAlertTitle,
StyledCheckCircle,
StyledContent,
StyledButtonWrapper,
StyledButton,
StyledExclamationCircle,
StyledIconWrapper,
StyledInformationCircle,
StyledWarning
};
56 changes: 48 additions & 8 deletions packages/components/src/Alert/Alert.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,72 @@
import { AlertStatus } from '@interlay/theme';
import { ForwardRefExoticComponent } from 'react';
import { XMark } from '@interlay/icons';
import { AlertStatus, AlertVariant, Rounded } from '@interlay/theme';
import { ForwardRefExoticComponent, ReactNode } from 'react';

import { FlexProps } from '../Flex';

import { StyledAlert, StyledCheckCircle, StyledInformationCircle, StyledWarning } from './Alert.style';
import {
StyledAlert,
StyledAlertTitle,
StyledButton,
StyledButtonWrapper,
StyledCheckCircle,
StyledContent,
StyledExclamationCircle,
StyledIconWrapper,
StyledInformationCircle,
StyledWarning
} from './Alert.style';

const iconMap: Record<AlertStatus, ForwardRefExoticComponent<any>> = {
info: StyledInformationCircle,
success: StyledCheckCircle,
error: StyledWarning,
error: StyledExclamationCircle,
warning: StyledWarning
};

type Props = {
status?: AlertStatus;
variant?: AlertVariant;
rounded?: Rounded;
title?: ReactNode;
onClose?: () => void;
};

type InheritAttrs = Omit<FlexProps, keyof Props>;

type AlertProps = Props & InheritAttrs;

const Alert = ({ status = 'success', children, ...props }: AlertProps): JSX.Element => {
const Alert = ({
status = 'success',
variant = 'default',
rounded,
children,
title,
onClose,
...props
}: AlertProps): JSX.Element => {
const Icon = iconMap[status];

return (
<StyledAlert $status={status} alignItems='center' gap='md' role='alert' {...props}>
<Icon $status={status} size='md' />
<div>{children}</div>
<StyledAlert $rounded={rounded} $status={status} $variant={variant} role='alert' {...props}>
<StyledIconWrapper>
<Icon $status={status} $variant={variant} size='s' strokeWidth='2' />
</StyledIconWrapper>
<StyledContent>
{title && (
<StyledAlertTitle $status={status} $variant={variant}>
{title}
</StyledAlertTitle>
)}
{children}
</StyledContent>
{onClose && (
<StyledButtonWrapper>
<StyledButton isIconOnly aria-label='close' size='s' variant='ghost' onPress={onClose}>
<XMark color='inherit' size='s' />
</StyledButton>
</StyledButtonWrapper>
)}
</StyledAlert>
);
};
Expand Down
14 changes: 13 additions & 1 deletion packages/components/src/Alert/__tests__/Alert.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { testA11y, render } from '@interlay/test-utils';
import { render, testA11y } from '@interlay/test-utils';
import { screen } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';

import { Alert } from '..';

Expand All @@ -12,4 +14,14 @@ describe('Alert', () => {
it('should pass a11y', async () => {
await testA11y(<Alert>Alert</Alert>);
});

it.skip('should emit close event', () => {
const handleClose = jest.fn();

render(<Alert onClose={handleClose}>Alert</Alert>);

userEvent.click(screen.getByRole('button', { name: /close/i }));

expect(handleClose).toHaveBeenCalledTimes(1);
});
});
14 changes: 12 additions & 2 deletions packages/core/theme/src/components/alert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@ import { StyledObject } from 'styled-components';

type AlertStatus = 'info' | 'success' | 'warning' | 'error';

type AlertVariant = 'filled' | 'outlined' | 'default';

type AlertTheme = {
base: StyledObject<object>;
status: Record<AlertStatus, StyledObject<object>>;
icon: StyledObject<object>;
title: StyledObject<object>;
content: StyledObject<object>;
closeBtn: StyledObject<object>;
closeBtnWrapper: StyledObject<object>;
status: Record<
AlertStatus,
Record<AlertVariant, { base: StyledObject<object>; icon: StyledObject<object>; title: StyledObject<object> }>
>;
};

export type { AlertTheme, AlertStatus };
export type { AlertTheme, AlertStatus, AlertVariant };
10 changes: 7 additions & 3 deletions packages/core/theme/src/core/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ type Palette = {
GreenColors &
RedColors;

type Color = keyof Palette;
type NativeColor = 'inherit' | 'unset' | string;

const color = (colors: Palette) => (color: Color | 'inherit') => (color === 'inherit' ? color : colors[color]);
type PaletteColor = keyof Palette;

type Color = PaletteColor | NativeColor;

const color = (colors: Palette) => (color: Color) => colors[color as PaletteColor] || color;

export { color };
export type { Color, Palette, PrimaryColors, GreyColors, BlueColors, GreenColors, RedColors };
export type { Color, Palette, PrimaryColors, PaletteColor, GreyColors, BlueColors, GreenColors, RedColors };
1 change: 1 addition & 0 deletions packages/core/theme/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type {
AccordionVariants,
ProgressBarSize,
AlertStatus,
AlertVariant,
TokenInputSize,
TabsSize,
SwitchSize,
Expand Down
Loading
Loading