Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Component] Text introduction #193

Merged
merged 22 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
79be7f5
feat: [Paragraph] Create component + tests + stories
meissadia Oct 5, 2023
98474e9
feat: [TextIntroduction] Create component + tests + stories
meissadia Oct 5, 2023
39311be
feat: [Storybook] Set default theme to "light" instead of "dark"
meissadia Oct 5, 2023
ed86d04
fix:[Paragraph] Remove duplicate intro paragraph
meissadia Oct 5, 2023
0328bfa
[Paragraph] Update placeholder text
meissadia Oct 12, 2023
1af90a8
fix: [TextIntroduction] Apply customized spacing to component elements
meissadia Oct 12, 2023
734be8b
feat: [Storybook] Set line-height to 22px
meissadia Oct 13, 2023
88e23e5
deps: Remove storybook-dark-mode
meissadia Oct 13, 2023
b5330f9
feat: [Storybook] Refactor and update UI theme
meissadia Oct 13, 2023
e05db0c
fix: [TextIntroduction] Apply latest component styles
meissadia Oct 13, 2023
7563dd2
docs: Note addtional places where CSS customization is implemented
meissadia Oct 13, 2023
d9552e8
fix: [Storybook] Update theme
meissadia Oct 16, 2023
2b21d79
WIP: Examples for spacing
meissadia Oct 16, 2023
ed160b5
Merge branch 'main' into 158-text-introduction
meissadia Oct 24, 2023
e31fbca
Merge branch 'main' into 158-text-introduction
meissadia Oct 26, 2023
4876a33
fix: Delete SpacingEvaluation stories
meissadia Oct 26, 2023
de79742
fix: [TextIntroduction] Match DS language
meissadia Oct 26, 2023
70f636a
fix: [TextIntroduction] Use DS styles
meissadia Oct 26, 2023
80dffd5
Merge branch 'main' into 158-text-introduction
meissadia Oct 31, 2023
cd6a4a5
Merge branch 'main' into 158-text-introduction
meissadia Oct 31, 2023
39860f8
Merge branch 'main' into 158-text-introduction
meissadia Oct 31, 2023
da513ce
Move Paragraph and TextIntroduction to "Verified" status
meissadia Oct 31, 2023
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
3 changes: 1 addition & 2 deletions .storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ module.exports = {
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-a11y',
'display-element-css',
'storybook-dark-mode'
'display-element-css'
],
docs: {
autodocs: true,
Expand Down
17 changes: 15 additions & 2 deletions .storybook/manager-head.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,22 @@
font-size: 15px !important;
}

div.sidebar-item[data-selected="false"]:hover,
/* Sidebar hover */
div.sidebar-item[data-selected='false']:hover,
button.sidebar-item:hover {
background-color: #5a5d61 !important;
color: white !important;
}
</style>

/* Sidebar hover/selected icons */
div.sidebar-item[data-selected='false']:hover svg,
button.sidebar-item:hover svg {
color: white;
}

/* Sidebar icons */
.sidebar-item svg {
color: black;
}

</style>
4 changes: 3 additions & 1 deletion .storybook/manager.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { addons } from '@storybook/manager-api';
import themeCFPB from './themeCFPB';

addons.setConfig({
sidebar: {
Expand All @@ -11,5 +12,6 @@ addons.setConfig({
}
return name;
}
}
},
theme: themeCFPB
});
54 changes: 19 additions & 35 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,26 @@
import '@cfpb/cfpb-design-system/src/cfpb-design-system.less';
import { themes } from '@storybook/theming';
import CfpbLogo from '../src/assets/images/cfpb-logo-vertical.png';
import '../src/assets/styles/_shared.less';
import themeCFPB from './themeCFPB';

const sharedThemeElements = {
brandTitle: 'CFPB Design System React',
brandImage: CfpbLogo,
brandUrl: 'https://cfpb.github.io/design-system/',
brandTarget: '_blank',
fontBase: '"Avenir Next", Arial ,sans-serif'
};

export const parameters = {
options: {
// Determines the display order of Stories in the sidebar
storySort: {
order: ['Guides', 'Components (Verified)', 'Components (Draft)', '*']
}
},
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/
}
},
darkMode: {
current: 'dark',
// Override the default dark theme
dark: {
...themes.dark,
...sharedThemeElements,
appBg: 'black'
export const preview = {
parameters: {
options: {
// Determines the display order of Stories in the sidebar
storySort: {
order: ['Guides', 'Components (Verified)', 'Components (Draft)', '*']
}
},
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/
}
},
// Override the default light theme
light: {
...themes.normal,
...sharedThemeElements
docs: {
theme: themeCFPB
}
}
};

export default preview;
53 changes: 53 additions & 0 deletions .storybook/themeCFPB.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { create } from '@storybook/theming/create';
import CfpbLogo from '../src/assets/images/cfpb-logo-vertical.png';

const colors = {
black: '#101820',
gray: '#5a5d61',
gray10: '#e7e8e9',
gray40: '#b4b5b6',
green10: '#f0f8eb',
teal: '#257675',
teal80: '#579695'
};

/**
* Note: Additional CSS customizations are implemented in
* - /.storybook/manager-head.html
* - /src/assets/styles/_shared.less
*/
export default create({
base: 'light',

brandTitle: 'CFPB Design System React',
brandImage: CfpbLogo,
brandUrl: 'https://cfpb.github.io/design-system/',
brandTarget: '_blank',

fontBase: '"Avenir Next", Arial ,sans-serif',

// App
appBorderColor: colors.gray,
appContentBg: 'white', // Story overview, tool panel

// Sidebar
appBg: 'white', // Background
textColor: colors.black, // Story names
textMutedColor: colors.black, // Group names

// Toolbars
// colorPrimary: 'color', // Purpose unknown
colorSecondary: colors.teal, // Selected (Controls, Actions, etc)
barTextColor: colors.black, // Text & icons
barSelectedColor: colors.teal,
barBg: colors.gray10,

// Form colors (Controls)
buttonBg: colors.gray10,
buttonBorder: colors.gray40,
booleanBg: colors.gray10,
booleanSelectedBg: colors.teal80,
inputBg: 'white',
inputBorder: colors.gray,
inputTextColor: colors.black
});
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@
"prettier": "2.7.1",
"start-server-and-test": "1.14.0",
"storybook": "^7.0.6",
"storybook-dark-mode": "^3.0.1",
"stylelint": "14.15.0",
"stylelint-config-prettier": "9.0.4",
"stylelint-config-standard": "29.0.0",
Expand Down
Binary file modified src/assets/images/cfpb-logo-vertical.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions src/assets/styles/_shared.less
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,10 @@ pre.prismjs,
:where(p:not(.sb-story *, #storybook-root *)) {
line-height: 22px !important;
}

/*
Apply a global line-height that doesn't interfere with component Stories that have their own line-height settings.
*/
:where(p:not(.sb-story *, #storybook-root *)){
line-height: 22px !important;
}
19 changes: 19 additions & 0 deletions src/components/Paragraph/Paragraph.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import { Paragraph } from './Paragraph';

describe('<Paragraph />', () => {
const helperText = 'helperText goes here';

it('renders Body text', () => {
render(<Paragraph>{helperText}</Paragraph>);
expect(screen.getByText(helperText)).toBeInTheDocument();
});

it('renders Lead paragraph', () => {
render(<Paragraph isLead>{helperText}</Paragraph>);
const element = screen.getByText(helperText);
expect(element).toBeInTheDocument();
expect(element.classList.contains('lead-paragraph')).toBe(true);
});
});
29 changes: 29 additions & 0 deletions src/components/Paragraph/Paragraph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import classnames from 'classnames';

interface ParagraphProperties extends React.HTMLProps<HTMLParagraphElement> {
isLead?: boolean;
}

/**
* Paragraph text should provide an efficient and pleasant experience on every viewport size. Readable text makes good use of alignment, spacing, line length and height, and contrast.
*
* Source: https://cfpb.github.io/design-system/foundation/paragraphs
*/
export function Paragraph({
children,
isLead,
className,
...properties
}: ParagraphProperties): JSX.Element {
const cnames = [className];

if (isLead) cnames.push('lead-paragraph');

return (
<p {...properties} className={classnames(cnames)}>
{children}
</p>
);
}

export default Paragraph;
26 changes: 26 additions & 0 deletions src/components/Paragraph/Paragraphs.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { Meta } from '@storybook/react';
import { Paragraph } from './Paragraph';

const meta: Meta<typeof Paragraph> = {
title: 'Components (Draft)/Paragraphs',
component: Paragraph
};

export default meta;

export const Body = {
name: 'Body text',
args: {
children:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore.'
}
};

export const Lead = {
name: 'Lead paragraph',
args: {
children:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
isLead: true
}
};
17 changes: 17 additions & 0 deletions src/components/TextIntroduction/TextIntroduction.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { Meta } from '@storybook/react';
import { TextIntroduction } from './TextIntroduction';
import placeholders from './testHelpers';

const meta: Meta<typeof TextIntroduction> = {
title: 'Components (Draft)/Text introductions',
component: TextIntroduction
};

export default meta;

export const Standard = {
name: 'Standard text introduction',
args: {
...placeholders
}
};
14 changes: 14 additions & 0 deletions src/components/TextIntroduction/TextIntroduction.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import { TextIntroduction } from './TextIntroduction';
import placeholders from './testHelpers';

describe('<TextIntroduction />', () => {
it('renders all elements when provided', () => {
render(<TextIntroduction {...placeholders} />);
expect(screen.getByText(placeholders.heading)).toBeInTheDocument();
expect(screen.getByText(placeholders.subheading)).toBeInTheDocument();
expect(screen.getByText(placeholders.description)).toBeInTheDocument();
expect(screen.getByText('Call-to-action link')).toBeInTheDocument();
});
});
54 changes: 54 additions & 0 deletions src/components/TextIntroduction/TextIntroduction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import classnames from 'classnames';
import { cloneElement, type ReactNode } from 'react';
import { Heading } from '../Headings/Heading';
import List from '../List/List';
import ListItem from '../List/ListItem';
import { Paragraph } from '../Paragraph/Paragraph';

interface TextIntroductionProperties extends React.HTMLProps<HTMLDivElement> {
// Page title
heading: string;
// Lead paragraph
subheading: string;
// Descriptive paragraph
description?: ReactNode;
// Call-to-action <Link>
callToAction?: JSX.Element;
}

/**
* The text introduction is the standard page introduction pattern used across all pages that do not have a <a href="https://cfpb.github.io/design-system/patterns/heroes">hero</a> or <a href="https://cfpb.github.io/design-system/patterns/item-introductions">item introduction</a>. They introduce a page, or collection of pages, with a brief description of the goals of that section.
*
* Source: https://cfpb.github.io/design-system/patterns/text-introductions
*/
export const TextIntroduction = ({
heading,
subheading,
description,
callToAction,
className,
...properties
}: TextIntroductionProperties): JSX.Element => {
const cnames = ['o-text-introduction', className];

const call2action = callToAction && (
<List isLinks>
<ListItem>{cloneElement(callToAction, { type: 'list' })}</ListItem>
</List>
);

return (
<div
className={classnames(cnames)}
{...properties}
data-testid='text-introduction-wrapper'
>
<Heading type='1'>{heading}</Heading>
<Paragraph isLead>{subheading}</Paragraph>
{description ? <p>{description}</p> : null}
{call2action}
</div>
);
};

export default TextIntroduction;
16 changes: 16 additions & 0 deletions src/components/TextIntroduction/testHelpers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Link from '../Link/Link';

const subheading =
'Lead paragraph lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.';

const description =
'Descriptive paragraph lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore.';

const callToAction = <Link href='/'>Call-to-action link</Link>;

export default {
heading: 'Heading 1',
description,
subheading,
callToAction
};
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export { default as Navbar } from './components/Navbar/Navbar';
export { Notification } from './components/Notification/Notification';
export { default as PageHeader } from './components/PageHeader/PageHeader';
export { Pagination } from './components/Pagination/Pagination';
export { Paragraph } from './components/Paragraph/Paragraph';
export { RadioButton } from './components/RadioButton/RadioButton';
export {
TableComplex,
Expand All @@ -44,5 +45,6 @@ export {
} from './components/Table/Table';
export { Tagline } from './components/Tagline/Tagline';
export { TextInput } from './components/TextInput/TextInput';
export { TextIntroduction } from './components/TextIntroduction/TextIntroduction';
export { default as Well } from './components/Well/Well';

Loading