Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8676bf4
Remove mostly duplicate `:ci` npm scripts
colinrotherham Oct 6, 2025
485956b
Split out ESLint only `lint:js` npm script
colinrotherham Oct 6, 2025
21b775b
Split out TypeScript only `lint:types` npm script
colinrotherham Oct 6, 2025
4109f7d
Split out Prettier only `lint:prettier` npm script
colinrotherham Oct 6, 2025
f4f5acb
Enable Prettier `"quoteProps": "consistent"`
colinrotherham Oct 6, 2025
fa0583c
Update to ESLint v9
colinrotherham Oct 3, 2025
6473ba7
Enable ESLint editor validation for JSX
colinrotherham Oct 3, 2025
933e48d
Remove ESLint rules we should fix instead
colinrotherham Oct 3, 2025
5e3be37
Turn off ESLint rules handled by TypeScript
colinrotherham Oct 6, 2025
4b087d3
Fix ESLint "Cannot reassign variables declared outside of the compone…
colinrotherham Oct 6, 2025
b7719fe
Fix ESLint missing React hook dependencies
colinrotherham Oct 3, 2025
7312da4
Fix ESLint unnecessary disable comments
colinrotherham Oct 6, 2025
55c0933
Fix ESLint remaining issues
colinrotherham Oct 6, 2025
df2ef3e
Fix missing lodash package
colinrotherham Oct 7, 2025
5069930
Upgrade to latest Yarn stable
colinrotherham Oct 7, 2025
2d4cd4d
Upgrade TypeScript with resolutions
colinrotherham Oct 7, 2025
4b72027
Require React v18.2 minimum version
colinrotherham Oct 6, 2025
e92a71f
Upgrade to React v19
colinrotherham Oct 7, 2025
0dc68ed
Upgrade to React v19 compatible packages
colinrotherham Oct 7, 2025
629cc59
Restore `'use client'` for Next.js
colinrotherham Oct 6, 2025
2bcc3a0
Merge pull request #273 from NHSDigital/react
colinrotherham Oct 7, 2025
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
4 changes: 0 additions & 4 deletions .eslintignore

This file was deleted.

43 changes: 0 additions & 43 deletions .eslintrc.cjs

This file was deleted.

4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ jobs:
- name: Yarn Install
run: yarn
- name: Lint
run: yarn lint:ci
run: yarn lint
- name: Jest Tests
run: yarn test:ci
run: yarn test --coverage
- name: Typescript build
run: yarn build
- name: Storybook build
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ jobs:
run: yarn

- name: Lint
run: yarn lint:ci
run: yarn lint

- name: Jest Tests
run: yarn test:ci
run: yarn test --coverage

- name: Typescript build
run: yarn build
Expand Down
12 changes: 12 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Node.js modules
node_modules/

# Test coverage
coverage/

# Build output
dist/

# Files to ignore
.yarnrc.yml
package-lock.json
7 changes: 4 additions & 3 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"printWidth": 100,
"quoteProps": "consistent",
"semi": true,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2
"tabWidth": 2,
"trailingComma": "all"
}
2 changes: 1 addition & 1 deletion .storybook/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const sentenceCase = (name = '') => {

addons.setConfig({
sidebar: {
renderLabel: ({ name, type }) => sentenceCase(name),
renderLabel: ({ name }) => sentenceCase(name),
},
theme: nhsTheme,
});
1 change: 1 addition & 0 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ const preview: Preview = {
},
},
};

export default preview;
4 changes: 2 additions & 2 deletions .storybook/theme.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { create } from '@storybook/theming/create';
const version = require('../package.json').version;
import packageJson from '../package.json' with { type: 'json' };

export default create({
base: 'light',
Expand Down Expand Up @@ -31,6 +31,6 @@ export default create({
inputTextColor: '#212b32',
inputBorderRadius: 4,

brandTitle: `NHS.UK React Components (v${version})`,
brandTitle: `NHS.UK React Components (v${packageJson.version})`,
brandUrl: 'https://github.com/NHSDigital/nhsuk-react-components',
});
4 changes: 1 addition & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@
"source.fixAll": "explicit",
"source.fixAll.eslint": "explicit"
},
"eslint.validate": ["javascript", "typescript"],
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
"eslint.codeAction.showDocumentation": {
"enable": true
},
"eslint.alwaysShowStatus": true,
"eslint.workingDirectories": ["src"],
"typescript.tsdk": "node_modules/typescript/lib"
}
22 changes: 21 additions & 1 deletion .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,22 @@
nodeLinker: node-modules
npmRegistryServer: https://registry.yarnpkg.com

npmRegistryServer: "https://registry.yarnpkg.com"

packageExtensions:
"@storybook/addon-docs@*":
peerDependencies:
"@types/react": "*"
"@types/react-dom": "*"

"@storybook/addon-essentials@*":
peerDependencies:
"@types/react": "*"
"@types/react-dom": "*"

"@storybook/core@*":
peerDependencies:
storybook: "*"

"@storybook/react-vite@*":
peerDependencies:
typescript: "*"
103 changes: 103 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { join } from 'node:path';
import configPrettier from 'eslint-config-prettier/flat';
import pluginReact from 'eslint-plugin-react';
import pluginReactHooks from 'eslint-plugin-react-hooks';
import eslint from '@eslint/js';
import pluginJsxA11y from 'eslint-plugin-jsx-a11y';
import { includeIgnoreFile } from '@eslint/compat';
import { defineConfig, globalIgnores } from 'eslint/config';
import globals from 'globals';
import pluginImport from 'eslint-plugin-import';
import pluginTypeScript from 'typescript-eslint';

const rootPath = import.meta.dirname;
const gitignorePath = join(rootPath, '.gitignore');

export default defineConfig([
{
files: ['**/*.{js,mjs,ts,tsx}'],
extends: [
configPrettier,
eslint.configs.recommended,
pluginTypeScript.configs.recommended,
pluginImport.flatConfigs.recommended,
pluginImport.flatConfigs.typescript,
],
languageOptions: {
parser: pluginTypeScript.parser,
parserOptions: {
ecmaVersion: 'latest',
projectService: true,
tsconfigRootDir: rootPath,
},
},
rules: {
// Turn off rules that are handled by TypeScript
// https://typescript-eslint.io/troubleshooting/typed-linting/performance/#eslint-plugin-import
'import/default': 'off',
'import/named': 'off',
'import/namespace': 'off',
'import/no-cycle': 'off',
'import/no-deprecated': 'off',
'import/no-named-as-default': 'off',
'import/no-named-as-default-member': 'off',
'import/no-unresolved': 'off',
'import/no-unused-modules': 'off',
},
settings: {
'import/resolver': {
node: true,
typescript: true,
},
},
},
{
files: ['**/*.{ts,tsx}'],
extends: [
pluginJsxA11y.flatConfigs.recommended,
pluginReact.configs.flat.recommended,
pluginReact.configs.flat['jsx-runtime'],
'react-hooks/recommended-latest',
],
languageOptions: {
globals: globals.browser,
parserOptions: {
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
plugins: {
'react-hooks': pluginReactHooks,
},
settings: {
react: {
version: 'detect',
},
},
},
{
files: ['**/*.{cjs,js,mjs}'],
languageOptions: {
globals: globals.node,
},
},
{
files: ['**/*.cjs'],
rules: {
'@typescript-eslint/no-require-imports': 'off',
'@typescript-eslint/no-var-requires': 'off',
},
},
{
files: ['**/*.test.{ts,tsx}'],
languageOptions: {
globals: globals.jest,
},
},
{
files: ['**/*.stories.tsx'],
rules: { '@typescript-eslint/no-unused-vars': 'off' },
},
globalIgnores(['**/coverage/', '**/dist/']),
includeIgnoreFile(gitignorePath, 'Imported .gitignore patterns'),
]);
76 changes: 41 additions & 35 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,77 +55,83 @@
"build": "yarn cleanup && rollup -c",
"test": "jest",
"test:watch": "jest --watch",
"test:ci": "jest --coverage",
"lint": "eslint 'src/**/*.{js,ts,tsx}' 'stories/**/*.{js,ts,tsx}'",
"lint:fix": "eslint 'src/**/*.{js,ts,tsx}' 'stories/**/*.{js,ts,tsx}' --fix",
"lint:ci": "eslint 'src/**/*.{js,ts,tsx}' 'stories/**/*.{js,ts,tsx}'",
"lint": "yarn lint:types && yarn lint:js && yarn lint:prettier",
"lint:fix": "yarn lint:js:fix && yarn lint:prettier:fix",
"lint:prettier": "prettier --check .",
"lint:prettier:fix": "prettier --write .",
"lint:js": "eslint . --max-warnings 0",
"lint:js:fix": "yarn lint:js --fix",
"lint:types": "tsc --build tsconfig.json --pretty",
"build-storybook": "storybook build",
"prepublishOnly": "yarn lint:ci && yarn test:ci && yarn storybook --smoke-test"
"prepublishOnly": "yarn lint && yarn test && yarn storybook --smoke-test"
},
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.28.4",
"@babel/preset-env": "^7.28.3",
"@babel/preset-react": "^7.27.1",
"@babel/preset-typescript": "^7.27.1",
"@eslint/compat": "^1.4.0",
"@eslint/js": "^9.37.0",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-commonjs": "^28.0.6",
"@rollup/plugin-node-resolve": "^16.0.1",
"@rollup/plugin-typescript": "^12.1.4",
"@storybook/addon-actions": "^8.0.5",
"@storybook/addon-essentials": "^8.0.5",
"@storybook/addon-links": "^8.0.5",
"@storybook/blocks": "^8.0.5",
"@storybook/manager-api": "^8.0.5",
"@storybook/preview-api": "^8.0.5",
"@storybook/react": "^8.0.5",
"@storybook/react-vite": "^8.0.5",
"@storybook/theming": "^8.0.5",
"@storybook/addon-essentials": "^8.6.14",
"@storybook/addon-links": "^8.6.14",
"@storybook/blocks": "^8.6.14",
"@storybook/manager-api": "^8.6.14",
"@storybook/react": "^8.6.14",
"@storybook/react-vite": "^8.6.14",
"@storybook/theming": "^8.6.14",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^15.0.7",
"@testing-library/react": "^16.3.0",
"@types/eslint": "^9.6.1",
"@types/jest": "^30.0.0",
"@types/jest-axe": "^3.5.9",
"@types/lodash": "^4.17.20",
"@types/node": "^24.6.2",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^7.1.0",
"@types/react": "^19.2.2",
"@types/react-dom": "^19.2.1",
"babel-jest": "^30.2.0",
"babel-plugin-module-resolver": "^5.0.2",
"babel-plugin-replace-import-extension": "^1.1.5",
"chromatic": "^6.17.3",
"classnames": "^2.5.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint": "^9.37.0",
"eslint-config-prettier": "^10.1.8",
"eslint-import-resolver-typescript": "^4.4.4",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^6.1.0",
"globals": "^16.4.0",
"jest": "^30.2.0",
"jest-axe": "^10.0.0",
"jest-environment-jsdom": "^30.2.0",
"lodash": "^4.17.21",
"nhsuk-frontend": "^10.0.0",
"outdent": "^0.8.0",
"prettier": "^3.2.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"prettier": "^3.6.2",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"rollup": "^4.52.4",
"rollup-plugin-preserve-directives": "^0.4.0",
"sass": "^1.53.0",
"storybook": "^8.0.5",
"storybook": "^8.6.14",
"tslib": "^2.8.1",
"typescript": "5.3.3",
"typescript": "^5.9.3",
"typescript-eslint": "^8.45.0",
"vite": "^4.5.3",
"vite-tsconfig-paths": "^4.3.2"
},
"peerDependencies": {
"classnames": ">=2.5.0",
"nhsuk-frontend": ">=10.0.0 <11.0.0",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
"react": ">=18.2.0",
"react-dom": ">=18.2.0",
"tslib": ">=2.8.0"
},
"packageManager": "yarn@4.1.1"
"packageManager": "yarn@4.10.3"
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use client';

import classNames from 'classnames';
import {
createContext,
Expand Down
Loading