diff --git a/.stylelintrc b/.stylelintrc index b956bbeb9..9db63eb9b 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -9,13 +9,12 @@ ], "rules": { "declaration-empty-line-before": null, - "unit-whitelist": [ - "rem", - "deg", - "fr", - "ms", - "%" - ], + "declaration-property-unit-whitelist": { + "/.*/": ["rem", "deg", "fr", "ms", "%", "px"] + }, + "declaration-property-value-blacklist": { + "/.*/": ["(\\d+[1]+px|[^1]+px)"] + }, "value-keyword-case": ["lower", { "ignoreKeywords": ["dummyValue"] }] } } diff --git a/src/components/Divider/Divider.spec.tsx b/src/components/Divider/Divider.spec.tsx new file mode 100644 index 000000000..303e147bc --- /dev/null +++ b/src/components/Divider/Divider.spec.tsx @@ -0,0 +1,35 @@ +import { render, screen } from '@testing-library/react'; +import * as React from 'react'; +import { Divider } from './Divider'; + +describe('Divider', () => { + it('renders a horizontal divider by default when not passing any props', () => { + render(); + expect(screen.getByTestId('horizontal-divider')).toBeInTheDocument(); + expect(screen.queryByTestId('vertical-divider')).not.toBeInTheDocument(); + }); + + it('renders a vertical divider when passing vertical prop', () => { + render(); + expect(screen.getByTestId('vertical-divider')).toBeInTheDocument(); + expect(screen.queryByTestId('horizontal-divider')).not.toBeInTheDocument(); + }); + + it('renders horizontal divider with 1rem top and bottom offset by default', () => { + render(); + const dividerInstance = screen.getByTestId('horizontal-divider'); + const dividerStyle = window.getComputedStyle(dividerInstance); + + expect(dividerStyle.marginTop).toBe('1rem'); + expect(dividerStyle.marginBottom).toBe('1rem'); + }); + + it('renders vertical divider with 1rem left and right offset by default', () => { + render(); + const dividerInstance = screen.getByTestId('vertical-divider'); + const dividerStyle = window.getComputedStyle(dividerInstance); + + expect(dividerStyle.marginLeft).toBe('1rem'); + expect(dividerStyle.marginRight).toBe('1rem'); + }); +}); diff --git a/src/components/Divider/Divider.tsx b/src/components/Divider/Divider.tsx new file mode 100644 index 000000000..f47ded65e --- /dev/null +++ b/src/components/Divider/Divider.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import styled, { StyledComponent } from 'styled-components'; +import { compose, space, SpaceProps } from 'styled-system'; +import { theme } from '../../essentials/theme'; +import { get } from '../../utils/themeGet'; + +type DividerOffset = number | string; + +interface DividerProps extends SpaceProps { + /** + * Set the direction of the divider to vertical + */ + vertical?: boolean; + /** + * Set offset / margin of the divider from the surrounding content + */ + offset?: DividerOffset; +} + +const HorizontalLine: StyledComponent<'div', typeof theme, DividerProps, 'theme'> = styled.div.attrs({ theme })< + Pick +>` + width: 100%; + margin-left: auto; + margin-right: auto; + border: 0; + border-top: 1px solid ${get('semanticColors.border.primary')}; + + ${compose(space)} +`; + +const VerticalLine: StyledComponent<'div', typeof theme, DividerProps, 'theme'> = styled.div.attrs({ theme })< + Pick +>` + display: inline-block; + width: 0.06rem; + margin-top: 0; + margin-bottom: 0; + border: 0; + border-left: 1px solid ${get('semanticColors.border.primary')}; + + ${compose(space)} +`; + +const Divider: React.FC = ({ vertical = false, offset = '1rem' }: DividerProps) => + vertical ? ( + + ) : ( + + ); + +export { Divider, DividerProps, DividerOffset }; diff --git a/src/components/Divider/docs/Divider.mdx b/src/components/Divider/docs/Divider.mdx new file mode 100644 index 000000000..413ffbff4 --- /dev/null +++ b/src/components/Divider/docs/Divider.mdx @@ -0,0 +1,101 @@ +--- +name: Divider +menu: Components +route: /components/divider +--- + +import { Playground } from 'docz'; +import { ItemWrapper } from '../../../../docs/components/ItemWrapper.ts'; +import { Divider } from '../Divider.tsx'; +import { WrappedHorizontalDivider, WrappedVerticalDivider, SectionPlaceholder } from './WrappedDivider.tsx'; + +# Divider + +**Primary UI element for visually separating content** + +Renders a divider UI component: horizontal or vertical line that visually separates two pieces of data, content or UI. +
+ +### Default Behaviour +The horizontal divider takes up the full available width and the vertical divider takes up the full available height. + +The horizontal divider is rendered by default. Set **vertical** prop to `true` to change the divider orientation. +
+ +### Divider vs Border +The default color of Divider is **$border.primary** (#C6CDD4), however... + +**Divider is NOT a border, and should not be used as such. Please do not use this component as a border for elements.** + +Divider is naturally expected to have a certain offset from the elements it is 'dividing' or separating. +
+ +### Style Props +The Divider has the following design props: +- **offset** - set the divider offset from the content it is separating (uses _mx_, _my_ styled system props) +
+
+ +## Usage + +### Horizontal (with default offset) + + + + + +```jsx + +``` +
+ +### Horizontal (without offset) + + + + + +```jsx + +``` +
+ +### Vertical (with default offset) + + + + + +```jsx + +``` +
+ +### Vertical (without offset) + + + + + +```jsx + +``` +
+ +# Playground + + +
Section 1
+ +
Section 2
+
+ + + {/* We need the row flow to see vertical divider */} +
+ Section 1 + + Section 2 +
+
+ diff --git a/src/components/Divider/docs/WrappedDivider.tsx b/src/components/Divider/docs/WrappedDivider.tsx new file mode 100644 index 000000000..43b64db90 --- /dev/null +++ b/src/components/Divider/docs/WrappedDivider.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import styled from 'styled-components'; +import { Divider } from '../Divider'; +import type DividerOffset from '../Divider'; + +const DividerWrapper = styled.div` + height: auto; + display: flex; + width: 100%; +`; + +const DividerColumnWrapper = styled(DividerWrapper)` + flex-direction: column; +`; + +const DividerSideElement = styled.div` + height: auto; + padding: 4; +`; + +const SectionPlaceholder = styled.div` + flex: 1; + height: '200px'; + border: 1px black solid; + text-align: center; + padding: 20px; +`; + +const WrappedHorizontalDivider = (offset: DividerOffset): React.ReactElement => ( + + Element 1 + + Element 2 + +); + +const WrappedVerticalDivider = (offset: DividerOffset): React.ReactElement => ( + + Element 1 + + Element 2 + +); + +export { WrappedHorizontalDivider, WrappedVerticalDivider, SectionPlaceholder }; diff --git a/src/components/index.ts b/src/components/index.ts index 72e2e515b..e8fc8425b 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -21,6 +21,7 @@ export { Tag, TagProps } from './Tag/Tag'; export { InlineSpinner, InlineSpinnerProps } from './InlineSpinner/InlineSpinner'; export { TabBar, TabBarWithLink as TabBarProps } from './TabBar/TabBar'; export { DatePicker, DateRangePicker, DateRangePickerProps, DatePickerProps } from './Datepicker'; +export { Divider, DividerProps } from './Divider/Divider'; export { Tooltip, TooltipProps } from './Tooltip/Tooltip'; export { Toggle, ToggleProps } from './Toggle/Toggle'; export { Box, BoxProps } from './Box/Box';