diff --git a/.storybook/preview.js b/.storybook/preview.js index a709f1a0da..8a1a1ef0ff 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -1,8 +1,7 @@ import React from 'react'; import { buildArgsParam } from 'storybook/internal/router'; import { useArgs, useGlobals } from 'storybook/preview-api'; -import '@fontsource-variable/source-sans-3'; -import '../src/assets/styles/_shared.scss'; +import '../src/assets/styles/entry-styles'; import themeCFPB from './themeCFPB'; const responsivePreviewQueryParameter = 'responsivePreview'; diff --git a/README.md b/README.md index 28cc4e4e50..540bf1aed0 100644 --- a/README.md +++ b/README.md @@ -12,16 +12,28 @@ Current components: https://cfpb.github.io/design-system-react The `@cfpb/design-system-react` library is released as an [NPM package](https://www.npmjs.com/package/@cfpb/design-system-react). -To install the package and its peer dependencies: +Install the library and its peer dependencies: ``` -yarn add @cfpb/design-system-react @cfpb/cfpb-design-system lit react react-dom react-router +yarn add @cfpb/design-system-react @cfpb/cfpb-design-system lit react react-dom ``` -`lit` is required because `@cfpb/cfpb-design-system` web components (for example `` in `Banner`) are built with [Lit](https://lit.dev/). +Add `react-router` if you use `Link` with `isRouterLink`: + +``` +yarn add react-router +``` + +| Peer | When you need it | +| -------------------------- | --------------------------------------------------------------------------------------------------------------- | +| `@cfpb/cfpb-design-system` | Always install it. Required for DS web components and for importing DS styles directly (see [Styles](#styles)). | +| `lit` | Components that render DS web components (for example `Banner` / ``). | +| `react-router` | `Link` with `isRouterLink` only. | ## Usage +Import components from the package: + ```ts import { Alert, Button } from '@cfpb/design-system-react'; import type { ReactElement } from 'react'; @@ -43,6 +55,172 @@ export default function SomePage(): ReactElement { } ``` +**You must also load styles** — see [Styles](#styles). Component imports alone do not apply CFPB styling. + +## Styles + +DSR components render the same CSS class names as `@cfpb/cfpb-design-system` (for example `.a-btn`, `.m-form-field`). **Styles must be loaded separately** — importing React components alone does not apply CFPB styling. + +There are **two supported patterns**. Pick one global CSS source for your app — **do not load both**. + +### Pattern A: DSR CSS only (new React apps) + +For Vite/CRA-style apps with no Sass pipeline. Import the library’s prebuilt stylesheet once: + +```ts +// main.tsx or App.tsx +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` or `@use '…/src/index'` in your app | +| **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. + +### Pattern B: Full DS CSS + DSR components (existing CFPB apps) + +For apps that already load the full Design System — Sass-based properties, hand-rolled DS markup, cf.gov-style setups (for example apps that use `.o-expandable`, `.m-list`, `.m-btn-group` outside DSR components). + +Import **DSR components only**. Do **not** import `@cfpb/design-system-react/index.css`. + +**JavaScript / prebuilt CSS:** + +```ts +// App entry — components from DSR, styles from DS +import { Button, Heading } from '@cfpb/design-system-react'; +// No: import '@cfpb/design-system-react/index.css'; +``` + +```scss +// base.scss or global styles entry +@use '@cfpb/cfpb-design-system/src/abstracts' as *; +@use '@cfpb/cfpb-design-system/src/base' as *; +@use '@cfpb/cfpb-design-system/dist/index.css' as *; +``` + +**Or Sass source (same coverage as `dist/index.css`):** + +```scss +@use '@cfpb/cfpb-design-system/src/index' as *; +``` + +| | | +| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| **You get** | Full DS component CSS (expandables, lists, button groups, cards, …) and your existing Sass mixins/variables via `@use '…/abstracts'` | +| **You still install** | Both `@cfpb/design-system-react` and `@cfpb/cfpb-design-system` | +| **You do not import** | `@cfpb/design-system-react/index.css` — it duplicates DS rules and embeds fonts a second time | +| **Fonts** | Load Source Sans yourself (for example `@fontsource-variable/source-sans-3` + DS `licensed-font` mixin). DS `dist/index.css` does not include fonts | +| **Best for** | Legacy apps mixing DSR React components with plain DS class names in JSX/SCSS | + +Per-component `@use '@cfpb/cfpb-design-system/src/abstracts'` in your app SCSS is fine — that is Sass API (breakpoints, mixins), not duplicate component CSS. + +### Do not combine Pattern A and Pattern B + +| If you import… | Also import… | Result | +| ------------------------------------- | ----------------------------------------- | ----------------------------------------------------- | +| `@cfpb/design-system-react/index.css` | `@cfpb/cfpb-design-system/dist/index.css` | Duplicate button/form/alert rules; fonts loaded twice | +| `@cfpb/design-system-react/index.css` | `@use '…/src/index'` in Sass | Same duplication | + +DSR React components work with either pattern — they emit standard DS classes. Pattern B apps rely on the app’s global DS stylesheet; Pattern A apps rely on the library’s `index.css`. + +### Choosing a pattern + +| Your situation | Use | +| ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| New React app, Vite/CRA, mostly DSR components | **Pattern A** | +| Existing app with `dist/index.css` or `@use '…/src/index'` in global SCSS | **Pattern B** | +| App uses hand-rolled `.o-expandable`, `.m-list`, `.m-btn-group`, etc. | **Pattern B** (DSR barrel does not include every DS module) | +| Something looks unstyled on Pattern A | Add the DS file to [`ds-components.ts`](src/assets/styles/ds-components.ts) in DSR, or temporarily switch to Pattern B until the barrel is updated | + +### What `ds-components.ts` covers today + +Styles bundled into `@cfpb/design-system-react/index.css` (Pattern A only): + +| React area | DS stylesheet (under `@cfpb/cfpb-design-system/src/components/…`) | +| -------------------------------------------- | --------------------------------------------------------------------------------------------- | +| `Button` | `cfpb-buttons/button`, `cfpb-buttons/button-link` | +| `Heading` (`type="slug"`) | `cfpb-typography/slug-header` | +| `Pagination` | `cfpb-pagination/pagination` | +| Forms (`TextInput`, `Checkbox`, `Select`, …) | `cfpb-forms/form`, `form-field`, `label`, `text-input`, `select`, `multiselect`, `form-alert` | +| `Alert` | `cfpb-notifications/notification` (+ DSR overrides in `alert.scss`) | +| `Table` | `cfpb-tables/table` | +| `Well`, `Divider` | `cfpb-layout/well`, `cfpb-layout/layout` | + +Not in the barrel (Pattern B or future DSR work): expandables, lists, button groups, link typography, hero, cards, and other DS modules. Pattern B apps get these from full DS CSS automatically. + +### Other options (advanced) + +**À la carte Sass** — if you only need buttons and links and already compile SCSS, import specific DS modules instead of full `dist/index.css`: + +```scss +@use '@cfpb/cfpb-design-system/src/base' as base; +@use '@cfpb/cfpb-design-system/src/components/cfpb-buttons/button'; +@use '@cfpb/cfpb-design-system/src/components/cfpb-buttons/button-link'; +@use '@cfpb/cfpb-design-system/src/components/cfpb-typography/link'; +``` + +Load fonts yourself. This is a slimmer alternative to Pattern B when you control exactly which DS patterns you use. See [`ds-components.ts`](src/assets/styles/ds-components.ts) for the library’s curated equivalent on Pattern A. + +**Abstracts/base only** — `@use '…/src/abstracts'` and `@use '…/src/base'` give tokens and global typography, **not** component rules (no `.a-btn`). You still need Pattern A, Pattern B, or à la carte component imports. + +### Quick start (Pattern A — Vite + React) + +```ts +// main.tsx +import '@cfpb/design-system-react/index.css'; +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import App from './App.tsx'; + +createRoot(document.getElementById('root')!).render( + + + , +); +``` + +Ensure `@cfpb/cfpb-design-system` and `lit` are installed even on Pattern A, so peer dependencies and web components resolve correctly. + +### Storybook (contributors) + +Storybook does **not** load prebuilt `dist/index.css`. It compiles the same source stack as Pattern A apps via [`src/assets/styles/entry-styles.ts`](src/assets/styles/entry-styles.ts), imported from [`.storybook/preview.js`](.storybook/preview.js): + +```js +import '../src/assets/styles/entry-styles'; +``` + +| Layer | File | Purpose | +| ------------------ | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- | +| Fonts | `@fontsource-variable/source-sans-3` | Registers `@font-face` in the preview bundle — required for nested “All viewports” iframes (each iframe is a separate document) | +| Tokens + overrides | `_shared.scss` | DS tokens/normalize plus DSR overrides (font stack, `.wrapper--match-content`, docs-tab prose in `#storybook-docs`) | +| Component rules | `ds-components.ts` | DS styles bundled into `dist/index.css` for npm consumers | + +When a component uses Design System class names (for example `.a-btn`, `.m-form-field`), add the matching DS SCSS import to [`ds-components.ts`](src/assets/styles/ds-components.ts). Do not import DS styles from individual component files — the barrel keeps the list in one place. + +**Stories** should import components from their source files (for example `./button`, `../Link/link`), not from `~/src/index`. ESLint enforces this on `*.stories.*` (`no-restricted-imports`). **MDX** overview pages should follow the same rule (not linted — our ESLint setup does not parse MDX reliably). + +Per-component `.scss` files (for example `banner.scss`, `link.scss`) still load when that component is imported. Storybook-only canvas tweaks live in [`.storybook/preview-head.html`](.storybook/preview-head.html). + +### Quick start (Pattern B — existing DS app) + +```js +// App.js — global SCSS already loads DS via base.scss +import './css/App.scss'; +import { Button, Heading } from '@cfpb/design-system-react'; +// Do not import '@cfpb/design-system-react/index.css' +``` + +```scss +// base.scss +@use '@cfpb/cfpb-design-system/src/abstracts' as *; +@use '@cfpb/cfpb-design-system/src/base' as *; +@use '@cfpb/cfpb-design-system/dist/index.css' as *; +``` + ## Development To edit components or add new ones, install dependencies and run Storybook: diff --git a/eslint.config.js b/eslint.config.js index f897c1fa0b..b12a242925 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -10,6 +10,29 @@ import unicorn from 'eslint-plugin-unicorn'; import globals from 'globals'; import tseslint from 'typescript-eslint'; +/** Stories must not import the library barrel — see README “Storybook styles”. */ +const noLibraryBarrelInStories = { + 'no-restricted-imports': [ + 'error', + { + paths: [ + { + name: '~/src/index', + message: + 'Import the component from its source file (e.g. ./button). Global styles load via .storybook/preview.js → entry-styles.ts.', + }, + ], + patterns: [ + { + group: ['~/src/index', '~/src/index.ts'], + message: + 'Import the component from its source file (e.g. ./button). Global styles load via .storybook/preview.js → entry-styles.ts.', + }, + ], + }, + ], +}; + export default tseslint.config( { ignores: [ @@ -97,4 +120,9 @@ export default tseslint.config( '@typescript-eslint/no-explicit-any': 'off', }, }, + // Stories: import components from source, not the library barrel (MDX: same convention; see README). + { + files: ['**/*.stories.ts?(x)'], + rules: noLibraryBarrelInStories, + }, ); diff --git a/src/assets/styles/_shared.scss b/src/assets/styles/_shared.scss index 6e458e8808..48107c9acb 100644 --- a/src/assets/styles/_shared.scss +++ b/src/assets/styles/_shared.scss @@ -11,10 +11,10 @@ */ /** - * Source Sans 3 is loaded via `@fontsource-variable/source-sans-3` in **`src/index.ts`** (apps) - * and **`.storybook/preview.js`** (Storybook, including nested “All viewports” iframes) before - * `_shared.scss` so `@font-face` is always registered. - * + * Source Sans 3 and this file are loaded via **`entry-styles.ts`**, imported from + * **`src/index.ts`** and **`.storybook/preview.js`**, so `@font-face` is always registered + * (including nested “All viewports” Storybook iframes). + * DS component rules load from **`ds-components.ts`** via the same entry. * DS `custom-props` sets `--font-stack-branded: initial`, so `var(--font-stack)` falls back to * `system-ui`. Other DS chunks can repeat that `:root` block when code-split; in dev the last * chunk can win and wipe a non-`!important` override. Pin both tokens with `!important` so inputs, diff --git a/src/assets/styles/ds-components.ts b/src/assets/styles/ds-components.ts new file mode 100644 index 0000000000..42939a4c3c --- /dev/null +++ b/src/assets/styles/ds-components.ts @@ -0,0 +1,44 @@ +/** + * Curated Design System component styles bundled into `dist/index.css`. + * + * When adding a React component that uses DS class names, add the matching DS + * SCSS import here (once per file — duplicates are unnecessary). Component + * `.tsx` files should not import DS styles directly. + * + * Styles listed here are bundled into `dist/index.css` via `entry-styles.ts` and + * loaded in Storybook the same way. + */ + +// Icons — Icon (and any component with .cf-icon-svg) +import '@cfpb/cfpb-design-system/src/components/cfpb-icons/icon.scss'; + +// Buttons — Button +import '@cfpb/cfpb-design-system/src/components/cfpb-buttons/button.scss'; +import '@cfpb/cfpb-design-system/src/components/cfpb-buttons/button-link.scss'; + +// Forms — Checkbox, RadioButton, Fieldset, Label, HelperText, TextInput, +// TextArea, SelectSingle, SelectMulti, AlertFieldLevel +import '@cfpb/cfpb-design-system/src/components/cfpb-forms/form.scss'; +import '@cfpb/cfpb-design-system/src/components/cfpb-forms/form-field.scss'; +import '@cfpb/cfpb-design-system/src/components/cfpb-forms/form-alert.scss'; +import '@cfpb/cfpb-design-system/src/components/cfpb-forms/label.scss'; +import '@cfpb/cfpb-design-system/src/components/cfpb-forms/text-input.scss'; +import '@cfpb/cfpb-design-system/src/components/cfpb-forms/select.scss'; +import '@cfpb/cfpb-design-system/src/components/cfpb-forms/multiselect.scss'; + +// Typography — Heading (type="slug"), Link +import '@cfpb/cfpb-design-system/src/components/cfpb-typography/slug-header.scss'; +import '@cfpb/cfpb-design-system/src/components/cfpb-typography/link.scss'; + +// Layout — Divider (.content__line), Well +import '@cfpb/cfpb-design-system/src/components/cfpb-layout/layout.scss'; +import '@cfpb/cfpb-design-system/src/components/cfpb-layout/well.scss'; + +// Notifications — Alert (page-level) +import '@cfpb/cfpb-design-system/src/components/cfpb-notifications/notification.scss'; + +// Pagination — Pagination +import '@cfpb/cfpb-design-system/src/components/cfpb-pagination/pagination.scss'; + +// Tables — Table +import '@cfpb/cfpb-design-system/src/components/cfpb-tables/table.scss'; diff --git a/src/assets/styles/entry-styles.ts b/src/assets/styles/entry-styles.ts new file mode 100644 index 0000000000..aa4888e68c --- /dev/null +++ b/src/assets/styles/entry-styles.ts @@ -0,0 +1,8 @@ +/** + * Global style entry for library consumers and Storybook. + * + * Imported from `src/index.ts` and `.storybook/preview.js`. Keep both in sync. + */ +import '@fontsource-variable/source-sans-3'; +import './_shared.scss'; +import './ds-components'; diff --git a/src/components/Alert/alert.stories.tsx b/src/components/Alert/alert.stories.tsx index d1f834ec37..4aa03e3819 100644 --- a/src/components/Alert/alert.stories.tsx +++ b/src/components/Alert/alert.stories.tsx @@ -1,6 +1,8 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import type { ReactNode } from 'react'; -import { Alert, AlertFieldLevel, TextInput } from '~/src/index'; +import { Alert } from './alert'; +import { AlertFieldLevel } from './alert-field-level'; +import { TextInput } from '../TextInput/text-input'; const meta: Meta = { title: 'Components (Draft)/Alerts', diff --git a/src/components/Banner/banner.stories.tsx b/src/components/Banner/banner.stories.tsx index d1cd9fe011..49966bd433 100644 --- a/src/components/Banner/banner.stories.tsx +++ b/src/components/Banner/banner.stories.tsx @@ -1,6 +1,6 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import type { ReactNode, SyntheticEvent } from 'react'; -import { Banner } from '~/src/index'; +import { Banner } from './banner'; import { AllLanguageCodes, LanguageLink } from './banner-language-link'; const meta: Meta = { diff --git a/src/components/Breadcrumb/breadcrumb.stories.tsx b/src/components/Breadcrumb/breadcrumb.stories.tsx index 699479cf91..3159901a16 100644 --- a/src/components/Breadcrumb/breadcrumb.stories.tsx +++ b/src/components/Breadcrumb/breadcrumb.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Breadcrumb } from '~/src/index'; +import { Breadcrumb } from './breadcrumb'; const meta: Meta = { title: 'Components (Draft)/Breadcrumbs', diff --git a/src/components/Buttons/buttons.stories.tsx b/src/components/Buttons/buttons.stories.tsx index 62e2cc842f..0097e526f4 100644 --- a/src/components/Buttons/buttons.stories.tsx +++ b/src/components/Buttons/buttons.stories.tsx @@ -1,6 +1,7 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import { expect, fn, userEvent, within } from 'storybook/test'; -import { Button, Link } from '~/src/index'; +import { Button } from './button'; +import Link from '../Link/link'; import { ButtonGroup } from './button-group'; /** diff --git a/src/components/Checkbox/checkbox-overview.mdx b/src/components/Checkbox/checkbox-overview.mdx index 618257cbe9..f18c157b68 100644 --- a/src/components/Checkbox/checkbox-overview.mdx +++ b/src/components/Checkbox/checkbox-overview.mdx @@ -1,6 +1,9 @@ {/* NOTE: Do NOT use auto-formatting on this MDX's. Otherwise MDX creates extra

elements per line */} import { Meta } from '@storybook/addon-docs/blocks'; -import { List, Link, ListLink, Heading, Paragraph } from '~/src/index'; +import { Heading } from '../Headings/heading'; +import Link, { ListLink } from '../Link/link'; +import List from '../List/list'; +import { Paragraph } from '../Paragraph/paragraph'; diff --git a/src/components/Divider/divider.stories.tsx b/src/components/Divider/divider.stories.tsx index 2131227d19..1c6f2a0739 100644 --- a/src/components/Divider/divider.stories.tsx +++ b/src/components/Divider/divider.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Divider } from '~/src/index'; +import { Divider } from './divider'; const meta: Meta = { title: 'Components (Draft)/Dividers', diff --git a/src/components/Expandable/expandable.stories.tsx b/src/components/Expandable/expandable.stories.tsx index 7f324f06ea..c5d103b7a4 100644 --- a/src/components/Expandable/expandable.stories.tsx +++ b/src/components/Expandable/expandable.stories.tsx @@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import type { ComponentProps } from 'react'; import { JSX } from 'react'; import { expect, userEvent, waitFor, within } from 'storybook/test'; -import { Expandable } from '~/src/index'; +import { Expandable } from './expandable'; import { sleep } from '../../utils/sleep'; // This is the expandable group diff --git a/src/components/Fieldset/fieldset.stories.tsx b/src/components/Fieldset/fieldset.stories.tsx index 87ecf52e36..ba580ae81a 100644 --- a/src/components/Fieldset/fieldset.stories.tsx +++ b/src/components/Fieldset/fieldset.stories.tsx @@ -1,6 +1,8 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import { expect, userEvent, waitFor, within } from 'storybook/test'; -import { Checkbox, Fieldset, RadioButton } from '~/src/index'; +import { Checkbox } from '../Checkbox/checkbox'; +import { Fieldset } from './fieldset'; +import { RadioButton } from '../RadioButton/radio-button'; /** * diff --git a/src/components/Grid/grid.stories.tsx b/src/components/Grid/grid.stories.tsx index 5bc7f63e1a..03b14d0f7a 100644 --- a/src/components/Grid/grid.stories.tsx +++ b/src/components/Grid/grid.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Grid } from '~/src/index'; +import Grid from './index'; const meta: Meta = { title: 'Components (Draft)/Grids', diff --git a/src/components/Header/header.stories.tsx b/src/components/Header/header.stories.tsx index 717432e302..746f1de955 100644 --- a/src/components/Header/header.stories.tsx +++ b/src/components/Header/header.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Header } from '~/src/index'; +import { Header } from './header'; import { ExampleLinks } from './responsive-menu'; const meta: Meta = { diff --git a/src/components/Header/responsive-menu.scss b/src/components/Header/responsive-menu.scss index 0814864f38..c6d574d2c0 100644 --- a/src/components/Header/responsive-menu.scss +++ b/src/components/Header/responsive-menu.scss @@ -154,6 +154,7 @@ $max-width: $bp-sm-max; margin-right: 0; padding: 10px 0; text-align: left; + // no underline when in menu .a-link__text { text-decoration: none; diff --git a/src/components/Headings/heading.test.tsx b/src/components/Headings/heading.test.tsx index 603c31520f..30e0cb8d5a 100644 --- a/src/components/Headings/heading.test.tsx +++ b/src/components/Headings/heading.test.tsx @@ -89,10 +89,10 @@ describe('', () => { expect(wrapper).toBeInTheDocument(); expect(wrapper.tagName.toLowerCase()).toBe('header'); - expect(wrapper.classList.contains('m-slug-header')); + expect(wrapper.classList.contains('m-slug-header')).toBeTruthy(); const content = screen.getByText(text); expect(content.tagName.toLowerCase()).toBe('h2'); - expect(content.classList.contains('a-heading')); + expect(content.classList.contains('m-slug-header__heading')).toBeTruthy(); }); }); diff --git a/src/components/Headings/headings.stories.tsx b/src/components/Headings/headings.stories.tsx index 1a54e83e33..a25ae983c4 100644 --- a/src/components/Headings/headings.stories.tsx +++ b/src/components/Headings/headings.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Heading } from '~/src/index'; +import { Heading } from './heading'; import { expect, within } from 'storybook/test'; /** * A successful type hierarchy establishes the order of importance of elements on a page. Consistent scaling, weights, and capitalization are used to create distinction between headings and provide users with familiar focus points when scanning text. @@ -97,4 +97,18 @@ export const Slug: Story = { type: 'slug', children: 'Slug', }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const slugHeading = canvas.getByRole('heading', { + level: 2, + name: /slug/i, + }); + + await expect(slugHeading.classList.contains('m-slug-header__heading')).toBe( + true, + ); + await expect( + slugHeading.closest('header')?.classList.contains('m-slug-header'), + ).toBe(true); + }, }; diff --git a/src/components/Hero/hero.stories.tsx b/src/components/Hero/hero.stories.tsx index 3d7b235357..73d0df48ac 100644 --- a/src/components/Hero/hero.stories.tsx +++ b/src/components/Hero/hero.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Hero } from '~/src/index'; +import Hero from './hero'; const meta: Meta = { title: 'Components (Draft)/Heroes', diff --git a/src/components/Icon/icon.stories.tsx b/src/components/Icon/icon.stories.tsx index bf13d4829d..edc6985cda 100644 --- a/src/components/Icon/icon.stories.tsx +++ b/src/components/Icon/icon.stories.tsx @@ -1,7 +1,8 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import { JSX } from 'react'; import type { ReactElement } from 'react'; -import { Heading, Icon } from '~/src/index'; +import { Heading } from '../Headings/heading'; +import { Icon } from './icon'; import type { HeadingType } from '../Headings/heading'; import { communicationIcons, diff --git a/src/components/Label/label.stories.tsx b/src/components/Label/label.stories.tsx index f24f2d8799..0b4eada1d8 100644 --- a/src/components/Label/label.stories.tsx +++ b/src/components/Label/label.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Label } from '~/src/index'; +import { Label } from './label'; import { TextInput } from '../TextInput/text-input'; const meta: Meta = { diff --git a/src/components/Layout/layout-content.stories.tsx b/src/components/Layout/layout-content.stories.tsx index 48f42abed0..7220485dc2 100644 --- a/src/components/Layout/layout-content.stories.tsx +++ b/src/components/Layout/layout-content.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Layout } from '~/src/index'; +import Layout from './layout'; const meta: Meta = { title: 'Components (Draft)/Layout/Content', diff --git a/src/components/Layout/layout-main.stories.tsx b/src/components/Layout/layout-main.stories.tsx index b570597409..9846db3172 100644 --- a/src/components/Layout/layout-main.stories.tsx +++ b/src/components/Layout/layout-main.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Layout } from '~/src/index'; +import Layout from './layout'; const meta: Meta = { title: 'Components (Draft)/Layout/Main', diff --git a/src/components/Layout/layout-sidebar.stories.tsx b/src/components/Layout/layout-sidebar.stories.tsx index c17026ab43..4c1474be70 100644 --- a/src/components/Layout/layout-sidebar.stories.tsx +++ b/src/components/Layout/layout-sidebar.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Layout } from '~/src/index'; +import Layout from './layout'; const meta: Meta = { title: 'Components (Draft)/Layout/Sidebar', diff --git a/src/components/Layout/layout-wrapper.stories.tsx b/src/components/Layout/layout-wrapper.stories.tsx index bfbd58278d..a16357aa30 100644 --- a/src/components/Layout/layout-wrapper.stories.tsx +++ b/src/components/Layout/layout-wrapper.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Layout } from '~/src/index'; +import Layout from './layout'; const meta: Meta = { title: 'Components (Draft)/Layout/Wrapper', diff --git a/src/components/Link/link.stories.tsx b/src/components/Link/link.stories.tsx index f819e26ac6..8a1b56bffe 100644 --- a/src/components/Link/link.stories.tsx +++ b/src/components/Link/link.stories.tsx @@ -1,7 +1,9 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import { BrowserRouter } from 'react-router'; import { expect, within } from 'storybook/test'; -import { Heading, Link, List, ListLink } from '~/src/index'; +import { Heading } from '../Headings/heading'; +import Link, { ListLink } from './link'; +import List from '../List/list'; const meta: Meta = { title: 'Components (Verified)/Links', diff --git a/src/components/List/list.stories.tsx b/src/components/List/list.stories.tsx index 4dbeaee49a..334335a763 100644 --- a/src/components/List/list.stories.tsx +++ b/src/components/List/list.stories.tsx @@ -1,5 +1,7 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Link, List, ListItem } from '~/src/index'; +import Link from '../Link/link'; +import List from './list'; +import ListItem from './list-item'; const meta: Meta = { title: 'Components (Draft)/Lists', diff --git a/src/components/Pagination/pagination.stories.tsx b/src/components/Pagination/pagination.stories.tsx index 6cec95faa9..4938e23d40 100644 --- a/src/components/Pagination/pagination.stories.tsx +++ b/src/components/Pagination/pagination.stories.tsx @@ -1,7 +1,8 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import { JSX } from 'react'; import { expect, fn, userEvent, within } from 'storybook/test'; -import { Pagination, usePagination } from '~/src/index'; +import { Pagination } from './pagination'; +import { usePagination } from './use-pagination'; import { generateTestRows, stringify } from './pagination.story-utils'; const meta: Meta = { diff --git a/src/components/Pagination/pagination.tsx b/src/components/Pagination/pagination.tsx index 7746c6ff98..01965e0147 100644 --- a/src/components/Pagination/pagination.tsx +++ b/src/components/Pagination/pagination.tsx @@ -1,4 +1,3 @@ -import '@cfpb/cfpb-design-system/src/components/cfpb-pagination/pagination.scss'; import type { ChangeEvent, FormEvent, ReactElement } from 'react'; import { JSX, useEffect, useId, useState } from 'react'; import { Button } from '../Buttons/button'; diff --git a/src/components/RadioButton/radio-button.stories.tsx b/src/components/RadioButton/radio-button.stories.tsx index d7f83ec6a4..2f0c13ff33 100644 --- a/src/components/RadioButton/radio-button.stories.tsx +++ b/src/components/RadioButton/radio-button.stories.tsx @@ -1,6 +1,6 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import { expect, userEvent, waitFor, within } from 'storybook/test'; -import { RadioButton } from '~/src/index'; +import { RadioButton } from './radio-button'; /** * Use radio buttons when the user can select exactly one option from a group. Avoid long lists of radio buttons (usually no more than 6-8 options). When there are more than two options, stack radio buttons vertically. Use [checkboxes](https://cfpb.github.io/design-system/components/checkboxes) when the user can select more than one option from a group. diff --git a/src/components/Select/select-multi.stories.tsx b/src/components/Select/select-multi.stories.tsx index 22eafa39c4..ecce1cdb12 100644 --- a/src/components/Select/select-multi.stories.tsx +++ b/src/components/Select/select-multi.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Select } from '~/src/index'; +import Select from './select'; import { MultipleSelectOptions } from './test-utils'; const meta: Meta = { diff --git a/src/components/Select/select-overview.mdx b/src/components/Select/select-overview.mdx index 6c4006c470..23235f95f4 100644 --- a/src/components/Select/select-overview.mdx +++ b/src/components/Select/select-overview.mdx @@ -1,5 +1,8 @@ import { Meta } from '@storybook/addon-docs/blocks'; -import { Heading, Link, List, ListLink, Paragraph } from '~/src/index'; +import { Heading } from '../Headings/heading'; +import Link, { ListLink } from '../Link/link'; +import List from '../List/list'; +import { Paragraph } from '../Paragraph/paragraph'; diff --git a/src/components/Select/select.stories.tsx b/src/components/Select/select.stories.tsx index 9abdde407b..ac3104bcf4 100644 --- a/src/components/Select/select.stories.tsx +++ b/src/components/Select/select.stories.tsx @@ -1,6 +1,7 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import { JSX, useState } from 'react'; -import { Select, SelectSingle } from '~/src/index'; +import Select from './select'; +import { SelectSingle } from './select-single'; import type { SelectOption, SelectProperties } from './select'; import { SingleSelectOptions } from './test-utils'; diff --git a/src/components/Table/table.stories.tsx b/src/components/Table/table.stories.tsx index ed74c26905..679a52ec85 100644 --- a/src/components/Table/table.stories.tsx +++ b/src/components/Table/table.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Table } from '~/src/index'; +import { Table } from './table'; import { ONE } from '../Pagination/use-pagination'; const meta: Meta = { diff --git a/src/components/TextInput/text-input-overview.mdx b/src/components/TextInput/text-input-overview.mdx index edee6a094d..32f27a9684 100644 --- a/src/components/TextInput/text-input-overview.mdx +++ b/src/components/TextInput/text-input-overview.mdx @@ -1,5 +1,8 @@ import { Meta } from '@storybook/addon-docs/blocks'; -import { List, Link, ListLink, Heading, Paragraph } from '~/src/index'; +import { Heading } from '../Headings/heading'; +import Link, { ListLink } from '../Link/link'; +import List from '../List/list'; +import { Paragraph } from '../Paragraph/paragraph'; Text inputs diff --git a/src/components/TextInput/text-input.stories.tsx b/src/components/TextInput/text-input.stories.tsx index 8c9b56e988..6d71e2fee5 100644 --- a/src/components/TextInput/text-input.stories.tsx +++ b/src/components/TextInput/text-input.stories.tsx @@ -1,7 +1,9 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import { useState } from 'react'; import { expect, userEvent, within } from 'storybook/test'; -import { Button, Icon, TextInput } from '~/src/index'; +import { Button } from '../Buttons/button'; +import { Icon } from '../Icon/icon'; +import { TextInput } from './text-input'; import type { TextInputProperties } from './text-input'; const meta: Meta = { diff --git a/src/components/TextIntroduction/text-introduction.stories.tsx b/src/components/TextIntroduction/text-introduction.stories.tsx index ad6e996101..3d48cf95b5 100644 --- a/src/components/TextIntroduction/text-introduction.stories.tsx +++ b/src/components/TextIntroduction/text-introduction.stories.tsx @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { List, TextIntroduction } from '~/src/index'; +import List from '../List/list'; +import TextIntroduction from './text-introduction'; import { callToAction, description, diff --git a/src/index.ts b/src/index.ts index 9a7d7dec82..9bf5efb15b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,4 @@ -import '@fontsource-variable/source-sans-3'; -import './assets/styles/_shared.scss'; +import './assets/styles/entry-styles'; export { Alert } from './components/Alert/alert'; export { AlertFieldLevel } from './components/Alert/alert-field-level'; diff --git a/src/stories/Introduction.mdx b/src/stories/Introduction.mdx index 74b43bb85e..c6ac648243 100644 --- a/src/stories/Introduction.mdx +++ b/src/stories/Introduction.mdx @@ -1,5 +1,6 @@ import { Meta } from '@storybook/addon-docs/blocks'; -import { Icon, Heading } from '~/src/index'; +import { Icon } from '../components/Icon/icon'; +import { Heading } from '../components/Headings/heading'; import Code from './assets/code-brackets.svg'; import Colors from './assets/colors.svg'; import Comments from './assets/comments.svg';