Skip to content

Commit 813071a

Browse files
Merge pull request #3 from NHSDigital/feature/migration-from-fergusbisset
Feature/migration from fergusbisset
2 parents 668f948 + 34eda00 commit 813071a

File tree

2,397 files changed

+387495
-81
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

2,397 files changed

+387495
-81
lines changed

.github/copilot-instructions.md

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
# NHS FDP Design System
2+
3+
NHS FDP Design System is a comprehensive React component library with TypeScript, design tokens, Storybook documentation, and comprehensive testing infrastructure. It uses Vite for building, Vitest for testing, and Style Dictionary for design token generation.
4+
5+
**ALWAYS follow these instructions first. Only search for additional information if these instructions are incomplete or incorrect.**
6+
7+
## Working Effectively
8+
9+
### Bootstrap and Build
10+
- Install dependencies: `npm install` (takes ~1 minute)
11+
- Build design tokens: `npm run build:tokens:smart` (usually instantaneous if unchanged)
12+
- **Full build process**: `npm run build:parity`
13+
- **TIMING**: Takes ~33 seconds. NEVER CANCEL. Set timeout to 120+ seconds.
14+
- This runs: clean dist → tokens → multi build → ESM/UMD builds → CSS compilation → component JS → types → verification
15+
- **Quick build** (development): `npm run build:fast` (faster iteration, ~7 seconds)
16+
- **Type checking only**: `npm run typecheck` (~2 seconds)
17+
18+
### Development Workflow
19+
- **Storybook development**: `npm run storybook`
20+
- Starts at http://localhost:6006
21+
- **TIMING**: Loads in ~6 seconds. NEVER CANCEL. Set timeout to 60+ seconds.
22+
- Provides comprehensive component library with docs and testing
23+
- **Vite dev server**: `npm run dev`
24+
- Starts at http://localhost:5173 (~1 second)
25+
- For demo/example development
26+
- **Clean build artifacts**: `npm run clean:dist`
27+
28+
### Testing Infrastructure
29+
- **Component tests**: `npm run test:components`
30+
- **TIMING**: Takes ~4 minutes, ~1000 tests. NEVER CANCEL. Set timeout to 300+ seconds.
31+
- Uses Vitest and React Testing Library and JSDOM
32+
- One expected test failure in AriaTabsDataGrid (aria-describedby assertion)
33+
- **SSR tests**: `npm run test:ssr-components`
34+
- **TIMING**: Takes ~5 seconds, 153 tests. Set timeout to 30+ seconds.
35+
- Tests server-side rendering compatibility
36+
- **Smoke tests**: `npm run test:smoke` (~2 seconds, basic functionality check)
37+
- **Watch mode**: `npm run test:watch` (for development)
38+
39+
### Build for Production
40+
- **Storybook build**: `npm run build-storybook`
41+
- **TIMING**: Takes ~36 seconds. NEVER CANCEL. Set timeout to 120+ seconds.
42+
- Outputs to `storybook-static/`
43+
44+
### Code Quality
45+
- **Linting**: `npm run lint`
46+
- **CURRENT STATE**: 5 unused eslint-disable directive errors (non-blocking)
47+
- **TIMING**: ~5 seconds. Set timeout to 30+ seconds.
48+
- ALWAYS run `npm run lint` before committing changes
49+
- **Type checking**: `npm run typecheck` (~2 seconds)
50+
51+
## Validation Scenarios
52+
53+
### ALWAYS Test After Changes
54+
1. **Build validation**: Run `npm run build:parity` to ensure all builds succeed
55+
2. **Component testing**: Run `npm run test:components` for comprehensive test coverage
56+
3. **SSR compatibility**: Run `npm run test:ssr-components` for server-side rendering
57+
4. **Code quality**: Run `npm run lint` and `npm run typecheck`
58+
59+
### Manual Testing Scenarios
60+
1. **Storybook functionality**:
61+
- Start with `npm run storybook`
62+
- Navigate to multiple component stories
63+
- Verify components render and interact correctly
64+
- Test different variants and props
65+
2. **Component accessibility**:
66+
- Use Storybook's accessibility addon
67+
- Test keyboard navigation
68+
Built with Style Dictionary (source definitions → generated SCSS & TS in `packages/nhs-fdp/dist/`)
69+
Smart build: `npm run build:tokens:smart` (skips when source hash unchanged) – ALWAYS prefer in incremental builds
70+
Force rebuild: `npm run build:tokens` (full Style Dictionary run and post-processing script)
71+
Outputs (do not hand edit):
72+
* SCSS: `packages/nhs-fdp/dist/scss/_tokens.scss` (master), plus categorical files (`_colors.scss`, `_spacing.scss`, etc.)
73+
* Component-specific token bundles in `packages/nhs-fdp/dist/scss/components/`
74+
* (If configured) TypeScript constants (search for `dist/**/tokens.*.ts` if needed)
75+
Consumption pattern in component SCSS: ALWAYS import the aggregated SCSS entry and reference variables via the `nhs.` namespace.
76+
77+
78+
### Key Directories
79+
- `src/components/` - React components (55+ components)
80+
- `src/styles/` - Global styles and font configuration
81+
- `src/tokens/` - Design token definitions
82+
- `config/` - Build and test configurations
83+
- `scripts/` - Build automation and verification scripts
84+
- `docs/` - Comprehensive documentation
85+
- `tests/` - SSR analysis and specialized tests
86+
87+
### Component Structure
88+
Each component follows a standardized pattern:
89+
- `Component.tsx` - Main component
90+
- `Component.types.ts` - TypeScript interfaces
91+
- `Component.scss` - Component styles
92+
93+
- `Component.stories.tsx` - Storybook documentation
94+
- `Component.client.test.tsx` - Interactive behavior tests
95+
- `Component.ssr.test.tsx` - Server-side rendering tests
96+
- `Component.hydration.test.tsx` - SSR to client hydration tests
97+
- `Component.a11y.test.tsx` - Accessibility tests (some components)
98+
99+
### Testing Strategy (Critical)
100+
Follow the established 3-tier testing pattern:
101+
102+
- **Client tests**: Interactive behavior, events, keyboard, accessibility
103+
- **SSR tests**: Structural output, roles, semantics, conditional rendering
104+
- **Hydration tests**: SSR → client integrity and post-hydration interaction
105+
106+
Use React Testing Library query priority:
107+
1. `getByRole` (with `name` option)
108+
109+
2. `getByLabelText`
110+
3. `getByPlaceholderText`
111+
4. `getByText` (scoped, exact)
112+
5. `getByTestId` (only when no semantic alternative)
113+
114+
### Design Token System
115+
116+
- Built with Style Dictionary
117+
- Smart building: `npm run build:tokens:smart` (skips if unchanged)
118+
- Full rebuild: `npm run build:tokens`
119+
- Outputs CSS custom properties, SCSS variables, and TypeScript constants
120+
121+
### Package Publishing
122+
- **GitHub Packages**: Requires `.npmrc` configuration with GitHub token
123+
- **Build before publish**: Always run `npm run build:parity`
124+
- **Version management**: Use `npm run release:patch|minor|major|prerelease`
125+
126+
127+
## Common Tasks
128+
129+
### Adding New Components
130+
1. Create component directory in `src/components/`
131+
2. Follow established file structure (see Component Structure above)
132+
3. Add component to `src/components/index.ts`
133+
4. Create comprehensive tests (client/SSR/hydration)
134+
135+
5. Add Storybook stories with documentation
136+
6. Run full build and test suite
137+
7. Update package.json exports if needed
138+
139+
### Modifying Existing Components
140+
141+
1. Update component files as needed
142+
2. Update corresponding tests to match changes
143+
3. Update Storybook stories if behavior changes
144+
4. Run `npm run test:components` to verify no regression
145+
5. Run `npm run build:parity` to ensure builds succeed
146+
6. Test manually in Storybook
147+
148+
### Working with Design Tokens
149+
1. Modify token files in appropriate config directory
150+
2. Run `npm run build:tokens` to regenerate
151+
3. Test components that use modified tokens
152+
4. Verify CSS output in `dist/` after full build
153+
154+
### Troubleshooting Build Issues
155+
- **Token build fails**: Check Style Dictionary config files
156+
- **Component JS build fails**: Check individual component exports
157+
- **Type build fails**: Run `npm run typecheck` for detailed errors
158+
- **CSS build fails**: Check SCSS imports and token references
159+
- **Verification fails**: Check package.json exports alignment
160+
161+
## SSR Compatibility
162+
163+
### Current State (as of latest analysis)
164+
- **Total components**: 149
165+
- **SSR compatibility**: 92% overall
166+
- **Fully compatible**: 135 components (91%)
167+
- **Compatible with hydration**: 3 components (2%)
168+
- **Client-only**: 1 component (1%)
169+
- **Requires refactoring**: 10 components (7%)
170+
171+
### SSR Analysis Tool
172+
- Run: `npm run analyze:ssr` (~1 second)
173+
- Generates detailed reports in `ssr-analysis-report/`
174+
- Identifies blocking issues and provides automated fixes
175+
- Use for impact assessment when modifying components
176+
177+
### Critical SSR Guidelines
178+
- Avoid direct `document` or `window` access in component rendering
179+
- Use conditional rendering for client-only features
180+
- Test SSR compatibility with `npm run test:ssr-components`
181+
- Components should render meaningful content server-side
182+
183+
## Performance Expectations
184+
185+
### Build Times (Set appropriate timeouts)
186+
- `npm install`: ~60 seconds
187+
- `npm run build:parity`: ~33 seconds (NEVER CANCEL - timeout 120+ seconds)
188+
- `npm run test:components`: ~240 seconds (NEVER CANCEL - timeout 300+ seconds)
189+
- `npm run build-storybook`: ~36 seconds (NEVER CANCEL - timeout 120+ seconds)
190+
- `npm run storybook`: ~6 seconds startup (NEVER CANCEL - timeout 60+ seconds)
191+
- `npm run lint`: ~5 seconds
192+
- `npm run test:ssr-components`: ~5 seconds
193+
- `npm run analyze:ssr`: ~1 second
194+
195+
### Known Issues
196+
- **Node version**: Style Dictionary requires Node 22+, currently using Node 20 (non-blocking warning)
197+
- **Linting**: 5 unused eslint-disable directive errors (non-blocking)
198+
- **Test failure**: 1 minor AriaTabsDataGrid aria-describedby test failure (non-blocking)
199+
200+
## Distribution and Dependencies
201+
202+
### GitHub Packages Setup
203+
The package is published to GitHub Packages. To install:
204+
1. Create `.npmrc` with:
205+
```
206+
@fergusbisset:registry=https://npm.pkg.github.com
207+
//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN
208+
```
209+
2. Verify setup: `npm whoami --registry=https://npm.pkg.github.com`
210+
211+
### Key Dependencies
212+
- **React 19** and TypeScript
213+
- **Vite 7** for building
214+
- **Vitest 3** for testing
215+
- **Storybook 9** for documentation
216+
- **Style Dictionary 5** for design tokens
217+
- **React Aria** for accessible interactions
218+
- **D3** for data visualization components
219+
220+
ALWAYS reference these instructions and fallback to bash commands or search only when information is missing or incorrect.

.github/dependabot.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
version: 2
2+
updates:
3+
# Enable version updates for npm
4+
- package-ecosystem: "npm"
5+
directory: "/"
6+
schedule:
7+
interval: "weekly"
8+
day: "monday"
9+
time: "09:00"
10+
# Limit number of open PRs to avoid overwhelming maintainers
11+
open-pull-requests-limit: 10
12+
# Add labels for easy filtering
13+
labels:
14+
- "dependencies"
15+
- "automated"
16+
# Group minor and patch updates together to reduce PR noise
17+
groups:
18+
development-dependencies:
19+
dependency-type: "development"
20+
update-types:
21+
- "minor"
22+
- "patch"
23+
production-dependencies:
24+
dependency-type: "production"
25+
update-types:
26+
- "patch"
27+
# Assign PRs to maintainer
28+
assignees:
29+
- "fergusbisset"
30+
# Increase pull request limit for security updates
31+
# Security updates are always created separately
32+
versioning-strategy: increase
33+
# Allow Dependabot to rebase PRs
34+
rebase-strategy: "auto"
35+
36+
# Monitor GitHub Actions for updates
37+
- package-ecosystem: "github-actions"
38+
directory: "/"
39+
schedule:
40+
interval: "weekly"
41+
day: "monday"
42+
labels:
43+
- "dependencies"
44+
- "github-actions"
45+
assignees:
46+
- "fergusbisset"
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
name: Publish to GitHub Packages
2+
3+
on:
4+
release:
5+
types: [published]
6+
workflow_dispatch:
7+
inputs:
8+
version:
9+
description: 'Optional semver bump to apply before publishing (patch, minor, major, prerelease)'
10+
required: false
11+
type: string
12+
preid:
13+
description: 'Prerelease identifier when version is prerelease (e.g., alpha, beta, rc)'
14+
required: false
15+
type: string
16+
tag:
17+
description: 'NPM dist-tag to publish under (e.g., latest, alpha, beta, next)'
18+
required: false
19+
default: 'latest'
20+
type: string
21+
22+
permissions:
23+
contents: write
24+
packages: write
25+
26+
jobs:
27+
publish:
28+
runs-on: ubuntu-latest
29+
steps:
30+
- name: Checkout
31+
uses: actions/checkout@v4
32+
33+
- name: Setup Node for GitHub Packages
34+
uses: actions/setup-node@v4
35+
with:
36+
node-version: 20
37+
registry-url: 'https://npm.pkg.github.com'
38+
scope: '@nhsdigital'
39+
40+
- name: Install dependencies
41+
run: npm ci
42+
43+
- name: Optionally bump version (manual dispatch only)
44+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.version != '' }}
45+
run: |
46+
git config user.name github-actions
47+
git config user.email [email protected]
48+
if [ "${{ inputs.version }}" = "prerelease" ]; then
49+
npm version prerelease --preid=${{ inputs.preid || 'alpha' }} -m "chore(release): %s"
50+
else
51+
npm version ${{ inputs.version }} -m "chore(release): %s"
52+
fi
53+
54+
- name: Run tests
55+
run: |
56+
npm run lint
57+
npm run test:components
58+
npm run test:ssr-components
59+
60+
- name: Build
61+
run: npm run build
62+
63+
- name: Publish to GitHub Packages
64+
env:
65+
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
66+
run: |
67+
if [ -n "${{ inputs.tag }}" ] && [ "${{ inputs.tag }}" != "latest" ]; then
68+
npm publish --registry=https://npm.pkg.github.com --tag ${{ inputs.tag }}
69+
else
70+
npm publish --registry=https://npm.pkg.github.com
71+
fi
72+
73+
- name: Push version bump (when version bumped)
74+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.version != '' }}
75+
run: |
76+
VERSION=$(node -p "require('./package.json').version")
77+
git push origin HEAD
78+
git tag v$VERSION
79+
git push origin v$VERSION
80+
81+
- name: Summary
82+
run: |
83+
VERSION=$(node -p "require('./package.json').version")
84+
echo "Published @nhsdigital/fdp-design-system@$VERSION to GitHub Packages" >> $GITHUB_STEP_SUMMARY
85+
echo "" >> $GITHUB_STEP_SUMMARY
86+
echo "Install with:" >> $GITHUB_STEP_SUMMARY
87+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
88+
echo "npm install @nhsdigital/fdp-design-system --registry=https://npm.pkg.github.com" >> $GITHUB_STEP_SUMMARY
89+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY

0 commit comments

Comments
 (0)