Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions src/paragraph/Paragraph.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,46 @@
import React from 'react';
import { classNames } from '../common/utils';

type ParagraphProps = {
type Props = {
/**
* optional CSS class name
*/
className?: string;
/**
* content of the paragraph
* content of the paragraph. it has precedence to children
*/
value: string | number;
/**
* allow to specify a custom content
*/
children: string | number | JSX.Element;
/**
* Additional props/attributes
*/
props?: React.HTMLAttributes<HTMLParagraphElement>;
};

export const Paragraph = ({ className, value, props }: ParagraphProps) => {
type ParagraphValue = Omit<Props, 'children'>;
type ParagraphChildren = Omit<Props, 'value'>;
type ParagraphProps = ParagraphValue | ParagraphChildren;

const isValueType = (p: any): p is ParagraphValue => !!p.value;
const isChildrenType = (p: any): p is ParagraphChildren => !!p.children;

export const Paragraph = ({
className,
props,
...rest
}: ParagraphProps): JSX.Element => {
const dynamicClassName = classNames(['dcx-paragraph', className]);

let content!: string | number | JSX.Element;

if (isChildrenType(rest)) content = rest.children;
if (isValueType(rest)) content = rest.value;

return (
<p className={dynamicClassName} {...props}>
{value}
{content}
</p>
);
};
20 changes: 17 additions & 3 deletions src/paragraph/__tests__/Paragraph.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,36 @@ import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';

describe('Paragraph', () => {

it('should render', () => {
const { container } = render(<Paragraph value="paragraph text"/>);
const { container } = render(<Paragraph value="paragraph text" />);
expect(container.querySelector('p')).toBeInTheDocument();
});
it('should allow to pass a value', () => {
render(<Paragraph className="paragraph" value="paragraph text" />);
expect(screen.getByText('paragraph text')).toBeInTheDocument();
});
it('should allow to pass a custom content', () => {
const expectedText = 'a custom content';
render(<Paragraph className="paragraph">{expectedText}</Paragraph>);
expect(screen.getByText(expectedText)).toBeInTheDocument();
});
it('should display the content of the value given it has precedence', () => {
const valueText = 'a custom value';
const customText = 'a custom content';
render(
<Paragraph className="paragraph" value={valueText}>
{customText}
</Paragraph>
);
expect(screen.getByText(valueText)).toBeInTheDocument();
});

it('should provide the ability to specify arbitrary props', () => {
const { container } = render(
<Paragraph
className="paragraph"
value="paragraph text"
props= {{ id:'my-paragraph'}}
props={{ id: 'my-paragraph' }}
/>
);
expect(container.querySelector('#my-paragraph')).toBeInTheDocument();
Expand Down
19 changes: 19 additions & 0 deletions stories/paragraph/ClassBased.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,27 @@ export default {

export const Basic = {
name: 'Basic',
args: {
className: 'govuk-body',
children: 'This is the content of the paragraph.',
},
};

export const BasicValue = {
name: 'BasicValue',
args: {
className: 'govuk-body',
value: 'This is the content of the paragraph.',
},
};

export const Complex = {
name: 'CustomContent',
args: {
className: 'govuk-body',
children: [
'This is the simple custom-content of the ',
<strong>paragraph</strong>,
],
},
};
14 changes: 12 additions & 2 deletions stories/paragraph/Documentation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,22 @@ When you import the paragraph component without providing any className or style

A more complex example with all the possible properties is:

```js
<Paragraph className="my-classname" props={{ id: 'my-paragraph' }}>
This is the content of the paragraph.
</Paragraph>
```

You can use value prop or children feature but you should not use both, If you use both together, the value property takes precedence:

```js
<Paragraph
value="This is the content of the paragraph."
value="This is the value prop of the paragraph"
className="my-classname"
props={{ id: 'my-paragraph' }}
/>
>
This is the content of the paragraph.
</Paragraph>
```

Below a list of all the available properties:
Expand Down
2 changes: 1 addition & 1 deletion stories/paragraph/UnStyled.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ export default {

export const Unstyled = {
args: {
value: 'This is the content of the paragraph.'
children: 'This is the content of the paragraph.',
},
};
36 changes: 28 additions & 8 deletions stories/paragraph/design-system/AccessibleTheme.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@ import { LiveProvider, LiveEditor } from 'react-live';
import { StorybookUtils } from '../../../core/storybook/StorybookUtils';

/**
* This a theme aimed at easing the vizualization of the different elements of the component in order to improve the experience for people that have visual impairments.
*/
* This a theme aimed at easing the vizualization of the different elements of the component in order to improve the experience for people that have visual impairments.
*/
export default {
title: 'DCXLibrary/Typography/Paragraph/Design system/Accessible',
component: Paragraph,
decorators: [
(getStory) => {
getStory => {
require('../../../dist/design-system/index.css');
require('../../themes/accessible.theme.css');
return getStory();
}
},
],
parameters: {
options: { showPanel: true },
actions: { disable: true },
},
tags: ['autodocs']
tags: ['autodocs'],
};

export const ShowCase = {
Expand All @@ -34,16 +34,36 @@ export const ShowCase = {
},
},
render: () => (
<LiveProvider code={StorybookUtils.getThemeCode('dcx-paragraph', style)} disabled={true} language="css">
<LiveProvider
code={StorybookUtils.getThemeCode('dcx-paragraph', style)}
disabled={true}
language="css"
>
<LiveEditor className="liveEditor" aria-label="editor" />
</LiveProvider>
)

),
};

export const Default = {
name: 'Default',
args: {
children: 'This is the content of the paragraph.',
},
};

export const Value = {
name: 'Value',
args: {
value: 'This is the content of the paragraph.',
},
};

export const CustomContent = {
name: 'CustomContent',
args: {
children: [
'This is the simple custom-content of the ',
<strong>paragraph</strong>,
],
},
};
53 changes: 45 additions & 8 deletions stories/paragraph/design-system/DarkTheme.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ import { LiveProvider, LiveEditor } from 'react-live';
import { StorybookUtils } from '../../../core/storybook/StorybookUtils';

/**
* This a theme showcases how to customize the component so it can be used on dark backgrounds.
*/
* This a theme showcases how to customize the component so it can be used on dark backgrounds.
*/
export default {
title: 'DCXLibrary/Typography/Paragraph/Design system/Dark',
component: Paragraph,
decorators: [
(getStory) => {
getStory => {
require('../../../dist/design-system/index.css');
require('../../themes/dark.theme.css');
return getStory();
}
},
],
parameters: {
options: { showPanel: true },
actions: { disable: true },
},
tags: ['autodocs']
tags: ['autodocs'],
};

export const ShowCase = {
Expand All @@ -35,13 +35,16 @@ export const ShowCase = {
},
},
render: () => (
<LiveProvider code={StorybookUtils.getThemeCode('dcx-paragraph', style)} disabled={true} language="css">
<LiveProvider
code={StorybookUtils.getThemeCode('dcx-paragraph', style)}
disabled={true}
language="css"
>
<LiveEditor className="liveEditor" aria-label="editor" />
</LiveProvider>
)
),
};


export const Default = {
name: 'Default',
parameters: {
Expand All @@ -53,8 +56,42 @@ export const Default = {
],
},
},
args: {
children: 'This is the content of the paragraph.',
},
};

export const Value = {
name: 'Value',
parameters: {
backgrounds: {
default: 'dark',
values: [
{ name: 'dark', value: '#282c34' },
{ name: 'light', value: '#fff' },
],
},
},
args: {
value: 'This is the content of the paragraph.',
},
};

export const CustomContent = {
name: 'CustomContent',
parameters: {
backgrounds: {
default: 'dark',
values: [
{ name: 'dark', value: '#282c34' },
{ name: 'light', value: '#fff' },
],
},
},
args: {
children: [
'This is the simple custom-content of the ',
<strong>paragraph</strong>,
],
},
};
36 changes: 26 additions & 10 deletions stories/paragraph/design-system/Default.stories.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,43 @@
import { Paragraph } from '../../../src/paragraph/Paragraph';
/**
* Here we display the component in its natural paragraph, importing only the base Design System styles.
*/
* Here we display the component in its natural paragraph, importing only the base Design System styles.
*/
export default {
title:'DCXLibrary/Typography/Paragraph/Design system/Default',
title: 'DCXLibrary/Typography/Paragraph/Design system/Default',
component: Paragraph,
decorators:[
(getStory) => {
decorators: [
getStory => {
require('../../../dist/design-system/index.css');
return getStory();
}
},
],
parameters:{
parameters: {
options: { showPanel: true },
actions: { disable: true },
},
tags: ['autodocs']
}
tags: ['autodocs'],
};

export const Default = {
export const Default = {
name: 'Default',
args: {
children: 'This is the content of the paragraph.',
},
};

export const Value = {
name: 'Value',
args: {
value: 'This is the content of the paragraph.',
},
};

export const CustomContent = {
name: 'CustomContent',
args: {
children: [
'This is the simple custom-content of the ',
<strong>paragraph</strong>,
],
},
};
Loading