From d96136bb518cc8f5e0f81ffbfcc75a85fb4f0706 Mon Sep 17 00:00:00 2001 From: Lloyd Francis Date: Tue, 22 Oct 2024 17:34:21 +0200 Subject: [PATCH 1/2] feat: adding an experimental divider component --- .../experimental/Divider/Divider.spec.tsx | 35 ++++++++++++ .../experimental/Divider/Divider.tsx | 33 ++++++++++++ .../Divider/docs/Divider.stories.tsx | 54 +++++++++++++++++++ src/essentials/experimental/Colors.ts | 2 + src/essentials/experimental/types.ts | 1 + 5 files changed, 125 insertions(+) create mode 100644 src/components/experimental/Divider/Divider.spec.tsx create mode 100644 src/components/experimental/Divider/Divider.tsx create mode 100644 src/components/experimental/Divider/docs/Divider.stories.tsx diff --git a/src/components/experimental/Divider/Divider.spec.tsx b/src/components/experimental/Divider/Divider.spec.tsx new file mode 100644 index 000000000..40a885a61 --- /dev/null +++ b/src/components/experimental/Divider/Divider.spec.tsx @@ -0,0 +1,35 @@ +import * as React from 'react'; +import { render, screen } from '@testing-library/react'; +import { Divider } from './Divider'; + +describe('Experimental: Divider', () => { + it('renders a horizontal divider by default when not passing any props', () => { + render(); + expect(screen.getByTestId('horizontal-divider-experimental')).toBeInTheDocument(); + expect(screen.queryByTestId('vertical-divider-experimental')).not.toBeInTheDocument(); + }); + + it('renders a vertical divider when passing vertical prop', () => { + render(); + expect(screen.getByTestId('vertical-divider-experimental')).toBeInTheDocument(); + expect(screen.queryByTestId('horizontal-divider-experimental')).not.toBeInTheDocument(); + }); + + it('renders horizontal divider with 1rem top and bottom offset', () => { + render(); + const dividerInstance = screen.getByTestId('horizontal-divider-experimental'); + 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', () => { + render(); + const dividerInstance = screen.getByTestId('vertical-divider-experimental'); + const dividerStyle = window.getComputedStyle(dividerInstance); + + expect(dividerStyle.marginLeft).toBe('1rem'); + expect(dividerStyle.marginRight).toBe('1rem'); + }); +}); diff --git a/src/components/experimental/Divider/Divider.tsx b/src/components/experimental/Divider/Divider.tsx new file mode 100644 index 000000000..0983adc09 --- /dev/null +++ b/src/components/experimental/Divider/Divider.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { compose, LayoutProps, space, SpaceProps } from 'styled-system'; +import styled from 'styled-components'; +import { getSemanticValue } from '../../../essentials/experimental'; + +type DividerProps = SpaceProps & + LayoutProps & { + /** + * Set the direction of the divider to vertical + */ + vertical?: boolean; + }; + +const HorizontalLine = styled.div` + width: ${props => props.width || '100%'}; + border-top: 1px solid ${getSemanticValue('divider')}; + ${compose(space)} +`; + +const VerticalLine = styled.div` + display: inline-block; + height: ${props => props.height || '100%'}; + border-left: 1px solid ${getSemanticValue('divider')}; + width: 0; + ${compose(space)} +`; + +export const Divider: React.FC = ({ vertical = false, ...props }: DividerProps) => + vertical ? ( + + ) : ( + + ); diff --git a/src/components/experimental/Divider/docs/Divider.stories.tsx b/src/components/experimental/Divider/docs/Divider.stories.tsx new file mode 100644 index 000000000..bbc9970b5 --- /dev/null +++ b/src/components/experimental/Divider/docs/Divider.stories.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { StoryObj, Meta } from '@storybook/react'; +import { Divider } from '../Divider'; +import { Text } from '../../Text/Text'; + +const meta: Meta = { + title: 'Experimental/Components/Divider', + component: Divider, + parameters: { + layout: 'centered' + } +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + decorators: [ + Story => ( +
+ One + + Two +
+ ) + ], + args: { + vertical: false + } +}; + +export const VerticalDivider: Story = { + args: { + vertical: true + }, + decorators: [ + Story => ( +
+ One + + Two +
+ ) + ] +}; diff --git a/src/essentials/experimental/Colors.ts b/src/essentials/experimental/Colors.ts index b48384c47..15537dff3 100644 --- a/src/essentials/experimental/Colors.ts +++ b/src/essentials/experimental/Colors.ts @@ -101,6 +101,7 @@ export const ColorPalette = { export const SemanticColorsLight = { // Accent accent: 'transparent', + divider: ColorPalette.neutral['90'], 'on-accent': 'transparent', // Interactive interactive: ColorPalette.marooned['50'], @@ -130,6 +131,7 @@ export const SemanticColorsLight = { export const SemanticColorsDark = { // Accent accent: 'transparent', + divider: ColorPalette.neutral['40'], 'on-accent': 'transparent', // Interactive interactive: ColorPalette.marooned['70'], diff --git a/src/essentials/experimental/types.ts b/src/essentials/experimental/types.ts index 66ba5f530..81c2ba262 100644 --- a/src/essentials/experimental/types.ts +++ b/src/essentials/experimental/types.ts @@ -29,6 +29,7 @@ export type SemanticColorsSchema = { 'on-interactive-container': Color; // Neutrals surface: Color; + divider: Color; 'on-surface': Color; 'surface-variant': Color; 'on-surface-variant': Color; From b25c3f035ea214b4dbacc65b1213ba64c7c19adf Mon Sep 17 00:00:00 2001 From: Lloyd Francis Date: Wed, 23 Oct 2024 11:49:40 +0200 Subject: [PATCH 2/2] feat: introducing variants as requested by lena :P --- .../experimental/Divider/Divider.spec.tsx | 54 ++++++++++++ .../experimental/Divider/Divider.tsx | 56 ++++++++++-- .../Divider/docs/Divider.stories.tsx | 87 +++++++++++++++++-- 3 files changed, 183 insertions(+), 14 deletions(-) diff --git a/src/components/experimental/Divider/Divider.spec.tsx b/src/components/experimental/Divider/Divider.spec.tsx index 40a885a61..1fa10946d 100644 --- a/src/components/experimental/Divider/Divider.spec.tsx +++ b/src/components/experimental/Divider/Divider.spec.tsx @@ -32,4 +32,58 @@ describe('Experimental: Divider', () => { expect(dividerStyle.marginLeft).toBe('1rem'); expect(dividerStyle.marginRight).toBe('1rem'); }); + + it('renders vertical divider with 1rem top and bottom offset when variant is middle-inset', () => { + render(); + const dividerInstance = screen.getByTestId('vertical-divider-experimental'); + const dividerStyle = window.getComputedStyle(dividerInstance); + + expect(dividerStyle.marginTop).toBe('1rem'); + expect(dividerStyle.marginBottom).toBe('1rem'); + }); + + it('renders vertical divider with 1rem offset when variant is inset', () => { + render(); + const dividerInstance = screen.getByTestId('vertical-divider-experimental'); + const dividerStyle = window.getComputedStyle(dividerInstance); + + expect(dividerStyle.marginTop).toBe('1rem'); + expect(dividerStyle.marginBottom).toBe(''); + }); + + it('renders horizontal divider with 1rem left offset when variant is inset', () => { + render(); + const dividerInstance = screen.getByTestId('horizontal-divider-experimental'); + const dividerStyle = window.getComputedStyle(dividerInstance); + + expect(dividerStyle.marginRight).toBe(''); + expect(dividerStyle.marginLeft).toBe('1rem'); + }); + + it('renders horizontal divider with overridden offset when variant is inset', () => { + render(); + const dividerInstance = screen.getByTestId('horizontal-divider-experimental'); + const dividerStyle = window.getComputedStyle(dividerInstance); + + expect(dividerStyle.marginRight).toBe(''); + expect(dividerStyle.marginLeft).toBe('2rem'); + }); + + it('renders horizontal divider with 1rem left and right offset when variant is middle-inset', () => { + render(); + const dividerInstance = screen.getByTestId('horizontal-divider-experimental'); + const dividerStyle = window.getComputedStyle(dividerInstance); + + expect(dividerStyle.marginRight).toBe('1rem'); + expect(dividerStyle.marginLeft).toBe('1rem'); + }); + + it('renders horizontal divider with overridden offset when variant is middle-inset', () => { + render(); + const dividerInstance = screen.getByTestId('horizontal-divider-experimental'); + const dividerStyle = window.getComputedStyle(dividerInstance); + + expect(dividerStyle.marginRight).toBe('2rem'); + expect(dividerStyle.marginLeft).toBe('1rem'); + }); }); diff --git a/src/components/experimental/Divider/Divider.tsx b/src/components/experimental/Divider/Divider.tsx index 0983adc09..15a27bf23 100644 --- a/src/components/experimental/Divider/Divider.tsx +++ b/src/components/experimental/Divider/Divider.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { compose, LayoutProps, space, SpaceProps } from 'styled-system'; +import { compose, LayoutProps, space, SpaceProps, variant } from 'styled-system'; import styled from 'styled-components'; import { getSemanticValue } from '../../../essentials/experimental'; @@ -9,25 +9,63 @@ type DividerProps = SpaceProps & * Set the direction of the divider to vertical */ vertical?: boolean; + /** + * Set the variant of the divider + */ + variant?: 'full-width' | 'inset' | 'middle-inset'; }; +const horizontalVariants = variant({ + prop: 'variant', + variants: { + 'full-width': { + minWidth: '100%' + }, + inset: { + marginLeft: '1rem' + }, + 'middle-inset': { + marginLeft: '1rem', + marginRight: '1rem' + } + } +}); + +const verticalVariants = variant({ + prop: 'variant', + variants: { + 'full-width': { + minHeight: '100%' + }, + inset: { + marginTop: '1rem' + }, + 'middle-inset': { + marginTop: '1rem', + marginBottom: '1rem' + } + } +}); + const HorizontalLine = styled.div` - width: ${props => props.width || '100%'}; border-top: 1px solid ${getSemanticValue('divider')}; - ${compose(space)} + ${compose(space, horizontalVariants)} `; const VerticalLine = styled.div` display: inline-block; - height: ${props => props.height || '100%'}; + height: 100%; border-left: 1px solid ${getSemanticValue('divider')}; - width: 0; - ${compose(space)} + ${compose(space, verticalVariants)} `; -export const Divider: React.FC = ({ vertical = false, ...props }: DividerProps) => +export const Divider: React.FC = ({ + vertical = false, + variant: variantVal = 'full-width', + ...props +}: DividerProps) => vertical ? ( - + ) : ( - + ); diff --git a/src/components/experimental/Divider/docs/Divider.stories.tsx b/src/components/experimental/Divider/docs/Divider.stories.tsx index bbc9970b5..49e812184 100644 --- a/src/components/experimental/Divider/docs/Divider.stories.tsx +++ b/src/components/experimental/Divider/docs/Divider.stories.tsx @@ -18,7 +18,7 @@ type Story = StoryObj; export const Default: Story = { decorators: [ Story => ( -
+
One Two @@ -30,6 +30,38 @@ export const Default: Story = { } }; +export const Inset: Story = { + decorators: [ + Story => ( +
+ One + + Two +
+ ) + ], + args: { + vertical: false, + variant: 'inset' + } +}; + +export const MiddleInset: Story = { + decorators: [ + Story => ( +
+ One + + Two +
+ ) + ], + args: { + vertical: false, + variant: 'middle-inset' + } +}; + export const VerticalDivider: Story = { args: { vertical: true @@ -39,10 +71,9 @@ export const VerticalDivider: Story = {
One @@ -52,3 +83,49 @@ export const VerticalDivider: Story = { ) ] }; + +export const VerticalInset: Story = { + decorators: [ + Story => ( +
+ One + + Two +
+ ) + ], + args: { + vertical: true, + variant: 'inset' + } +}; + +export const VerticalMiddleInset: Story = { + decorators: [ + Story => ( +
+ One + + Two +
+ ) + ], + args: { + vertical: true, + variant: 'middle-inset' + } +};