@trustvid/design-system
v0.5.1
Published
TrustVid React UI library — components, tokens, and styles (npm package @trustvid/design-system).
Readme
trustvid-ui-library
@trustvid/design-system — TrustVid's shared React UI library: typed Tv* primitives, theme tokens, CSS bundles, and branding hooks. Published to npm as @trustvid/design-system.
Audience for this document: design-system contributors, frontend engineers consuming the package, and AI coding agents (Cursor, Copilot, etc.). Sections below explain why this package exists, what it owns, how it is structured, and where to look when adding or changing UI building blocks.
Why this package exists
TrustVid's main app (trustvid-ai-platform) originally inlined UI primitives inside the monolith. That made it hard to:
- Version UI independently from feature releases
- Enforce one visual language across screens and future apps
- Share components with other packages (e.g.
@trustvid/remotion-compositionsoverrides design-system peer)
This repo is the source of truth for TrustVid UI. It was extracted from trustvid-ai-platform/packages/design-system (same pattern as trustvid-remotion-compositions) so primitives, tokens, and styles can be built, tested, and published on their own semver.
Goals:
- Consistency — One
Tv*vocabulary and token set across TrustVid products - Scalability — Add screens in host apps without reinventing buttons, forms, tables, modals
- Maintainability — Token-driven styling (
baseTokens, CSS variables) instead of scattered hex literals - Tenant branding — Runtime theming via
--tv-theme-*/--bs-*without forking components
What this repo does
| Responsibility | Details |
|----------------|---------|
| Tv* primitives | Buttons, inputs, tables, modals, alerts, charts, layout wrappers — BEM tv-* classes on reactstrap/Bootstrap 5 |
| Composed components | Higher-level patterns (TvMediaAspectBox, TvLazyVideoPreview, TvFeatureSwitchRow) |
| Theme system | baseTokens, DesignSystemProvider, buildCssVariablesFromColors |
| Styles bundle | dist/styles.css — import once in host app (@trustvid/design-system/styles.css) |
| reactstrap surface | Re-exports reactstrap so consumers import from one package, not reactstrap directly |
| npm package | Only dist/ is published (package.json files) |
Out of scope: Feature screens, routing, API calls, campaign editor logic — those live in trustvid-ai-platform. Promote UI here only when it is reused across modules or apps.
TrustVid ecosystem (consumers & siblings)
your-workspace/
├── trustvid-ui-library/ ← this repo (@trustvid/design-system)
├── trustvid-ai-platform/ ← primary consumer (React admin UI)
├── trustvid-remotion-compositions/ ← peer-depends on @trustvid/design-system
└── devops/ ← CI/CD for npm publish pipelines| Consumer | How it depends | Notes |
|----------|----------------|-------|
| trustvid-ai-platform | "@trustvid/design-system": "file:../trustvid-ui-library" or semver from npm | scripts/ensure-ui-library-built.js builds sibling dist/ on postinstall / predev |
| trustvid-remotion-compositions | peer + npm override for design-system | Render-safe components use same tokens |
| Future TrustVid React apps | npm install @trustvid/design-system | Same import surface |
Host app integration guide: trustvid-ai-platform/docs/design-system.md
Authoritative component reference: docs/DEVELOPER_README.md
Package name & entry points
npm name: @trustvid/design-system
| Import | Purpose |
|--------|---------|
| @trustvid/design-system | Components, tokens, DesignSystemProvider, hooks, reactstrap re-exports |
| @trustvid/design-system/styles.css | Bundled design-system CSS (import once in host app entry) |
Published artifacts live under dist/ only (package.json → files: ["dist"]).
Current version: see package.json (e.g. 0.2.0).
Tech stack
| Layer | Technology |
|-------|------------|
| Language | TypeScript 4.9 (strict compile → dist/) |
| UI runtime | React 18 (peer dependency) |
| Component kit | Reactstrap 9 (Bootstrap 5 API; peer dependency) |
| Styling | CSS modules per primitive under src/styles/; bundled to dist/styles.css |
| Charts | Recharts 3 (peer; TvChart* wrappers) |
| Build | tsc + scripts/bundle-styles.js |
| Testing | Jest 29 + React Testing Library + ts-jest |
| CI | Bitbucket Pipelines (lint:ci, build, test:*, package:check, auto-publish on main) |
Peer dependencies (host must provide): react, react-dom, reactstrap, recharts
Architecture & source tree
trustvid-ui-library/
├── src/
│ ├── index.ts # Public export surface (Tv*, tokens, reactstrap re-export)
│ ├── primitives/ # Low-level Tv* components (TvButton, TvTable, TvModal, …)
│ ├── components/ # Composed patterns (TvLazyVideoPreview, TvFeatureSwitchRow, …)
│ ├── hooks/ # useDebouncedSearch (exported with TvSearchBar)
│ ├── tokens/
│ │ └── themeTokens.ts # baseTokens — source of truth for colors/spacing/radius
│ ├── theme/
│ │ ├── DesignSystemProvider.tsx
│ │ └── cssVariables.ts # buildCssVariablesFromColors, colorKeys
│ ├── styles/ # Per-component CSS (tv-button.css, tv-table.css, …)
│ └── utils/
│ └── tvClasses.ts # BEM class helper
├── dist/ # Published output only (gitignored in dev; built before publish)
├── tests/
│ ├── unit/ # *.unit.test.tsx
│ ├── integration/ # *.integration.test.tsx
│ └── workflow/ # *.workflow.test.tsx
├── scripts/
│ ├── bundle-styles.js # Concatenates src/styles → dist/styles.css
│ └── release.sh # Version bump + npm publish (Bitbucket)
└── docs/
└── DEVELOPER_README.md # Extended tokens, branding, a11y, troubleshootingLayering conventions
| Layer | Location | When to add here |
|-------|----------|------------------|
| Primitives | src/primitives/Tv*.tsx | Single-purpose building blocks (button, input, table cell) |
| Composed | src/components/Tv*.tsx | Reusable multi-primitive patterns used in 2+ host features |
| Styles | src/styles/tv-*.css | One CSS file per primitive family; registered in bundle-styles.js |
| Tokens | src/tokens/themeTokens.ts | Colors, spacing, typography, radius — no hardcoded hex in primitives |
| Theme bridge | src/theme/ | Provider + CSS variable generation for account branding |
Adding a new Tv* primitive (checklist)
- Create
src/primitives/TvMyWidget.tsxwith typed props andtv-*BEM classes viatvClasses(). - Add
src/styles/tv-my-widget.cssand wire it inscripts/bundle-styles.js. - Export from
src/index.ts(component + props type). - Add tests under
tests/unit/primitives/,tests/integration/primitives/,tests/workflow/primitives/. - Document usage in
docs/DEVELOPER_README.mdif non-obvious. - Bump semver and publish; bump consumer dependency in
trustvid-ai-platform.
Do not import from host apps into this package. Do not add feature-specific business logic.
Component catalog (summary)
Full API and examples: docs/DEVELOPER_README.md.
| Category | Examples |
|----------|----------|
| Actions | TvButton, TvIconButton, TvCloseButton, TvButtonGroup |
| Forms | TvInput, TvTextarea, TvSelect, TvCheckbox, TvRadio, TvFormGroup, TvLabel, TvForm, TvSearchBar, useDebouncedSearch |
| Feedback | TvAlert, TvSpinner, TvBadge, TvProgress, TvTooltip |
| Surfaces | TvCard, TvCardBody, TvCardHeader, TvModal, TvDrawer, TvAccordion |
| Navigation | TvBreadcrumb, TvTabs, TvNav, TvPagination, TvDropdown, TvControlledDropdown |
| Tables | TvTable, TvThead, TvTbody, TvTr, TvTh, TvTd, TvTfoot |
| Typography / layout | TvH1–TvH6, TvP, TvSmall, TvCode, TvDiv, TvRow, TvCol, TvContainer |
| Media | TvImg, TvVideo, TvAudio, TvMediaAspectBox, TvLazyVideoPreview |
| Charts | TvChartBarChart, TvChartPieChart, TvChartResponsiveContainer, … |
| Settings | TvFeatureSwitchRow |
| Theme | baseTokens, DesignSystemProvider, buildCssVariablesFromColors, useDesignSystem |
reactstrap re-export: export * from "reactstrap" at bottom of index.ts — host apps should import layout/dropdown pieces from @trustvid/design-system, not reactstrap directly.
Consumer integration (trustvid-ai-platform)
Local sibling development
{
"dependencies": {
"@trustvid/design-system": "file:../trustvid-ui-library"
}
}trustvid-ai-platform runs scripts/ensure-ui-library-built.js on postinstall / predev / pretest to compile this repo and sync dist/ into node_modules/@trustvid/design-system/dist.
After publish (semver)
{
"dependencies": {
"@trustvid/design-system": "^0.2.0"
}
}Platform CI enforces check:no-local-design-system-dep and check:no-direct-ui-imports — feature code must use @trustvid/design-system, not raw reactstrap or deep paths.
Host app setup (minimum)
// index.js (host)
import "bootstrap/dist/css/bootstrap.min.css";
import "@trustvid/design-system/styles.css";import { DesignSystemProvider, TvButton, baseTokens } from "@trustvid/design-system";
<DesignSystemProvider tokens={baseTokens}>
<TvButton variant="primary">Save</TvButton>
</DesignSystemProvider>Account branding: host merges palette → buildCssVariablesFromColors → apply on :root. See Theming and docs/DEVELOPER_README.md §16–17.
Component promotion rules (from platform)
These rules are enforced in trustvid-ai-platform; this package is the destination for promoted UI:
- Keep feature-only components in
trustvid-ai-platform/src/features/… - Promote here when a component is used in 2+ modules or across apps
- Low-level building blocks →
src/primitives/ - Composed reusable patterns →
src/components/
Local development
npm ci
npm run lint:ci # tsc --noEmit
npm run build # tsc + bundle styles → dist/
npm run test # unit + integration + workflowWatch TypeScript:
npm run build:watchVerify package contents before publish:
npm run package:check # npm pack --dry-runPrerequisites: Node.js 18+, npm. No .env required for local build/test.
After changing primitives or styles, always run npm run build before testing in a linked trustvid-ai-platform checkout (or let ensure-ui-library-built.js rebuild for you).
Theming (host app)
- Import styles once before app components:
import "@trustvid/design-system/styles.css";Wrap the tree with
DesignSystemProvider(optional token overrides).Use
buildCssVariablesFromColors+ apply variables on:rootfor account branding.
See docs/DEVELOPER_README.md for the full guide (color tokens, typography, logo usage, a11y).
Testing policy
Every primitive or composed component change requires three Jest layers (mandatory in CI):
| Layer | Location | Pattern | Script |
|-------|----------|---------|--------|
| Unit | tests/unit/<area>/ | *.unit.test.tsx | npm run test:unit |
| Integration | tests/integration/<area>/ | *.integration.test.tsx | npm run test:integration |
| Workflow | tests/workflow/<area>/ | *.workflow.test.tsx | npm run test:workflow |
Mirror src/ structure inside each tier. See tests/README.md.
npm run test:unit
npm run test:integration
npm run test:workflow
npm test # all threeWriting tests (guidelines)
- Import from
src/using relative paths in test files, e.g.import TvButton from "../../../src/primitives/TvButton". - Use
@testing-library/react+userEventfor interaction tests. - Assert behavior (roles, labels, callbacks), not implementation details.
- At least one test must fail if the fix is reverted.
- Cover variants, disabled states, and accessibility roles where relevant.
Example structure
tests/
unit/primitives/TvButton.unit.test.tsx
integration/primitives/TvButton.integration.test.tsx
workflow/primitives/TvButton.workflow.test.tsxAI agent & Cursor context
This package is a shared dependency for TrustVid frontends. When an AI agent works here:
| Resource | Purpose |
|----------|---------|
| AGENTS.md | Repo agent role, testing policy, PR conventions |
| docs/DEVELOPER_README.md | Authoritative tokens, components, branding, a11y |
| trustvid-ai-platform/docs/design-system.md | How the host app consumes this package |
| trustvid-ai-platform/.cursor/rules/design-system.mdc | Rules enforced in feature code (Tv* only, no raw HTML) |
| src/index.ts | Complete public export list |
| src/tokens/themeTokens.ts | Token source of truth |
When adding or changing a component:
- Add primitive under
src/primitives/+ CSS undersrc/styles/. - Export from
src/index.tswith TypeScript props type. - Add unit + integration + workflow tests under
tests/. - Run
npm run lint:ci && npm run build && npm test. - Bump version and publish; update
trustvid-ai-platform/package.jsonsemver. - Never add host-app feature logic or API calls in this package.
PR conventions: Target branch main; title prefix with Jira key (e.g. TVD-1097: …).
Versioning and release flow
Required Bitbucket repository variables
Add under Repository settings → Pipelines → Repository variables (mark NPM_AUTH_TOKEN as Secured):
| Variable | Required | Notes |
|----------|----------|--------|
| NPM_AUTH_TOKEN | Yes | npm Automation token with publish access for @trustvid/design-system |
| BITBUCKET_API_TOKEN | Yes (for release push) | Repository access token with write access; used by release.sh to push version commits (see scripts/bitbucket-ci-env.sh) |
| BITBUCKET_USERNAME | No | Defaults to x-token-auth |
| NPM_REGISTRY_URL | No | Defaults to https://registry.npmjs.org/ |
| NPM_REGISTRY_HOST | No | Defaults to registry.npmjs.org |
scripts/npm-registry-env.sh only sets registry URL/host defaults; it does not replace NPM_AUTH_TOKEN when Bitbucket already provides it.
Pipeline behavior
mainbranch: validate (lint:ci,build,test:unit,test:integration,package:check) → auto bump + publish- Custom pipelines:
publish-current-version,release-patch,release-minor,release-major
Release runs scripts/release.sh (includes test:workflow before publish). Duplicate published versions fail fast. Before npm ci, release.sh runs npm whoami; if the npm token is expired or invalid, the log shows npm registry authentication failed instead of the misleading 404 from npm publish.
Auto bump rules on main
When BUMP_TYPE is not set, bump is derived from the latest commit message:
#majororBREAKING CHANGE→major#minororfeat(...)/feature→minor- default →
patch
Git push for release commits
Same model as trustvid-remotion-compositions (scripts/release.sh + bitbucket-pipelines.yml): bump-and-publish runs git push --dry-run before version bump/publish, then pushes the release commit after a successful npm publish.
For bump-and-publish pipelines, release.sh configures origin as follows:
- If
BITBUCKET_API_TOKENis set andBITBUCKET_WORKSPACE/BITBUCKET_REPO_SLUGare available (Pipelines), use HTTPS with token auth. - If
originis already SSH ([email protected]:...), use SSH push directly. - Otherwise rewrite to SSH when workspace/repo slug are known.
Required for release commit push:
- Secured
BITBUCKET_API_TOKENwith repository write access (preferred over hardcoded defaults inscripts/bitbucket-ci-env.sh). - Branch permissions on
main: allow the pipeline identity to push thechore(release): … [skip ci]commit. - Optional: Repository settings → Pipelines → SSH keys (when using SSH remotes).
Optional bot identity: RELEASE_GIT_NAME, RELEASE_GIT_EMAIL.
Recovering git/npm version drift
If publish succeeded but git was behind npm (or you see ERROR: … is already published / Git version is behind npm latest), sync git to the registry before the next release:
npm view @trustvid/design-system version # e.g. 0.1.5
npm version 0.1.5 --no-git-tag-version # match npm latest
npm install
git add package.json package-lock.json
git commit -m "chore(release): sync package version with npm 0.1.5 [skip ci]"
git push origin mainrelease.sh runs assert_git_not_behind_npm before bumping to catch this early.
Install in consumers (after publish)
npm install @trustvid/design-systemConfigure .npmrc for your private registry if not using the public npm registry.
Scripts (reference)
| Script | Purpose |
|--------|---------|
| npm run build | tsc + bundle-styles.js → dist/ |
| npm run build:watch | TypeScript watch mode |
| npm run lint / lint:ci | Type-check only (tsc --noEmit) |
| npm test | All three test tiers |
| npm run test:unit | Unit tests + coverage |
| npm run test:integration | Integration tests + coverage |
| npm run test:workflow | Workflow tests + coverage |
| npm run package:check | Dry-run npm pack (validates files manifest) |
| prepack | Runs build before npm pack / publish |
Extended documentation
| Document | Topic |
|----------|-------|
| docs/DEVELOPER_README.md | Tokens, components, branding, a11y, troubleshooting (authoritative) |
| tests/README.md | Test folder layout and naming |
| trustvid-ai-platform/docs/design-system.md | Host app integration and promotion rules |
| trustvid-ai-platform/README.md | Full TrustVid platform context |
Quick troubleshooting
| Problem | Check |
|---------|-------|
| Host app can't resolve @trustvid/design-system | Sibling repo cloned; npm run build in this repo; ensure-ui-library-built.js output |
| Styles missing / unstyled Tv* | Host imports @trustvid/design-system/styles.css and Bootstrap CSS |
| Type errors after publish | Consumer on matching semver; dist/index.d.ts exists |
| npm publish 404 | Usually expired NPM_AUTH_TOKEN — check npm whoami in pipeline logs |
| Git behind npm on release | Run version sync steps in Recovering git/npm version drift |
| Peer dependency warnings | Host must install react, react-dom, reactstrap, recharts at compatible versions |
| New primitive has no styles | CSS file added to src/styles/ and registered in scripts/bundle-styles.js |
