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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
28 changes: 14 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ import '@cfpb/design-system-react/index.css';
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **You get** | DS styles for components listed in [`src/assets/styles/ds-components.ts`](src/assets/styles/ds-components.ts), plus Source Sans 3 (embedded), plus DSR-specific overrides |
| **You still install** | `@cfpb/cfpb-design-system` (peer dependency — web components, version alignment) |
| **You do not import** | `@cfpb/cfpb-design-system/dist/index.css`, `@use '…/src/index'`, or `@cfpb/design-system-react/dsr.css` (already included in `index.css`) |
| **You do not import** | `@cfpb/cfpb-design-system/dist/index.css`, `@use '…/src/index'`, or `@cfpb/design-system-react/dsr.css` (already included in `index.css`) |
| **Best for** | Greenfield React apps that mostly use DSR components (`dsr-test`, new internal tools) |

The [`ds-components.ts`](src/assets/styles/ds-components.ts) barrel is the **library-maintained list** of DS SCSS files that feed `dist/index.css`. DSR contributors add to it when new React components need DS styles. App developers using Pattern A do not touch that file.
Expand Down Expand Up @@ -138,26 +138,26 @@ DSR React components work with either pattern — they emit standard DS classes.

Styles bundled into `@cfpb/design-system-react/index.css` (Pattern A only):

| React area | DS stylesheet (under `@cfpb/cfpb-design-system/src/components/…`) |
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `Button`, `ButtonGroup` | `cfpb-buttons/button`, `button-link`, `button-group` |
| `Heading` (`type="slug"`), `Link`, `List` | `cfpb-typography/slug-header`, `link`, `list` |
| `Pagination` | `cfpb-pagination/pagination` |
| Forms (`TextInput`, `Checkbox`, `Select`, …) | `cfpb-forms/form`, `form-field`, `label`, `text-input`, `select`, `multiselect`, `form-alert`, `search-input` |
| `Expandable`, `ExpandableGroup`, `Summary` | `cfpb-expandables/expandable`, `expandable-group`, `summary`, `summary-minimal` |
| `Alert` | `cfpb-notifications/notification` (+ DSR overrides in `alert.scss`) |
| `Table` | `cfpb-tables/table` |
| `Well`, `Divider`, `Hero`, `TextIntroduction`| `cfpb-layout/well`, `layout`, `hero`, `text-introduction` |
| React area | DS stylesheet (under `@cfpb/cfpb-design-system/src/components/…`) |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `Button`, `ButtonGroup` | `cfpb-buttons/button`, `button-link`, `button-group` |
| `Heading` (`type="slug"`), `Link`, `List` | `cfpb-typography/slug-header`, `link`, `list` |
| `Pagination` | `cfpb-pagination/pagination` |
| Forms (`TextInput`, `Checkbox`, `Select`, …) | `cfpb-forms/form`, `form-field`, `label`, `text-input`, `select`, `multiselect`, `form-alert`, `search-input` |
| `Expandable`, `ExpandableGroup`, `Summary` | `cfpb-expandables/expandable`, `expandable-group`, `summary`, `summary-minimal` |
| `Alert` | `cfpb-notifications/notification` (+ DSR overrides in `alert.scss`) |
| `Table` | `cfpb-tables/table` |
| `Well`, `Divider`, `Hero`, `TextIntroduction` | `cfpb-layout/well`, `layout`, `hero`, `text-introduction` |

Still not every DS module (for example cards). Pattern B apps get remaining DS coverage from full Design System CSS.

### What `dsr.css` covers (Pattern B companion)

Built from [`src/assets/styles/dsr-styles.ts`](src/assets/styles/dsr-styles.ts):

| Area | Notes |
| ---- | ----- |
| `Tab` / `TabList` / `TabPanel` | DSR-only until Tabs land in `cfpb-design-system` |
| Area | Notes |
| ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `Tab` / `TabList` / `TabPanel` | DSR-only until Tabs land in `cfpb-design-system` |
| Alert, banner, breadcrumb, fieldset, footer, grid, header, hero, layout, link, secondary-nav, skip-nav, table, text-input | React-authored overrides / chrome not shipped by DS `dist/index.css` |

### Other options (advanced)
Expand Down
2 changes: 2 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ export default tseslint.config(
'unicorn/prevent-abbreviations': 'off', // Airbnb was less strict than Unicorn
'unicorn/null-data-property': 'off',
'unicorn/no-null': 'off',
// Prefer concise prop JSDoc (`/** ... */`) over forced multiline blocks.
'unicorn/single-line-block-comment-style': 'off',
'react/prop-types': 'off', // Using TypeScript, so don't use PropTypes.
// Resolver cannot resolve Vite/tsconfig path aliases or @cfpb/cfpb-design-system src subpaths.
'import/no-unresolved': [
Expand Down
48 changes: 24 additions & 24 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@cfpb/design-system-react",
"license": "MIT",
"version": "2.0.1",
"version": "2.0.2",
"repository": {
"type": "git",
"url": "https://github.com/cfpb/design-system-react.git"
Expand Down Expand Up @@ -57,28 +57,28 @@
},
"devDependencies": {
"@cfpb/browserslist-config": "^0.0.7",
"@cfpb/cfpb-design-system": "5.8.1",
"@cfpb/cfpb-design-system": "5.8.2",
"@chromatic-com/storybook": "^5.2.1",
"@eslint/js": "^10.0.1",
"@fontsource-variable/source-sans-3": "5.3.0",
"@nabla/vite-plugin-eslint": "^3.0.1",
"@storybook/addon-a11y": "^10.5.5",
"@storybook/addon-docs": "^10.5.5",
"@storybook/addon-links": "^10.5.5",
"@storybook/addon-vitest": "^10.5.5",
"@storybook/react-vite": "^10.5.5",
"@storybook/addon-a11y": "^10.5.6",
"@storybook/addon-docs": "^10.5.6",
"@storybook/addon-links": "^10.5.6",
"@storybook/addon-vitest": "^10.5.6",
"@storybook/react-vite": "^10.5.6",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^7.0.0",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
"@testing-library/user-event": "^14.6.3",
"@types/css-mediaquery": "0.1.4",
"@types/node": "^26.1.2",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.4",
"@types/testing-library__jest-dom": "6.0.0",
"@typescript-eslint/eslint-plugin": "8.65.0",
"@typescript-eslint/parser": "8.65.0",
"@vitejs/plugin-react": "^6.0.4",
"@typescript-eslint/eslint-plugin": "8.66.0",
"@typescript-eslint/parser": "8.66.0",
"@vitejs/plugin-react": "^6.0.5",
"@vitest/browser-playwright": "4.1.10",
"@vitest/coverage-istanbul": "^4.1.10",
"astring": "^1.9.0",
Expand All @@ -95,32 +95,32 @@
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-storybook": "^10.5.5",
"eslint-plugin-storybook": "^10.5.6",
"eslint-plugin-testing-library": "7.16.2",
"eslint-plugin-unicorn": "^72.0.0",
"globals": "^17.8.0",
"eslint-plugin-unicorn": "^73.0.0",
"globals": "^17.9.0",
"husky": "9.1.7",
"jest-matchmedia-mock": "1.1.0",
"jsdom": "29.1.1",
"lint-staged": "17.2.0",
"jsdom": "30.0.1",
"lint-staged": "17.3.0",
"lit": "^3.3.3",
"npm-run-all": "4.1.5",
"playwright": "^1.62.0",
"postcss": "8.5.24",
"playwright": "^1.62.1",
"postcss": "8.5.25",
"prettier": "3.9.6",
"react": "19.2.8",
"react-dom": "19.2.8",
"rollup-plugin-jsx-remove-attributes": "^3.1.2",
"sass": "^1.102.0",
"start-server-and-test": "3.0.11",
"storybook": "^10.5.5",
"start-server-and-test": "3.0.12",
"storybook": "^10.5.6",
"storybook-addon-tag-badges": "^3.1.0",
"storybook-font-inspector": "^1.1.7",
"stylelint": "^17.14.1",
"stylelint-config-standard-scss": "^17.0.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.65.0",
"vite": "^8.1.5",
"typescript-eslint": "^8.66.0",
"vite": "^8.2.0",
"vite-plugin-dts": "^5.0.3",
"vite-plugin-pwa": "^1.3.0",
"vite-plugin-svgr": "^5.2.0",
Expand Down
14 changes: 7 additions & 7 deletions src/components/alert/alert.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import type { ReactNode } from 'react';
import { Alert } from './alert';
import {
AlertFieldLevel,
type AlertFieldLevelType,
} from './alert-field-level';
import { AlertFieldLevel, type AlertFieldLevelType } from './alert-field-level';
import { TextInput } from '../text-input/text-input';
import type { TextInputStatusType } from '../text-input/text-input-status';

Expand Down Expand Up @@ -116,12 +113,15 @@ export const InProgress: Story = {
},
};

const textInputStatuses = ['error', 'warning', 'success'] as const;

const isTextInputStatus = (status: string): status is TextInputStatusType =>
(textInputStatuses as readonly string[]).includes(status);

const textInputStatus = (
status?: AlertFieldLevelType,
): TextInputStatusType | undefined =>
status !== undefined && ['error', 'warning', 'success'].includes(status)
? status
: undefined;
status !== undefined && isTextInputStatus(status) ? status : undefined;

export const SuccessFieldLevel: FieldLevelStory = {
render: (_arguments) => (
Expand Down
5 changes: 1 addition & 4 deletions src/components/alert/alert.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import '@testing-library/jest-dom';
import { render, screen, within } from '@testing-library/react';
import Paragraph from '../paragraph/paragraph';
import { Alert, AlertType } from './alert';
import {
AlertFieldLevel,
type AlertFieldLevelType,
} from './alert-field-level';
import { AlertFieldLevel, type AlertFieldLevelType } from './alert-field-level';

const statusesWithModifier: AlertType[] = ['success', 'warning', 'error'];

Expand Down
3 changes: 3 additions & 0 deletions src/components/tabs/tab.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

.tablist {
display: flex;

// Inset shadow sits in the background layer so an opaque active tab can cover
// it. A real `border-bottom` paints above overlapping children and leaves a
// hairline under the active tab (especially with subpixel heights / retina).
Expand All @@ -16,6 +17,7 @@
padding: math.div(math.div($grid-gutter-width, 3), $base-font-size-px) + rem
math.div($grid-gutter-width, $base-font-size-px) + rem;
border: 1px solid transparent;

// `heading-4` still sets margin-bottom at the xs breakpoint even when
// `$has-margin-bottom` is false. That gap leaves the tablist rule hanging
// below the tab fills (especially obvious on phone widths).
Expand All @@ -37,6 +39,7 @@

&--active {
color: var(--black);

// Beat `.a-btn--link { background-color: transparent !important }` so the
// active fill can cover the tablist rule.
background-color: var(--gray-5) !important;
Expand Down
2 changes: 1 addition & 1 deletion src/components/well/well.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('<WellContent />', () => {
it('Displays elements', () => {
render(<WellContent {...Content.args} />);

const headingText = Content.args!.heading as string;
const headingText = Content.args!.heading!;
const heading = screen.getByText(headingText);
expect(heading).toHaveClass('h3');

Expand Down
1 change: 1 addition & 0 deletions tsconfig.eslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"vite",
"postcss.config.ts",
"vite.config.ts",
"vite.dsr-css.config.ts",
"vitest.config.ts",
"vitest.setup.ts",
"vitest.shims.d.ts",
Expand Down
4 changes: 2 additions & 2 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import type { Plugin } from 'vite';
import { defineConfig } from 'vite';
import dts from 'vite-plugin-dts';
import svgr from 'vite-plugin-svgr';
import { name } from './package.json';
import { svgRawLoaderPlugin } from './vite/plugins/svg-raw-loader';
import { name } from './package.json' with { type: 'json' };
import { svgRawLoaderPlugin } from './vite/plugins/svg-raw-loader.ts';

const __dirname = import.meta.dirname;
const { resolve } = path;
Expand Down
2 changes: 1 addition & 1 deletion vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { playwright } from '@vitest/browser-playwright';
import path from 'node:path';
import { defineConfig, mergeConfig } from 'vitest/config';
import viteConfig from './vite.config';
import viteConfig from './vite.config.ts';

const __dirname = import.meta.dirname;
const { resolve } = path;
Expand Down
Loading
Loading