This document provides guidance for AI coding agents operating in this repository.
This is the VISA Product Design System (Nova) React component library - a pnpm monorepo containing:
libs/nova-react/- The main React component library (Rollup build)apps/workshop/- Documentation and demo application (Vite)
Stack: React 19, TypeScript 5.9+, Vitest, ESLint 9, Prettier, pnpm 9.x
pnpm install # Install dependencies
pnpm build # Build all workspaces
pnpm build:lib # Build only the component library
pnpm build:docs # Build only the workshop/docs
pnpm dev # Run all in dev mode (parallel)
pnpm dev:lib # Run library in watch mode
pnpm dev:docs # Run workshop dev server
pnpm lint # Lint with auto-fix (zero warnings allowed)
pnpm api:json # Create the json file for design.visa.com usagepnpm test # Run all tests
pnpm test:watch # Run tests in watch mode
pnpm test:coverage # Run tests with coverage report
# Run a single test file
pnpm vitest run libs/nova-react/src/badge/index.test.tsx
# Run tests matching a pattern
pnpm vitest run badge # Runs all tests with "badge" in path
pnpm vitest run use-debounce # Runs hook tests
# Run tests for a specific workspace
pnpm vitest run libs/nova-react # All library tests
pnpm vitest run apps/workshop # All workshop testspnpm prepush # Runs lint && build (used by husky pre-push hook)Every source file MUST include the Apache 2.0 license header:
/**
* © 2025 Visa
*
* Licensed under the Apache License, Version 2.0 (the "License");
* ...full license text...
**/- External packages first (React, clsx, etc.)
- Type-only imports use
import type { ... } - Relative imports last
import cn from 'clsx';
import type { ComponentPropsWithRef, ElementType } from 'react';
import SomeLocalUtil from '../utils';const CSS_PREFIX = 'v-component-name';
export type ComponentProperties<ET extends ElementType = 'div'> = {
/** JSDoc comment for prop */
propName?: PropType;
} & ComponentPropsWithRef<ET>;
/**
* Component description.
* @docs {@link https://design.visa.com/components/name | See Docs}
* @vgar TODO
* @wcag TODO
*/
const Component = <ET extends ElementType = 'div'>({
propName,
className,
tag: Tag = 'div',
...remainingProps
}: ComponentProperties<ET>) => (
<Tag
className={cn(CSS_PREFIX, propName && `${CSS_PREFIX}-modifier`, className)}
{...remainingProps}
/>
);
export default Component;
Component.displayName = 'Component';/**
* Hook description
* @related component1, component2
* @param {Type} paramName - Description
* @returns {ReturnType} Description
*/
export const useHookName = (params): ReturnType => {
// implementation
};
export default useHookName;
useHookName.displayName = 'useHookName';- Components: PascalCase (e.g.,
Badge,InputMessage) - Hooks: camelCase with
useprefix (e.g.,useDebounce,useFocusTrap) - Types: PascalCase with
Propertiessuffix (e.g.,BadgeProperties) - CSS Prefix:
v-component-name(lowercase, kebab-case) - Folders: kebab-case matching component/hook name
- Test Files:
index.test.tsx(components) orindex.test.ts(hooks)
- Single quotes
- 120 character print width
- 2 space indentation
- Trailing commas (ES5 style)
- No arrow parens when possible
- Semicolons required
- Strict mode enabled
- Use
import typefor type-only imports (verbatimModuleSyntax: true) - Polymorphic components use
ElementTypegeneric pattern - All props must have JSDoc comments
- No unused variables or parameters
- Use
clsx(imported ascn) for conditional class composition - CSS prefix pattern:
v-{component}for base,v-{component}-{modifier}for variants - User's
classNameprop is always appended last
import { render } from '@testing-library/react';
import { axe } from 'jest-axe';
import Component from '.';
describe('Component', () => {
it('should render defaults correctly', async () => {
const { container } = render(<Component />);
const results = await axe(container);
expect(results).toHaveNoViolations(); // Accessibility check
expect(container).toMatchSnapshot();
});
// Test each prop variation
// Test custom classNames
// Test custom tags
// Test prop permeation
});Format: type(scope): description
- Types: feat, fix, docs, test, refactor, chore, style, perf, build, ci
- Scope: Component or hook name in kebab-case (optional)
- Description: Imperative mood ("add" not "added"), max 72 chars total
libs/nova-react/src/
├── {component-name}/ # Component folder (kebab-case)
│ ├── index.tsx # Component implementation
│ ├── index.test.tsx # Component tests
│ ├── meta.json # Component metadata
│ └── __snapshots__/ # Jest snapshots
├── use-{hook-name}/ # Hook folder
│ ├── index.ts # Hook implementation
│ ├── index.test.ts # Hook tests
│ └── meta.json # Hook metadata
└── index.ts # Main exports (auto-generated)
apps/workshop/src/
├── examples/ # Component usage examples
│ ├── components/ # Component examples
│ ├── hooks/ # Hook examples
│ └── patterns/ # Complex pattern examples
└── pages/ # Workshop pages
- React: 19.x (uses new JSX transform - no React import needed)
- clsx: For className composition
- @testing-library/react: For component testing
- jest-axe: For accessibility testing
- vitest: Test runner with jsdom environment