|
| 1 | +# Repository Guidelines |
| 2 | + |
| 3 | +This repository contains the source code and documentation for Base UI: a headless, unstyled React component library. |
| 4 | + |
| 5 | +## Project structure |
| 6 | + |
| 7 | +- Source code for components and private utils is in `packages/react/`. |
| 8 | +- Source code for public shared utils is in `packages/utils/`. |
| 9 | +- Experiments are located at `docs/src/app/(private)/experiments/`. Use for creating demos that require manual testing in the browser. |
| 10 | +- Public documentation is located at `docs/src/app/(public)/(content)/react/`. Alter the docs where necessary when changes must be visible to library users. |
| 11 | +- When creating public demos on the docs, refer to the `hero` demo for the given component and largely follow its styles (both CSS Modules and Tailwind CSS versions). Other demos may also contain relevant styling. Do not add custom styling beyond the critical layout styles necessary for new demos. |
| 12 | + |
| 13 | +## Code guidelines |
| 14 | + |
| 15 | +- Always use the `useTimeout` utility from `@base-ui-components/utils/useTimeout` instead of `window.setTimeout`, and `useAnimationFrame` from `@base-ui-components/utils/useAnimationFrame` instead of `requestAnimationFrame`. Search for other example usage in the codebase if unsure how to use them. |
| 16 | +- Use the `useEventCallback` utility from `@base-ui-components/utils/useEventCallback` instead of `React.useCallback` if the function is called within an effect or event handler. The utility cannot be used to memoize functions that are called directly in the body of a component (during render), so continue with `React.useCallback` in those scenarios. |
| 17 | +- Always use the `useIsoLayoutEffect` utility from `@base-ui-components/utils/useIsoLayoutEffect` instead of `React.useLayoutEffect`. |
| 18 | +- Avoid duplicating logic where necessary. If two components can share logic (such as event handlers), define the logic/handlers in the parent and share it through a context to the child; use the existing context if it exists. |
| 19 | + |
| 20 | +## Linting, typechecking, and formatting |
| 21 | + |
| 22 | +- Do not randomly cast (for example `as any`) if there are no type errors without doing so. Run `pnpm typescript` to verify types. |
| 23 | +- Ensure your changes pass linting - run `pnpm eslint`. |
| 24 | +- Ensure your changes are formatted correctly - run `pnpm prettier`. |
| 25 | + |
| 26 | +## Testing |
| 27 | + |
| 28 | +- Run tests in JSDOM env with `pnpm test:jsdom {name} --no-watch` such as `pnpm test:jsdom NumberField --no-watch` or `pnpm test:jsdom parse --no-watch`. |
| 29 | +- Run tests in Chromium env with `pnpm test:chromium {name} --no-watch` such as `pnpm test:chromium NumberField --no-watch` or `pnpm test:jsdom parse --no-watch`. |
| 30 | +- If you made changes to the source code, ensure you verify your changes by running tests (see above), and writing new tests where applicable. If tests require the browser because, for example, they require layout measurements, restrict it to the Chromium env by using `it.skipIf(isJSDOM)` or `describe.skipIf(isJSDOM)` (search other tests for example usage if unsure). |
| 31 | +- Follow the established conventions in existing tests. Each file/component is tested with the filename `name.test.tsx`. For example, `PopoverRoot.test.tsx` is next to its source file `PopoverRoot.tsx`. |
| 32 | +- Tests use `chai`'s `expect` and Sinon's `spy()`, do not assume they have methods of other libraries' APIs. Search existing tests for example usage if unsure. |
| 33 | + |
| 34 | +## Commit guidelines |
| 35 | + |
| 36 | +- Commit messages follow the format `[scope] Imperative summary` (for example `[popover] Fix focus trap`). Choose scopes that mirror package or component names that were changed. |
| 37 | +- Use `[all components]` scope for changes that broadly affect most components. |
0 commit comments