Tonic UI Patterns
Commit Conventions
This project uses conventional commits with scope:
| Type | Usage | Frequency |
|---|---|---|
chore |
Releases, deps, tooling | ~36% |
feat |
New features | ~23% |
docs |
Documentation | ~18% |
ci |
CI/CD workflows | ~12% |
fix |
Bug fixes | ~7% |
test |
Test additions | ~2% |
refactor |
Code restructuring | ~1% |
Scope format: type(package/component) — e.g., feat(react/menu), fix(react/Checkbox), chore(deps-dev)
Common scopes:
react/react/<component>— Main component packagereact-hooks— Hooks packagereact-icons— Icons packagemcp— MCP server packagedeps/deps-dev— Dependency bumpsrelease— Version releaseschangesets— Changeset config
PR references: Commit messages include (#<number>) at the end.
Monorepo Structure
packages/
├── changelog-github/ # Custom changelog generator
├── codemod/ # Code migration tools
├── mcp/ # MCP server (TypeScript)
├── react/ # Main component library (JavaScript)
├── react-base/ # Base primitives (Box)
├── react-docs/ # Next.js documentation site
├── react-hooks/ # Shared hooks
├── react-icons/ # SVG icon components
├── styled-system/ # Styled System utilities
├── theme/ # Design tokens
└── utils/ # Shared utilities
Key: packages/react is the most frequently modified package (~38 commits in last 200).
Component Architecture
File Structure Pattern
Each component lives in packages/react/src/<component-name>/:
<component-name>/
├── ComponentName.js # Main component (forwardRef + Box base)
├── index.js # Barrel exports
├── styles.js # Style hooks (useComponentNameStyle)
├── context.js # React context (if compound component)
├── useComponentName.js # Context consumer hook
├── withComponentName.js # HOC for context injection (optional)
├── constants.js # Constants (variants, sizes)
└── __tests__/
├── ComponentName.test.js
└── __snapshots__/
└── ComponentName.test.js.snap
Component Pattern
Components use forwardRef with useDefaultProps:
import React, { forwardRef } from 'react';
import { useDefaultProps } from '../default-props';
import { useComponentStyle } from './styles';
const Component = forwardRef((inProps, ref) => {
const {
prop1,
prop2,
...rest
} = useDefaultProps({ props: inProps, name: 'Component' });
const styleProps = useComponentStyle({ prop1 });
return (
<Box ref={ref} {...styleProps} {...rest} />
);
});
Component.displayName = 'Component';
export default Component;
Compound Component Pattern
For related component groups (Menu, FormControl, Accordion):
- Context file (
context.js) —createContext() - Provider component — wraps children with context
- Consumer hook (
useComponentName.js) —useContext(ComponentContext) - HOC (
withComponentName.js) — injects context props (optional) - Barrel exports (
index.js) — named exports for all sub-components
Style Pattern
Styles use hooks that return style objects using Styled System tokens:
import { useColorStyle } from '../color-style';
const useComponentStyle = ({ variant }) => {
const [colorStyle] = useColorStyle();
return {
color: colorStyle.color.primary,
fontSize: 'sm',
px: '2x',
py: '1x',
};
};
Token formats: '1x', '2x', 'sm', 'md', 'lg' (Styled System spacing/sizing).
Adding a New Component
Based on recent features (Highlight, Mark, FormControl), the workflow is:
1. Create component source files
packages/react/src/<component-name>/
├── ComponentName.js
├── index.js
├── styles.js
└── __tests__/
└── ComponentName.test.js
2. Register in package index
Add to packages/react/src/index.js:
export { ComponentName } from './<component-name>';
3. Update package export test
Add to packages/react/__tests__/index.test.js to verify the export exists.
4. Create documentation pages
Add to packages/react-docs/pages/components/<component-name>/:
index.page.mdx— Main doc page- Individual example files (
.js) for each usage pattern
5. Register in sidebar
Add route to packages/react-docs/config/sidebar-routes.js.
6. Create changeset
Add .changeset/<changeset-name>.md:
---
"@tonic-ui/react": minor
---
feat: Add `ComponentName` component
Files That Co-Change
These files typically change together:
packages/react/src/index.js+packages/react/__tests__/index.test.js(new exports)packages/react-docs/config/sidebar-routes.js+packages/react-docs/pages/components/*/index.page.mdx(new docs)packages/react/package.json+packages/react/CHANGELOG.md+.changeset/*.md(releases)
Testing Patterns
- Framework: Jest with React Testing Library
- Location:
__tests__/directories co-located with source - Naming:
ComponentName.test.js - Snapshots: Used extensively for visual regression (
__snapshots__/) - Accessibility: Tests use
@tonic-ui/react-base/test-utils/accessibilityutilities - Test command:
yarn test
Changesets & Releases
- Uses
@changesets/clifor versioning - Base branch:
v2 - Changelog: Custom
@tonic-ui/changelog-githubgenerator - Access:
public(npm) - Changeset files go in
.changeset/with descriptive names (e.g.,tonic-ui-pr-1085.md)
Key Conventions
- JavaScript only — No TypeScript for components;
.d.tsfiles for type definitions - forwardRef everywhere — All components forward refs
- Styled System props — Style via props (
px,py,color,bg), not CSS classes - Color tokens — Use
colorStyle.color.primary,colorStyle.color.secondary,colorStyle.color.error - useDefaultProps — Components use this for default prop values
- displayName — Always set on components
- Named exports — Barrel files use named
export { X } from './X'pattern
Source: trendmicro-frontend/tonic-ui — distributed by TomeVault.