diff --git a/package-lock.json b/package-lock.json index 036b3ee..3a6c372 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12373,6 +12373,30 @@ "supports-color": "^5.5.0" } }, + "styled-icons": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/styled-icons/-/styled-icons-8.1.0.tgz", + "integrity": "sha512-/DgEIJRcIiyG6hCX8yl+xXucEc4wWhwY3BuT4H+8ZymuGYsvNjGIIOZ7+hXZI3owJK736LNHV9hTg1fG7CDkJg==", + "requires": { + "@emotion/is-prop-valid": "^0.7.3", + "tslib": "^1.9.3" + }, + "dependencies": { + "@emotion/is-prop-valid": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz", + "integrity": "sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==", + "requires": { + "@emotion/memoize": "0.7.1" + } + }, + "@emotion/memoize": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.1.tgz", + "integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==" + } + } + }, "stylis": { "version": "3.5.4", "resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz", @@ -12801,8 +12825,7 @@ "tslib": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" }, "tty-browserify": { "version": "0.0.0", diff --git a/package.json b/package.json index 94f665c..30deb80 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "^/(.*)$": "/src/$1", "^/(.*)$": "/src/styles/variables/$1", "^/(.*)$": "/src/components/pages/$1", - "^/(.*)$": "/src/core/$1" + "^/(.*)$": "/src/core/$1", + "^/(.*)$": "/src/fixtures/$1" }, "coverageReporters": [ "json-summary", @@ -98,6 +99,7 @@ "react": "^16.8.6", "react-dom": "^16.8.6", "react-router-dom": "^5.0.1", - "styled-components": "^4.3.2" + "styled-components": "^4.3.2", + "styled-icons": "^8.1.0" } } diff --git a/src/components/UI/atoms/Icon/Icon.jsx b/src/components/UI/atoms/Icon/Icon.jsx new file mode 100644 index 0000000..0320ed4 --- /dev/null +++ b/src/components/UI/atoms/Icon/Icon.jsx @@ -0,0 +1,84 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styled from 'styled-components'; +import * as boxIconsRegular from 'styled-icons/boxicons-regular'; +import { iconSizes, icons } from '/icons'; +import { iconColors } from '/colorPalette'; +import spacing from '/spacing'; + + +/** + * @description - Icon Component + * + * @prop {string} color - color + * @prop {string} height - height + * @prop {string} width - width + * @prop {string} display - display + * @prop {string} margin - margin + * @prop {string} icon - icon + * + * @return {component} Icon + */ +const Icon = ({ + id, + color, + height, + width, + display, + margin, + icon, +}) => { + const IconType = boxIconsRegular[icons[icon]]; + return ( + + + ); +}; + +Icon.propTypes = { + children: PropTypes.node, + id: PropTypes.string, + color: PropTypes.oneOf(Object.keys(iconColors)), + icon: PropTypes.oneOf(Object.keys(icons)).isRequired, + height: PropTypes.oneOf(Object.keys(iconSizes)), + width: PropTypes.oneOf(Object.keys(iconSizes)), + display: PropTypes.oneOf(['block', 'inline', 'inline-block', 'none']), + margin: PropTypes.oneOf(Object.keys(spacing)), +}; + +Icon.defaultProps = { + id: 'mockIcon', + icon: 'search', + height: 'normal', + width: 'normal', + display: 'block', + margin: 'md', + color: 'primary', +}; + +Icon.Container = styled.svg` +${({ + color, + height, + width, + display, + margin, + theme, + }) => ` +color: ${theme.iconColors[color]}; +height: ${theme.iconSizes[height]}; +width: ${theme.iconSizes[width]}; +display: ${display}; +margin: ${theme.spacing[margin]}; +`} +`; + +export default Icon; diff --git a/src/components/UI/atoms/Icon/Icon.md b/src/components/UI/atoms/Icon/Icon.md new file mode 100644 index 0000000..f07b760 --- /dev/null +++ b/src/components/UI/atoms/Icon/Icon.md @@ -0,0 +1,39 @@ +Icon Default: + +```jsx + +``` + +Icon with all attributes +```jsx + +``` + +Icon with size +```jsx + +``` + +Icon with color +```jsx + +``` + +Icon with margin +```jsx + +``` \ No newline at end of file diff --git a/src/components/UI/atoms/Icon/Icon.spec.js b/src/components/UI/atoms/Icon/Icon.spec.js new file mode 100644 index 0000000..583b458 --- /dev/null +++ b/src/components/UI/atoms/Icon/Icon.spec.js @@ -0,0 +1,70 @@ +import React from 'react'; +import { render, cleanup } from '/helpers/testUtils'; +import mockIcon from '/icons/mockIcon'; +import Icon from './Icon.jsx'; +import 'jest-dom/extend-expect'; + +afterEach(cleanup); + +jest.mock('/icons/Star.svg', () => jest.fn(() => mockIcon)); + +const defaultProps = { + icon: 'star', +}; + +const setup = (props) => { + const utils = render(); + + return { + ...utils, + }; +}; + + +describe('Icon', () => { + it('should render the Icon component with default prop', () => { + const { container } = setup(); + + expect(container).toBeTruthy(); + }); + + it('should render the Icon with height', () => { + const { getByTestId } = setup({ height: 'medium' }); + + const icon = getByTestId('mockIcon'); + + expect(icon).toHaveStyle(` + height: medium + `); + }); + + it('should render the Icon with width', () => { + const { getByTestId } = setup({ width: 'medium' }); + + const icon = getByTestId('mockIcon'); + + expect(icon).toHaveStyle(` + width: medium + `); + }); + + it('should render the Icon with display', () => { + const { getByTestId } = setup({ display: 'inline' }); + + const icon = getByTestId('mockIcon'); + + expect(icon).toHaveStyle(` + display: inline + `); + }); + + it('should render the Icon with color', () => { + const { getByTestId } = setup({ color: 'primary' }); + + const icon = getByTestId('mockIcon'); + + expect(icon).toHaveStyle(` + color: primary + `); + }); +}); diff --git a/src/fixtures/icons/Star.svg b/src/fixtures/icons/Star.svg new file mode 100644 index 0000000..7216c8d --- /dev/null +++ b/src/fixtures/icons/Star.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/fixtures/icons/mockIcon.jsx b/src/fixtures/icons/mockIcon.jsx new file mode 100644 index 0000000..ae0b91c --- /dev/null +++ b/src/fixtures/icons/mockIcon.jsx @@ -0,0 +1,12 @@ +import React from 'react'; + +const mockIcon = ( + + + +); + +export default mockIcon; diff --git a/src/styles/variables/colorPalette.js b/src/styles/variables/colorPalette.js index ded5965..ce55839 100644 --- a/src/styles/variables/colorPalette.js +++ b/src/styles/variables/colorPalette.js @@ -18,3 +18,8 @@ export const borderColors = { primary: '#B02091', black: '#191919', }; + +export const iconColors = { + primary: '#B02091', + gold: '#FFCC4A', +}; diff --git a/src/styles/variables/icons.js b/src/styles/variables/icons.js new file mode 100644 index 0000000..f9aafc2 --- /dev/null +++ b/src/styles/variables/icons.js @@ -0,0 +1,10 @@ +export const icons = { + search: 'Search', + star: 'Star', +}; + +export const iconSizes = { + normal: '3.0rem', + medium: '4.8rem', + big: '8.0rem', +}; diff --git a/src/styles/variables/mainTheme.js b/src/styles/variables/mainTheme.js index 202ba62..a294c7f 100644 --- a/src/styles/variables/mainTheme.js +++ b/src/styles/variables/mainTheme.js @@ -5,13 +5,16 @@ import { textColors, backgroundColors, borderColors, + iconColors, } from './colorPalette'; import borderRadius from './border'; import width from './width'; +import { iconSizes } from './icons'; export default { spacing, fontSizes, + iconSizes, fontWeights, buttonColors, textColors, @@ -19,4 +22,5 @@ export default { borderRadius, width, borderColors, + iconColors, };