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

Feature/info message component #644

Merged
merged 5 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
node_modules/
dist/
coverage/

# Logs
logs
Expand Down
50 changes: 50 additions & 0 deletions src/lib/components/infomessage/InfoMessage.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import styled from 'styled-components';
import { Link, Text } from '../text/Text.component';
import { Icon } from '../icon/Icon.component';
import { defaultTheme } from '../../style/theme';
import { useComputeBackgroundColor } from './InfoMessageUtils';
import { Stack } from '../../spacing';

type Props = {
title: string | React.ReactNode;
content: React.ReactNode;
link?: string;
};

const InfoMessageContainer = styled.div`
background-color: ${defaultTheme.darkRebrand.backgroundLevel2};
border-radius: 3px;
padding: 0.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
color: white;
`;

function InfoMessage({ title, content, link }: Props) {
const { containerRef, backgroundColor } = useComputeBackgroundColor();

return (
<InfoMessageContainer
ref={containerRef}
style={{ backgroundColor: backgroundColor }}
>
<Stack>
<Icon
name="Info-circle"
color={defaultTheme.darkRebrand.infoPrimary}
size="lg"
/>
{typeof title === 'string' ? <Text isEmphazed>{title}</Text> : title}
</Stack>
<Text color="textSecondary">{content}</Text>
{link && (
<Link href={link} target="_blank" style={{ alignSelf: 'flex-end' }}>
More infos <Icon name="External-link"></Icon>
</Link>
)}
</InfoMessageContainer>
);
}

export default InfoMessage;
94 changes: 94 additions & 0 deletions src/lib/components/infomessage/InfoMessageUtils.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { defaultTheme } from '../../style/theme';
import React from 'react';
import { useComputeBackgroundColor } from './InfoMessageUtils';
import { render } from '@testing-library/react';
import '@testing-library/jest-dom';
import { CoreUiThemeProvider } from '../coreuithemeprovider/CoreUiThemeProvider';

describe('useComputeBackgroundColor', () => {
const SUT = jest.fn();

Copy link
Contributor

@JBWatenbergScality JBWatenbergScality Nov 15, 2023

Choose a reason for hiding this comment

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

As it is extracted you will need to add:

afterEach(() => {
SUT.mockClear()
})

it('should return backgroundlevel2 by default', () => {
//S
const Component = () => {
const { containerRef, backgroundColor } = useComputeBackgroundColor();
SUT(backgroundColor);
return <div ref={containerRef}></div>;
};
render(
<CoreUiThemeProvider theme={defaultTheme.darkRebrand}>
<Component />
</CoreUiThemeProvider>,
);
//V
expect(SUT).toHaveBeenCalledWith(defaultTheme.darkRebrand.backgroundLevel2);
});

it('should return backgroundlevel3 if parent element backgroundColor is level 2', () => {
//S
const Component = () => {
const { containerRef, backgroundColor } = useComputeBackgroundColor();
SUT(backgroundColor);
return (
<div
style={{ backgroundColor: defaultTheme.darkRebrand.backgroundLevel2 }}
>
<div ref={containerRef}></div>
</div>
);
};
render(
<CoreUiThemeProvider theme={defaultTheme.darkRebrand}>
<Component />
</CoreUiThemeProvider>,
);
//V
expect(SUT).toHaveBeenCalledWith(defaultTheme.darkRebrand.backgroundLevel3);
});
it('should return backgroundlevel3 if parent of parent element backgroundColor is level 2', () => {
//S
const Component = () => {
const { containerRef, backgroundColor } = useComputeBackgroundColor();
SUT(backgroundColor);
return (
<div
style={{ backgroundColor: defaultTheme.darkRebrand.backgroundLevel2 }}
>
<div>
<div ref={containerRef}></div>
</div>
</div>
);
};
render(
<CoreUiThemeProvider theme={defaultTheme.darkRebrand}>
<Component />
</CoreUiThemeProvider>,
);
//V
expect(SUT).toHaveBeenCalledWith(defaultTheme.darkRebrand.backgroundLevel3);
});
it('should return backgroundlevel2 if parent of parent element backgroundColor is level 3', () => {
//S
const Component = () => {
const { containerRef, backgroundColor } = useComputeBackgroundColor();
SUT(backgroundColor);
return (
<div
style={{ backgroundColor: defaultTheme.darkRebrand.backgroundLevel3 }}
>
<div>
<div ref={containerRef}></div>
</div>
</div>
);
};
render(
<CoreUiThemeProvider theme={defaultTheme.darkRebrand}>
<Component />
</CoreUiThemeProvider>,
);
//V
expect(SUT).toHaveBeenCalledWith(defaultTheme.darkRebrand.backgroundLevel2);
});
});
39 changes: 39 additions & 0 deletions src/lib/components/infomessage/InfoMessageUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { DefaultTheme, useTheme } from "styled-components";
import { hex2RGB } from "../../utils";
import { useEffect, useRef, useState } from "react";

export const useComputeBackgroundColor = () => {
const theme = useTheme();
const containerRef = useRef<HTMLDivElement | null>(null);
const [backgroundColor, setBackgroundColor] = useState('');

useEffect(() => {
containerRef.current &&
setBackgroundColor(getBackgroundColor(containerRef.current, theme));
}, [containerRef,theme]);

return {
containerRef,
backgroundColor,
};
};

export const getBackgroundColor = (element: HTMLElement, theme: DefaultTheme) => {
if (element.parentElement) {
const parentElementBackgroundColor = window.getComputedStyle(
element.parentElement,
)['background-color'];
if (/rgba\([0-9]+, [0-9]+, [0-9]+, 0\)/.test(parentElementBackgroundColor) || !window.getComputedStyle(element.parentElement,)['background-color']) {
return getBackgroundColor(element.parentElement, theme);
} else {
const rgbArray = hex2RGB(theme.backgroundLevel2);
if (
`rgb(${rgbArray[0]}, ${rgbArray[1]}, ${rgbArray[2]})` ===
parentElementBackgroundColor
) {
return theme.backgroundLevel3;
}
}
}
return theme.backgroundLevel2;
};
107 changes: 107 additions & 0 deletions stories/infomessage.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React from 'react';
import InfoMessage from '../src/lib/components/infomessage/InfoMessage.component';
import { Wrapper } from './common';
import { defaultTheme } from '../src/lib/style/theme';
import { Meta, StoryObj } from '@storybook/react';

type Story = StoryObj<typeof InfoMessage>;

const meta: Meta<typeof InfoMessage> = {
title: 'Components/InfoMessage',
component: InfoMessage,
decorators: [(story) => <Wrapper>{story()}</Wrapper>],
};

export default meta;

export const Playground: StoryObj<
React.ComponentProps<typeof InfoMessage> & { backgroundColor?: string }
> = {
render: ({ backgroundColor, ...args }) => (
<div
style={{
backgroundColor,
padding: '1rem',
}}
>
<div
style={{
padding: '1rem',
}}
>
<InfoMessage
title="What to do with this key?"
content="This key is needed by the Veeam repository to access ARTESCA for data backup."
link="test"
/>
</div>
</div>
),
argTypes: {
backgroundColor: {
description: 'Background color of the parent element',
options: ['Level1', 'Level2', 'Level3', 'Level4'],
mapping: {
Level1: defaultTheme.darkRebrand.backgroundLevel1,
Level2: defaultTheme.darkRebrand.backgroundLevel2,
Level3: defaultTheme.darkRebrand.backgroundLevel3,
Level4: defaultTheme.darkRebrand.backgroundLevel4,
},
control: {
type: 'radio',
},
},
},
};

export const Default: Story = {
args: {
title: 'Title for the provided info',
content: 'Some text that will help the user to understand what to do',
},
};

export const WithLink: Story = {
args: {
...Default.args,
link: 'toDocs',
},
};

export const WithDifferentBackground: Story = {
render: (args) => {
return (
<div
style={{
padding: '1rem',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-around',
height: '30rem',
}}
>
<div
style={{
height: '10rem',
backgroundColor: defaultTheme.darkRebrand.backgroundLevel3,
padding: '1rem',
}}
>
<InfoMessage {...args} />
</div>
<div
style={{
height: '10rem',
backgroundColor: defaultTheme.darkRebrand.backgroundLevel2,
padding: '1rem',
}}
>
<InfoMessage {...args} />
</div>
</div>
);
},
args: {
...Default.args,
},
};
Loading