@sidcorp/react-kit
v0.1.0
Published
Shared tooling config and design tokens for React 19 + Vite + TypeScript SaaS apps — ESLint, Prettier, tsconfig, Vite/Vitest preset and Tailwind 4 tokens in one package.
Readme
@sidcorp/react-kit
Shared tooling config and design tokens for React 19 + Vite + TypeScript SaaS apps. The published half of forge-react-kit.
One package rather than five: every app built from the kit consumes all of it, so splitting bought nothing but five versions to keep in sync. Splitting later is cheap (publish the new package, re-export from this one); merging later would mean deprecating claimed names while projects depend on them.
pnpm add -D @sidcorp/react-kitESLint
// eslint.config.js
export { default } from '@sidcorp/react-kit/eslint'Extends @eslint/js recommended, typescript-eslint recommended and @tanstack/eslint-plugin-query, plus react-hooks and react-refresh.
Beyond the usual set it adds no-hardcoded-color: hex literals and Tailwind palette classes (bg-blue-500, text-red-600, …) are errors. Components must use semantic tokens (bg-background, text-muted-foreground, border-border) so swapping a theme stays a config change instead of an edit across every component. A colour the token set cannot express means the token set needs extending — see Tokens below.
Exempt: **/*.test.{ts,tsx}, src/test-utils/**, and src/assets/** (illustrations, where the fill is the content).
Project-specific rules go in a second config object appended in your app, never by patching this package.
Prettier
// prettier.config.js
import base from '@sidcorp/react-kit/prettier'
export default { ...base, tailwindStylesheet: './src/styles/index.css' }Ships @trivago/prettier-plugin-sort-imports and prettier-plugin-tailwindcss with a fixed import order, so import blocks look identical across projects — variance between projects is what makes code review expensive. tailwindStylesheet is left to the app because the path is app-relative.
Plugin paths are resolved with createRequire(import.meta.url).resolve() rather than bare names, because Prettier resolves bare plugin names relative to the config file — which under pnpm lives in an app where these plugins are not installed.
If a .prettierrc exists in your app it will shadow prettier.config.js and this config will silently do nothing. Delete it, and check with prettier --find-config-path src/main.tsx.
TypeScript
{
"extends": "@sidcorp/react-kit/tsconfig-app.json",
"compilerOptions": { "paths": { "@/*": ["./src/*"] } },
"include": ["src"]
}tsconfig-base.json is strict with bundler resolution and unused locals/params as errors; tsconfig-app.json adds DOM libs and react-jsx; tsconfig-node.json is for build-time files. paths and tsBuildInfoFile stay in the app because both are app-relative.
Vite + Vitest
// vite.config.ts
import { defineKitConfig } from '@sidcorp/react-kit/vite'
export default defineKitConfig({ root: import.meta.dirname })Owns the plugin set (TanStack Router with auto code splitting, React, Tailwind), the @ → src alias, and Vitest browser mode on Playwright Chromium.
overrides is merged on top via Vite's own mergeConfig — the escape hatch for a project that needs one extra plugin, so it never has to fork the preset:
defineKitConfig({
root: import.meta.dirname,
overrides: { server: { port: 4000 } },
})Tokens and themes
/* src/styles/index.css */
@import 'tailwindcss';
@import 'tw-animate-css';
@import '@sidcorp/react-kit/theme-default.css';
@import '@sidcorp/react-kit/base.css';Keep @import 'tailwindcss' in your app's CSS, not in the package — Tailwind roots its automatic source detection at the importing file, and rooting it inside node_modules scans the wrong tree.
theme-default.css—:root/.darktoken values plus the@theme inlinemappingtheme-ocean.css— a second theme, demonstrating that a swap is one linebase.css— the dark variant,@layer baseresets, shared@utilitydefinitions and keyframes
Swapping a theme is one @import line and nothing else. Verified end to end: theme-default.css → theme-ocean.css changes primary colour, border radius and status colours with no component file edited.
Alongside the ~30 shadcn semantic tokens (surface/content pairs, chart-1..5, sidebar-*, the radius scale) this adds four for state: success · info · warning · neutral, each with a -foreground pair. These four have not been contrast-checked against WCAG AA yet — treat their values as provisional.
Adding a new state means adding a token pair here, not a literal colour in a component. The ESLint rule enforces that.
Note when developing the kit itself
Vite does not watch node_modules, so editing a file in this package does not hot-reload in a linked app — not even on a page refresh. Restart the dev server and clear node_modules/.vite.
MIT
