Adding `BaseIcon` UI component (#15609)
* Adding BaseIcon component * Updates to styles, docs and proptypes * Updating box props linkfeature/default_network_editable
parent
6e0f130168
commit
fc23cff03c
@ -0,0 +1,77 @@ |
||||
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; |
||||
|
||||
import { BaseIcon } from './base-icon'; |
||||
|
||||
### This is a base component. It should not be used in your feature code directly but as a "base" for other UI components |
||||
|
||||
# BaseIcon |
||||
|
||||
The `BaseIcon` is the base component for all icons. It is used in conjunction with a script to create all icons it should not be used directly. |
||||
|
||||
<Canvas> |
||||
<Story id="ui-components-component-library-base-icon-base-icon-stories-js--default-story" /> |
||||
</Canvas> |
||||
|
||||
## Props |
||||
|
||||
The `BaseIcon` accepts all props below as well as all [Box](/docs/ui-components-ui-box-box-stories-js--default-story#props) component props |
||||
|
||||
<ArgsTable of={BaseIcon} /> |
||||
|
||||
### Size |
||||
|
||||
Use the `size` prop and the `SIZES` object from `./ui/helpers/constants/design-system.js` to change the size of `BaseIcon`. Defaults to `SIZES.SM` |
||||
|
||||
Possible sizes include: |
||||
|
||||
- `SIZES.XXS` 10px |
||||
- `SIZES.XS` 12px |
||||
- `SIZES.SM` 16px |
||||
- `SIZES.MD` 20px |
||||
- `SIZES.LG` 24px |
||||
- `SIZES.XL` 32px |
||||
|
||||
<Canvas> |
||||
<Story id="ui-components-component-library-base-icon-base-icon-stories-js--size" /> |
||||
</Canvas> |
||||
|
||||
```jsx |
||||
import { SIZES } from '../../../helpers/constants/design-system'; |
||||
import { BaseIcon } from '../ui/component-library'; |
||||
|
||||
<BaseIcon size={SIZES.XXS} /> |
||||
<BaseIcon size={SIZES.XS} /> |
||||
<BaseIcon size={SIZES.SM} /> |
||||
<BaseIcon size={SIZES.MD} /> |
||||
<BaseIcon size={SIZES.LG} /> |
||||
<BaseIcon size={SIZES.XL} /> |
||||
``` |
||||
|
||||
### Color |
||||
|
||||
Use the `color` prop and the `COLORS` object from `./ui/helpers/constants/design-system.js` to change the color of `BaseIcon`. Defaults to `COLORS.INHERIT` which will use the text color of the parent element. This is useful for inline icons. |
||||
|
||||
<Canvas> |
||||
<Story id="ui-components-component-library-base-icon-base-icon-stories-js--color" /> |
||||
</Canvas> |
||||
|
||||
```jsx |
||||
import { COLORS } from '../../../helpers/constants/design-system'; |
||||
import { BaseIcon } from '../ui/component-library'; |
||||
|
||||
<BaseIcon color={COLORS.INHERIT} /> |
||||
<BaseIcon color={COLORS.ICON_DEFAULT} /> |
||||
<BaseIcon color={COLORS.ICON_ALTERNATIVE} /> |
||||
<BaseIcon color={COLORS.ICON_MUTED} /> |
||||
<BaseIcon color={COLORS.OVERLAY_INVERSE} /> |
||||
<BaseIcon color={COLORS.PRIMARY_DEFAULT} /> |
||||
<BaseIcon color={COLORS.PRIMARY_INVERSE} /> |
||||
<BaseIcon color={COLORS.ERROR_DEFAULT} /> |
||||
<BaseIcon color={COLORS.ERROR_INVERSE} /> |
||||
<BaseIcon color={COLORS.SUCCESS_DEFAULT} /> |
||||
<BaseIcon color={COLORS.SUCCESS_INVERSE} /> |
||||
<BaseIcon color={COLORS.WARNING_DEFAULT} /> |
||||
<BaseIcon color={COLORS.WARNING_INVERSE} /> |
||||
<BaseIcon color={COLORS.INFO_DEFAULT} /> |
||||
<BaseIcon color={COLORS.INFO_INVERSE} /> |
||||
``` |
@ -0,0 +1,56 @@ |
||||
import React from 'react'; |
||||
import PropTypes from 'prop-types'; |
||||
import classnames from 'classnames'; |
||||
import Box from '../../ui/box/box'; |
||||
|
||||
import { |
||||
SIZES, |
||||
COLORS, |
||||
ICON_COLORS, |
||||
} from '../../../helpers/constants/design-system'; |
||||
|
||||
export const BaseIcon = ({ |
||||
className, |
||||
size = SIZES.MD, |
||||
color = COLORS.INHERIT, |
||||
children, |
||||
...props |
||||
}) => { |
||||
return ( |
||||
<Box |
||||
as="svg" |
||||
viewBox="0 0 512 512" |
||||
className={classnames(className, 'base-icon', `base-icon--size-${size}`)} |
||||
color={color} |
||||
{...props} |
||||
> |
||||
{children} |
||||
</Box> |
||||
); |
||||
}; |
||||
|
||||
BaseIcon.propTypes = { |
||||
/** |
||||
* The size of the BaseIcon. |
||||
* Possible values could be 'SIZES.XXS', 'SIZES.XS', 'SIZES.SM', 'SIZES.MD', 'SIZES.LG', 'SIZES.XL', |
||||
* Default value is 'SIZES.MD'. |
||||
*/ |
||||
size: PropTypes.oneOf(Object.values(SIZES)), |
||||
/** |
||||
* The color of the icon. |
||||
* Defaults to COLORS.INHERIT. |
||||
*/ |
||||
color: PropTypes.oneOf(Object.values(ICON_COLORS)), |
||||
/** |
||||
* An additional className to apply to the icon. |
||||
*/ |
||||
className: PropTypes.string, |
||||
/** |
||||
* The <path> to the icon. |
||||
*/ |
||||
children: PropTypes.node, |
||||
/** |
||||
* BaseIcon accepts all the props from Box |
||||
*/ |
||||
...Box.propTypes, |
||||
}; |
@ -0,0 +1,33 @@ |
||||
.base-icon { |
||||
--icon-size: var(--size, 16px); |
||||
|
||||
&--size-xxs { |
||||
--size: 10px; |
||||
} |
||||
|
||||
&--size-xs { |
||||
--size: 12px; |
||||
} |
||||
|
||||
&--size-sm { |
||||
--size: 16px; |
||||
} |
||||
|
||||
&--size-md { |
||||
--size: 20px; |
||||
} |
||||
|
||||
&--size-lg { |
||||
--size: 24px; |
||||
} |
||||
|
||||
&--size-xl { |
||||
--size: 32px; |
||||
} |
||||
|
||||
font-size: var(--icon-size); |
||||
width: 1em; |
||||
height: 1em; |
||||
display: inline-block; |
||||
fill: currentColor; |
||||
} |
@ -0,0 +1,176 @@ |
||||
import React from 'react'; |
||||
import { |
||||
SIZES, |
||||
ALIGN_ITEMS, |
||||
DISPLAY, |
||||
COLORS, |
||||
ICON_COLORS, |
||||
} from '../../../helpers/constants/design-system'; |
||||
import Box from '../../ui/box/box'; |
||||
|
||||
import { BaseIcon } from './base-icon'; |
||||
import README from './README.mdx'; |
||||
|
||||
const marginSizeControlOptions = [ |
||||
undefined, |
||||
0, |
||||
1, |
||||
2, |
||||
3, |
||||
4, |
||||
5, |
||||
6, |
||||
7, |
||||
8, |
||||
9, |
||||
10, |
||||
11, |
||||
12, |
||||
'auto', |
||||
]; |
||||
|
||||
export default { |
||||
title: 'Components/ComponentLibrary/BaseIcon', |
||||
id: __filename, |
||||
component: BaseIcon, |
||||
parameters: { |
||||
docs: { |
||||
page: README, |
||||
}, |
||||
}, |
||||
argTypes: { |
||||
size: { |
||||
control: 'select', |
||||
options: Object.values(SIZES), |
||||
}, |
||||
color: { |
||||
control: 'select', |
||||
options: Object.values(ICON_COLORS), |
||||
}, |
||||
className: { |
||||
control: 'text', |
||||
}, |
||||
marginTop: { |
||||
options: marginSizeControlOptions, |
||||
control: 'select', |
||||
table: { category: 'box props' }, |
||||
}, |
||||
marginRight: { |
||||
options: marginSizeControlOptions, |
||||
control: 'select', |
||||
table: { category: 'box props' }, |
||||
}, |
||||
marginBottom: { |
||||
options: marginSizeControlOptions, |
||||
control: 'select', |
||||
table: { category: 'box props' }, |
||||
}, |
||||
marginLeft: { |
||||
options: marginSizeControlOptions, |
||||
control: 'select', |
||||
table: { category: 'box props' }, |
||||
}, |
||||
}, |
||||
args: { |
||||
color: COLORS.INHERIT, |
||||
size: SIZES.MD, |
||||
children: ( |
||||
<path d="M259 16l204 112 3 3c1 1 2 2 2 3 1 1 1 3 1 4 1 1 1 2 1 3l-2 224c0 5-3 10-7 13L261 496c-3 1-5 2-8 2h-1c-3 0-5-1-8-2L49 380c-5-2-7-7-7-12V141c0-5 2-10 7-13 1 0 1-1 2-1L245 16c5-2 10-2 14 0zm182 150l-175 97 1 195 172-101zm-370 0v190l2 2c0 1 1 2 1 3l163 97V261zm331 170c3-5 9-7 14-4l6 3c5 3 6 9 4 14-2 4-6 6-9 6-2 0-4-1-5-2l-6-3c-5-3-7-9-4-14zm-305-4c5-3 12-1 14 4 3 4 2 11-3 14l-6 3c-2 1-3 1-5 1-4 0-7-2-9-5-3-5-1-11 4-14zm265-18c3-5 9-7 14-4l6 3c5 3 7 9 4 14-2 3-6 5-9 5-2 0-4 0-5-1l-6-3c-5-3-7-9-4-14zm-226-5c5-3 11-1 14 4s1 11-4 14l-5 4c-2 0-4 1-5 1-4 0-7-2-9-5-3-5-1-12 3-14zm186-18c3-5 9-7 14-4l6 3c5 3 7 10 4 14-2 4-5 6-9 6-2 0-4-1-5-2l-6-3c-5-3-7-9-4-14zm-147-4c5-3 11-1 14 4s1 11-4 14l-5 3c-2 1-4 2-6 2-3 0-7-2-9-6-2-5-1-11 4-14zm107-18c3-5 10-7 14-4l6 3c5 3 7 9 4 14-2 3-5 5-9 5-2 0-3 0-5-1l-6-3c-5-3-6-9-4-14zm-69-4c5-3 12-2 15 3 2 5 1 12-4 15l-6 3c-1 1-3 1-5 1-3 0-7-2-9-5-3-5-1-11 4-14zm39-220L87 140l166 95 173-94zm0 150c6 0 11 4 11 10v6c0 6-5 11-11 11-5 0-10-5-10-11v-6c0-6 5-10 10-10zm0-45c6 0 11 4 11 10v6c0 6-5 11-11 11-5 0-10-5-10-11v-6c0-6 5-10 10-10zm0-45c6 0 11 4 11 10v7c0 5-5 10-11 10-5 0-10-5-10-10v-7c0-6 5-10 10-10zm0-45c6 0 11 5 11 10v7c0 5-5 10-11 10-5 0-10-5-10-10v-7c0-5 5-10 10-10z" /> |
||||
), |
||||
}, |
||||
}; |
||||
|
||||
export const DefaultStory = (args) => <BaseIcon {...args} />; |
||||
|
||||
DefaultStory.storyName = 'Default'; |
||||
|
||||
export const Size = (args) => ( |
||||
<Box display={DISPLAY.FLEX} alignItems={ALIGN_ITEMS.BASELINE} gap={1}> |
||||
<BaseIcon {...args} size={SIZES.XXS} /> |
||||
<BaseIcon {...args} size={SIZES.XS} /> |
||||
<BaseIcon {...args} size={SIZES.SM} /> |
||||
<BaseIcon {...args} size={SIZES.MD} /> |
||||
<BaseIcon {...args} size={SIZES.LG} /> |
||||
<BaseIcon {...args} size={SIZES.XL} /> |
||||
</Box> |
||||
); |
||||
|
||||
export const Color = (args) => ( |
||||
<Box display={DISPLAY.FLEX} alignItems={ALIGN_ITEMS.BASELINE}> |
||||
<Box padding={1} display={DISPLAY.FLEX} alignItems={ALIGN_ITEMS.CENTER}> |
||||
<BaseIcon {...args} color={COLORS.INHERIT} /> |
||||
</Box> |
||||
<Box padding={1} display={DISPLAY.FLEX} alignItems={ALIGN_ITEMS.CENTER}> |
||||
<BaseIcon {...args} color={COLORS.ICON_DEFAULT} /> |
||||
</Box> |
||||
<Box padding={1} display={DISPLAY.FLEX} alignItems={ALIGN_ITEMS.CENTER}> |
||||
<BaseIcon {...args} color={COLORS.ICON_ALTERNATIVE} /> |
||||
</Box> |
||||
<Box padding={1} display={DISPLAY.FLEX} alignItems={ALIGN_ITEMS.CENTER}> |
||||
<BaseIcon {...args} color={COLORS.ICON_MUTED} /> |
||||
</Box> |
||||
<Box |
||||
padding={1} |
||||
display={DISPLAY.FLEX} |
||||
alignItems={ALIGN_ITEMS.CENTER} |
||||
backgroundColor={COLORS.OVERLAY_DEFAULT} |
||||
> |
||||
<BaseIcon {...args} color={COLORS.OVERLAY_INVERSE} /> |
||||
</Box> |
||||
<Box padding={1} display={DISPLAY.FLEX} alignItems={ALIGN_ITEMS.CENTER}> |
||||
<BaseIcon {...args} color={COLORS.PRIMARY_DEFAULT} /> |
||||
</Box> |
||||
<Box |
||||
padding={1} |
||||
display={DISPLAY.FLEX} |
||||
alignItems={ALIGN_ITEMS.CENTER} |
||||
backgroundColor={COLORS.PRIMARY_DEFAULT} |
||||
> |
||||
<BaseIcon {...args} color={COLORS.PRIMARY_INVERSE} /> |
||||
</Box> |
||||
<Box padding={1} display={DISPLAY.FLEX} alignItems={ALIGN_ITEMS.CENTER}> |
||||
<BaseIcon {...args} color={COLORS.ERROR_DEFAULT} /> |
||||
</Box> |
||||
<Box |
||||
padding={1} |
||||
display={DISPLAY.FLEX} |
||||
alignItems={ALIGN_ITEMS.CENTER} |
||||
backgroundColor={COLORS.ERROR_DEFAULT} |
||||
> |
||||
<BaseIcon {...args} color={COLORS.ERROR_INVERSE} /> |
||||
</Box> |
||||
<Box padding={1} display={DISPLAY.FLEX} alignItems={ALIGN_ITEMS.CENTER}> |
||||
<BaseIcon {...args} color={COLORS.SUCCESS_DEFAULT} /> |
||||
</Box> |
||||
<Box |
||||
padding={1} |
||||
display={DISPLAY.FLEX} |
||||
alignItems={ALIGN_ITEMS.CENTER} |
||||
backgroundColor={COLORS.SUCCESS_DEFAULT} |
||||
> |
||||
<BaseIcon {...args} color={COLORS.SUCCESS_INVERSE} /> |
||||
</Box> |
||||
<Box padding={1} display={DISPLAY.FLEX} alignItems={ALIGN_ITEMS.CENTER}> |
||||
<BaseIcon {...args} color={COLORS.WARNING_DEFAULT} /> |
||||
</Box> |
||||
<Box |
||||
padding={1} |
||||
display={DISPLAY.FLEX} |
||||
alignItems={ALIGN_ITEMS.CENTER} |
||||
backgroundColor={COLORS.WARNING_DEFAULT} |
||||
> |
||||
<BaseIcon {...args} color={COLORS.WARNING_INVERSE} /> |
||||
</Box> |
||||
<Box padding={1} display={DISPLAY.FLEX} alignItems={ALIGN_ITEMS.CENTER}> |
||||
<BaseIcon {...args} color={COLORS.INFO_DEFAULT} /> |
||||
</Box> |
||||
<Box |
||||
padding={1} |
||||
display={DISPLAY.FLEX} |
||||
alignItems={ALIGN_ITEMS.CENTER} |
||||
backgroundColor={COLORS.INFO_DEFAULT} |
||||
> |
||||
<BaseIcon {...args} color={COLORS.INFO_INVERSE} /> |
||||
</Box> |
||||
</Box> |
||||
); |
@ -0,0 +1,64 @@ |
||||
/* eslint-disable jest/require-top-level-describe */ |
||||
import { render } from '@testing-library/react'; |
||||
import React from 'react'; |
||||
import { SIZES, COLORS } from '../../../helpers/constants/design-system'; |
||||
import { BaseIcon } from './base-icon'; |
||||
|
||||
describe('BaseIcon', () => { |
||||
it('should render correctly', () => { |
||||
const { getByTestId, container } = render( |
||||
<BaseIcon data-testid="base-icon" />, |
||||
); |
||||
expect(getByTestId('base-icon')).toBeDefined(); |
||||
expect(container.querySelector('svg')).toBeDefined(); |
||||
}); |
||||
it('should render with different size classes', () => { |
||||
const { getByTestId } = render( |
||||
<> |
||||
<BaseIcon size={SIZES.XXS} data-testid="base-icon-xxs" /> |
||||
<BaseIcon size={SIZES.XS} data-testid="base-icon-xs" /> |
||||
<BaseIcon size={SIZES.SM} data-testid="base-icon-sm" /> |
||||
<BaseIcon size={SIZES.MD} data-testid="base-icon-md" /> |
||||
<BaseIcon size={SIZES.LG} data-testid="base-icon-lg" /> |
||||
<BaseIcon size={SIZES.XL} data-testid="base-icon-xl" /> |
||||
</>, |
||||
); |
||||
expect(getByTestId('base-icon-xxs')).toHaveClass('base-icon--size-xxs'); |
||||
expect(getByTestId('base-icon-xs')).toHaveClass('base-icon--size-xs'); |
||||
expect(getByTestId('base-icon-sm')).toHaveClass('base-icon--size-sm'); |
||||
expect(getByTestId('base-icon-md')).toHaveClass('base-icon--size-md'); |
||||
expect(getByTestId('base-icon-lg')).toHaveClass('base-icon--size-lg'); |
||||
expect(getByTestId('base-icon-xl')).toHaveClass('base-icon--size-xl'); |
||||
}); |
||||
it('should render with icon colors', () => { |
||||
const { getByTestId } = render( |
||||
<> |
||||
<BaseIcon data-testid="base-icon-color-inherit" /> |
||||
<BaseIcon |
||||
color={COLORS.ICON_DEFAULT} |
||||
data-testid="base-icon-color-default" |
||||
/> |
||||
<BaseIcon |
||||
color={COLORS.ICON_ALTERNATIVE} |
||||
data-testid="base-icon-color-alternative" |
||||
/> |
||||
<BaseIcon |
||||
color={COLORS.ICON_MUTED} |
||||
data-testid="base-icon-color-muted" |
||||
/> |
||||
</>, |
||||
); |
||||
expect(getByTestId('base-icon-color-inherit')).toHaveClass( |
||||
'box--color-inherit', |
||||
); |
||||
expect(getByTestId('base-icon-color-default')).toHaveClass( |
||||
'box--color-icon-default', |
||||
); |
||||
expect(getByTestId('base-icon-color-alternative')).toHaveClass( |
||||
'box--color-icon-alternative', |
||||
); |
||||
expect(getByTestId('base-icon-color-muted')).toHaveClass( |
||||
'box--color-icon-muted', |
||||
); |
||||
}); |
||||
}); |
@ -0,0 +1 @@ |
||||
export { BaseIcon } from './base-icon'; |
@ -1,2 +1,3 @@ |
||||
/** Please import your files in alphabetical order **/ |
||||
@import 'base-avatar/base-avatar'; |
||||
@import 'base-icon/base-icon'; |
||||
|
Loading…
Reference in new issue