Merge pull request #100 from arturbien/feature/window-enhancements-and-tests

Feature/window enhancements and tests
This commit is contained in:
Artur Bień
2020-02-26 09:31:53 +01:00
committed by GitHub
9 changed files with 187 additions and 50 deletions

View File

@@ -30,7 +30,7 @@ const commonButtonStyles = css`
padding-top: ${({ active, isDisabled }) => active && !isDisabled && '2px'};
`;
const StyledButton = styled.button`
export const StyledButton = styled.button`
${({ variant, theme, active, isDisabled, primary }) =>
variant === 'flat'
? css`

View File

@@ -1,31 +1,62 @@
import React from 'react';
import propTypes from 'prop-types';
import styled from 'styled-components';
import styled, { css } from 'styled-components';
import { createBorderStyles, createBoxStyles } from '../common';
const StyledWindow = styled.div`
position: relative;
padding: 2px;
padding: 4px;
${createBorderStyles({ windowBorders: true })}
${createBoxStyles()}
`;
const ResizeHandle = styled.span`
${({ theme }) => css`
display: inline-block;
position: absolute;
bottom: 4px;
right: 4px;
width: 25px;
height: 25px;
background-image: linear-gradient(
135deg,
${theme.borderLightest} 16.67%,
${theme.material} 16.67%,
${theme.material} 33.33%,
${theme.borderDark} 33.33%,
${theme.borderDark} 50%,
${theme.borderLightest} 50%,
${theme.borderLightest} 66.67%,
${theme.material} 66.67%,
${theme.material} 83.33%,
${theme.borderDark} 83.33%,
${theme.borderDark} 100%
);
background-size: 8.49px 8.49px;
clip-path: polygon(100% 0px, 0px 100%, 100% 100%);
border-width: 2px;
border-style: solid;
border-color: ${theme.material};
cursor: nwse-resize;
`}
`;
const Window = ({ shadow, className, children, ...otherProps }) => (
<StyledWindow shadow={shadow} className={className} {...otherProps} swag>
const Window = ({ resizable, shadow, children, ...otherProps }) => (
<StyledWindow shadow={shadow} {...otherProps}>
{children}
{resizable && <ResizeHandle data-testid='resizeHandle' />}
</StyledWindow>
);
Window.defaultProps = {
resizable: false,
shadow: true,
className: '',
children: null
};
Window.propTypes = {
shadow: propTypes.bool,
className: propTypes.string,
resizable: propTypes.bool,
children: propTypes.node
};

View File

@@ -0,0 +1,37 @@
import React from 'react';
import { renderWithTheme } from '../../../test/utils';
import Window from './Window';
describe('<Window />', () => {
it('renders Window', () => {
const { container } = renderWithTheme(<Window />);
const window = container.firstChild;
expect(window).toBeInTheDocument();
});
it('renders children', () => {
const textContent = 'Hi there!';
const { getByText } = renderWithTheme(
<Window>
<span>{textContent}</span>
</Window>
);
expect(getByText(textContent)).toBeInTheDocument();
});
describe('prop: resizable', () => {
it('does not render resize handle by default', () => {
const { queryByTestId } = renderWithTheme(<Window />);
expect(queryByTestId('resizeHandle')).not.toBeInTheDocument();
});
it('renders resize handle when set to true', () => {
const { queryByTestId } = renderWithTheme(<Window resizable />);
expect(queryByTestId('resizeHandle')).toBeInTheDocument();
});
});
});

View File

@@ -28,13 +28,9 @@ storiesOf('Window', module)
}}
>
<span>react95.exe</span>
<Button
style={{ marginRight: '-6px', marginTop: '1px' }}
size='sm'
square
>
<Button>
<span style={{ fontWeight: 'bold', transform: 'translateY(-1px)' }}>
x
X
</span>
</Button>
</WindowHeader>
@@ -59,16 +55,17 @@ storiesOf('Window', module)
</WindowContent>
</Window>
))
.add('no shadow', () => (
<Window shadow={false}>
.add('resizable', () => (
<Window resizable>
<WindowHeader>react95.exe</WindowHeader>
<WindowContent>
<ul>
<li>something here</li>
<li>something here</li>
<li>something here</li>
<li>something here</li>
</ul>
Resizable Window displays resize handle in bottom right corner
</WindowContent>
</Window>
))
.add('not Active', () => (
<Window>
<WindowHeader isActive={false}>react95.exe</WindowHeader>
<WindowContent>I am not active</WindowContent>
</Window>
));

View File

@@ -9,21 +9,15 @@ const StyledWindowContent = styled.div`
margin-right: 2px;
`;
const WindowContent = ({ className, children, style, ...otherProps }) => (
<StyledWindowContent className={className} style={style} {...otherProps}>
{children}
</StyledWindowContent>
const WindowContent = ({ children, ...otherProps }) => (
<StyledWindowContent {...otherProps}>{children}</StyledWindowContent>
);
WindowContent.defaultProps = {
className: '',
style: {},
children: null
};
WindowContent.propTypes = {
className: propTypes.string,
style: propTypes.shape([propTypes.string, propTypes.number]),
children: propTypes.node
};

View File

@@ -0,0 +1,24 @@
import React from 'react';
import { renderWithTheme } from '../../../test/utils';
import WindowContent from './WindowContent';
describe('<WindowContent />', () => {
it('renders WindowContent', () => {
const { container } = renderWithTheme(<WindowContent />);
const windowContent = container.firstChild;
expect(windowContent).toBeInTheDocument();
});
it('renders children', () => {
const textContent = 'Hi there!';
const { getByText } = renderWithTheme(
<WindowContent>
<span>{textContent}</span>
</WindowContent>
);
expect(getByText(textContent)).toBeInTheDocument();
});
});

View File

@@ -2,41 +2,49 @@ import React from 'react';
import propTypes from 'prop-types';
import styled from 'styled-components';
import { padding } from '../common/system';
import { StyledButton } from '../Button/Button';
const SlyledWindowHeader = styled.div`
height: 33px;
line-height: 33px;
padding: 0 ${padding.sm};
margin-right: 2px;
margin-bottom: 4px;
padding-left: 0.25rem;
padding-right: 3px;
font-weight: bold;
color: ${({ theme }) => theme.textInvert};
background: linear-gradient(
to right,
${({ theme }) => theme.headerMaterialDark},
${({ theme }) => theme.headerMaterialLight}
);
&[data-active='false'] {
background: ${({ theme }) => theme.headerNotActive};
color: ${({ theme }) => theme.material};
}
&[data-active='true'] {
background: linear-gradient(
to right,
${({ theme }) => theme.headerMaterialDark},
${({ theme }) => theme.headerMaterialLight}
);
color: ${({ theme }) => theme.textInvert};
}
${StyledButton} {
padding-left: 0;
padding-right: 0;
height: 27px;
width: 31px;
}
`;
const WindowHeader = ({ className, style, children, ...otherProps }) => (
<SlyledWindowHeader className={className} style={style} {...otherProps}>
// TODO - should we add some aria label indicating if window is currently active?
const WindowHeader = ({ isActive, children, ...otherProps }) => (
<SlyledWindowHeader data-active={isActive.toString()} {...otherProps}>
{children}
</SlyledWindowHeader>
);
WindowHeader.defaultProps = {
className: '',
style: {},
children: null
children: null,
isActive: true
};
WindowHeader.propTypes = {
className: propTypes.string,
style: propTypes.shape([propTypes.string, propTypes.number]),
children: propTypes.node
children: propTypes.node,
isActive: propTypes.bool
};
export default WindowHeader;

View File

@@ -0,0 +1,40 @@
import React from 'react';
import { renderWithTheme } from '../../../test/utils';
import WindowHeader from './WindowHeader';
describe('<WindowHeader />', () => {
it('renders WindowHeader', () => {
const { container } = renderWithTheme(<WindowHeader />);
const windowHeader = container.firstChild;
expect(windowHeader).toBeInTheDocument();
});
it('renders children', () => {
const textContent = 'Hi there!';
const { getByText } = renderWithTheme(
<WindowHeader>
<span>{textContent}</span>
</WindowHeader>
);
expect(getByText(textContent)).toBeInTheDocument();
});
describe('prop: isActive', () => {
it('displays active header by default', () => {
const { container } = renderWithTheme(<WindowHeader />);
const windowHeader = container.firstChild;
expect(windowHeader).toHaveAttribute('data-active', 'true');
});
it('renders non-active header when set to false', () => {
const { container } = renderWithTheme(<WindowHeader isActive={false} />);
const windowHeader = container.firstChild;
expect(windowHeader).toHaveAttribute('data-active', 'false');
});
});
});

View File

@@ -12,8 +12,9 @@ themes.default = {
borderLight: '#dfe0e3',
headerMaterialDark: '#000080',
headerMaterialLight: '#1034a6',
headerMaterialLight: '#000080',
headerText: '#ffffff',
headerNotActive: '#7f7f7f',
text: '#050608',
textInvert: '#ffffff',
@@ -53,6 +54,7 @@ themes.water = {
headerMaterialDark: '#72b3b4',
headerMaterialLight: '#72b3b4',
headerText: '#ffffff',
headerNotActive: '#9a9e9c',
text: '#050608',
textInvert: '#ffffff',
@@ -95,6 +97,7 @@ themes.coldGray = {
headerMaterialDark: '#3B3D64',
headerMaterialLight: '#8d88c2',
headerText: '#010601',
headerNotActive: '#6063a5',
text: '#010601',
textInvert: '#c7c7df',
@@ -135,6 +138,7 @@ themes.lilacRoseDark = {
headerMaterialDark: '#4C0030',
headerMaterialLight: '#8d88c2',
headerText: '#010601',
headerNotActive: '#763a60',
text: '#000000',
textInvert: '#ecbfe3',
@@ -163,6 +167,7 @@ themes.violetDark = {
canvas: '#c47bcc',
material: '#652a6d',
materialDark: '#210e23',
borderDarkest: '#18051a',
borderLightest: '#c47bcc',
borderDark: '#3c1f3e',
@@ -171,6 +176,7 @@ themes.violetDark = {
headerMaterialDark: '#1034a6',
headerMaterialLight: '#512155',
headerNotActive: '#210e23',
text: '#c57ece',
textInvert: '#c47bcc',