Tiberius react UI, themes, and controlled component library
  • JavaScript 83.9%
  • TypeScript 15.6%
  • HTML 0.2%
  • CSS 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Eric Wardner 8ef3fb0e5d
fix(pickers): Center the clear X over the icon
The clear button listed `absolute` before `touchHitArea`, whose leading
`relative` won the tailwind-merge conflict. The X became an in-flow
flex item instead of an overlay: on hover it sat about half a field
height low and a slot to the right of the calendar/clock icon, and that
reserved slot pushed the icon inward whenever a value was set.

Put `touchHitArea` first, as Sidebar already does for the same reason.
Affects DatePicker, DateRangePicker and TimePicker.
2026-10-15 18:37:17 -04:00
.forgejo ci: Update ci input to forgejo-workflows@51ff391f 2026-10-06 18:47:39 +00:00
.github/workflows feat: switch to date-based dev tags, remove releases 2026-02-23 16:13:35 -06:00
.storybook chore(storybook): upgrade to 10.6 and isolate the visual-test server's Vite cache 2026-10-05 17:07:18 -04:00
dist release/v3.0.2 (#20) 2026-10-08 15:38:47 +00:00
docs feat: library-wide component audit and fix pass 2026-10-06 16:31:08 -04:00
nix ci: Generate workflows from the ci flake input 2026-10-05 18:58:38 +00:00
scripts fix(release): Push the version bump for a PR (#19) 2026-10-08 15:07:15 +00:00
src fix(pickers): Center the clear X over the icon 2026-10-15 18:37:17 -04:00
storybook-static feat: library-wide component audit and fix pass 2026-10-06 16:31:08 -04:00
tests fix(theme): Bring back the blue in the light theme (#22) 2026-10-15 18:02:14 +00:00
.envrc feat: add OTPInput component 2026-02-13 16:23:22 -05:00
.gitignore feat(theme): add on-colour tokens, fix contrast in every theme, add theme test suites 2026-10-05 16:22:01 -04:00
CLAUDE.md release/v3.0.2 (#20) 2026-10-08 15:38:47 +00:00
flake.lock chore(nix): Bump nixpkgs to clear the image's nginx and OpenSSL CVEs (#24) 2026-10-15 18:27:11 +00:00
flake.nix fix(nix): Update the storybook npmDepsHash (#23) 2026-10-15 17:57:36 +00:00
package-lock.json chore(storybook): upgrade to 10.6 and isolate the visual-test server's Vite cache 2026-10-05 17:07:18 -04:00
package.json release/v3.0.2 (#20) 2026-10-08 15:38:47 +00:00
playwright.config.ts chore(storybook): upgrade to 10.6 and isolate the visual-test server's Vite cache 2026-10-05 17:07:18 -04:00
postcss.config.mjs chore: fix warnings from storybook 10 upgrade 2026-02-24 13:39:27 -05:00
README.md fix(release): Push the version bump for a PR (#19) 2026-10-08 15:07:15 +00:00
tsconfig.json Initial commit: tibui React component library 2026-01-28 13:19:35 -05:00
tsup.config.ts Initial commit: tibui React component library 2026-01-28 13:19:35 -05:00
version.txt chore: bump version to v2.1.4 2026-02-23 21:52:16 +00:00
vitest.config.ts feat(theme): add on-colour tokens, fix contrast in every theme, add theme test suites 2026-10-05 16:22:01 -04:00

tibui

A React UI component library built with TypeScript, Tailwind CSS, and Radix UI.

Installation

From the public mirror

Consumers install from the public mirror, not from this repo:

# Install a specific release, select any tag here
npm install https://code.grail.tiberius.com/public/tibui/archive/v2.9.0.tar.gz

The mirror exists so that nix pipelines can fetch tibui with no credentials. Installing from the private repo would require injecting a private npm key into the build, which is impure and anti-nix. See Releasing for how the mirror is kept up to date.

Local Development

  1. Clone and run the dev server:
git clone git@code.grail.tiberius.com:grail/tibui.git
cd tibui
npm install
npm run dev
  1. In your consuming project's package.json, reference the local path:
{
  "dependencies": {
    "tibui": "file:/path/to/tibui"
  }
}

Then run npm install in your project. Changes to tibui will be picked up automatically.

Usage

Import Components

import { Button, Tabs, Toggle, TextField, DataTable } from 'tibui'

Import Styles

In your CSS or main entry file:

@import 'tibui/theme.css';

Or in JavaScript/TypeScript:

import 'tibui/theme.css'

Development

# Install dependencies
npm install

# Build
npm run build

# Watch mode
npm run dev

# Type check
npm run typecheck

Testing

npm test                     # unit: theme contrast pairs, theme structure, no hardcoded colours
npm run test:visual          # Playwright + axe: every component under every theme, plus screenshots
npm run test:visual:update   # accept reviewed screenshot changes

npm run test:visual starts Storybook on port 6007 (or reuses a running one; set STORYBOOK_URL to point at another instance), renders the Themes/Gallery stories and the Mock App under each theme, fails on any axe color-contrast violation, and compares against the baselines in tests/visual/__screenshots__. Every axe finding is also appended to test-results/theme-contrast.ndjson. Chromium for Playwright is installed with npx playwright install chromium.

Storybook

This library uses Storybook for component development and documentation.

Running Storybook

Start the Storybook development server:

npm run storybook

This will start Storybook at http://localhost:6006 where you can browse and interact with all components.

Building Storybook

Build a static version of Storybook for deployment:

npm run build-storybook

This outputs a static site to the storybook-static directory, which can be deployed to any static hosting service.

Releasing

A release is two steps. Tagging alone does not publish anything — the tag is not visible to consumers until the public mirror has been synchronized.

Repo Purpose
Source (private) git@code.grail.tiberius.com:grail/tibui.git Where you develop and tag. This is origin.
Public mirror https://code.grail.tiberius.com/public/tibui What consumers and nix pipelines install from.

The private repo cannot be consumed by nix pipelines: cloning it requires credentials, which would mean injecting a private npm key into the build. That is impure and anti-nix, so release tags are mirrored to a public repo that needs no credentials to fetch.

Step 1 — Cut the release

npm run release

The script (scripts/release.mjs) will:

  1. Abort if the working tree is dirty, or if you are not on main
  2. git pull origin main
  3. Prompt you to choose a version bump (patch, minor, major)
  4. Create branch release/vX.Y.Z and run npm run build
  5. Update the version in package.json
  6. Commit package.json and dist/ as chore: bump version to vX.Y.Z
  7. Push the branch and print the link to open the PR
  8. After the PR is squash-merged, tag the merged commit vX.Y.Z on main and push the tag

Note that dist/ is listed in .gitignore but is deliberately committed on every release via git add -f dist/. Consumers install straight from git and do not run a build step, so a release without dist/ is broken.

On completion the script reminds you that the release is not yet published, and prints the mirror sync URL along with a command to verify the tag.

Step 2 — Synchronize the public mirror

Open the mirror settings and trigger a sync:

https://code.grail.tiberius.com/public/tibui/settings

Do this after every release. Until it completes, npm install ...#vX.Y.Z and any nix pipeline pinned to the new tag will fail to resolve, because the tag only exists on the private repo.

Verify the tag landed:

git ls-remote --tags https://code.grail.tiberius.com/public/tibui.git | grep vX.Y.Z

Manual release

If you need to release without the script, mirror what it does — in particular, do not skip the build or the forced dist/ add:

# 1. Clean tree on main, up to date
git checkout main
git pull origin main
git status --porcelain   # must be empty

# 2. Build, then bump the "version" field in package.json by hand
npm run build

# 3. Commit the bump together with the build output
git add package.json
git add -f dist/
git commit -m "chore: bump version to v1.0.0"

# 4. Push for a PR; after it is squash-merged, tag the merged commit on main
git push -u origin HEAD:release/v1.0.0
git fetch origin && git tag v1.0.0 origin/main
git push origin v1.0.0

Then complete Step 2.

Tag management

# List all tags
git tag

# Delete a local tag
git tag -d v1.0.0

# Delete a remote tag
git push origin --delete v1.0.0

# Create annotated tag with message
git tag -a v1.0.0 -m "Release v1.0.0"

If you delete or move a tag on the private repo, re-sync the mirror so it does not keep serving the old tag.