11# @man4ish/ui
22
3- Shared React component library for the [ OmniBioAI] ( https://github.com/man4ish/omnibioai-studio ) platform. Provides ` Button ` , ` Badge ` , ` Card ` , ` Input ` , ` StatusDot ` , and ` Spinner ` components built on unified design tokens with zero hardcoded colors.
3+ Shared React component library for the [ OmniBioAI] ( https://github.com/man4ish/omnibioai-studio ) platform. Provides ` Button ` , ` Badge ` , ` Card ` , ` Input ` , ` StatusDot ` , ` Spinner ` , ` Table ` , ` Tabs ` , ` ProgressBar ` , ` Tooltip ` , and ` Select ` components built on unified design tokens with zero hardcoded colors.
44
55---
66
@@ -10,6 +10,9 @@ Shared React component library for the [OmniBioAI](https://github.com/man4ish/om
1010- ** Design-token driven** — all colors, spacing, and radii come from ` @man4ish/design-tokens ` ; no hardcoded hex values anywhere in the library
1111- ** Tree-shakeable** — built as ES module + CJS with Vite library mode; only import what you use
1212- ** React 18+ peer dep** — works with any React 18+ project including the OmniBioAI Electron app and any downstream consumer
13+ - ** Fully tested** — 50+ unit tests with Vitest + React Testing Library
14+ - ** Storybook catalogue** — visual stories for every component and variant
15+ - ** Type-safe exports** — full ` .d.ts ` declarations via vite-plugin-dts
1316
1417---
1518
@@ -76,6 +79,8 @@ import { Button } from '@man4ish/ui';
7679| ` disabled ` | ` boolean ` | ` false ` | Disables button |
7780| ` onClick ` | ` () => void ` | — | Click handler |
7881
82+ > ** Note:** When ` loading ` is ` true ` , a ` Spinner ` is shown and the button is automatically disabled.
83+
7984---
8085
8186### ` Badge `
@@ -92,7 +97,9 @@ import { Badge } from '@man4ish/ui';
9297
9398| Prop | Type | Default | Description |
9499| ---| ---| ---| ---|
95- | ` variant ` | ` 'success' \| 'warning' \| 'danger' \| 'info' \| 'neutral' ` | ` 'neutral' ` | Semantic color |
100+ | ` variant ` | ` 'success' \| 'warning' \| 'danger' \| 'info' \| 'neutral' \| 'default' ` | ` 'neutral' ` | Semantic color |
101+
102+ > ** Note:** ` 'default' ` is a legacy alias for ` 'neutral' ` and maps to the same visual style.
96103
97104---
98105
@@ -162,11 +169,14 @@ import { StatusDot } from '@man4ish/ui';
162169<StatusDot status = " failed" />
163170<StatusDot status = " queued" />
164171<StatusDot status = " idle" />
172+
173+ <StatusDot status = " running" label = " Job in progress" />
165174```
166175
167- | Prop | Type | Description |
168- | ---| ---| ---|
169- | ` status ` | ` 'running' \| 'success' \| 'failed' \| 'queued' \| 'idle' ` | Determines color and animation |
176+ | Prop | Type | Default | Description |
177+ | ---| ---| ---| ---|
178+ | ` status ` | ` 'running' \| 'success' \| 'failed' \| 'queued' \| 'idle' ` | — | Determines color and animation |
179+ | ` label ` | ` string ` | — | Optional text label beside the dot |
170180
171181---
172182
@@ -186,12 +196,157 @@ import { Spinner } from '@man4ish/ui';
186196
187197---
188198
199+ ### ` Table `
200+
201+ Generic sortable, paginated table. Columns are fully typed.
202+
203+ ``` tsx
204+ import { Table } from ' @man4ish/ui' ;
205+ import type { Column } from ' @man4ish/ui' ;
206+
207+ const columns: Column <MyRow >[] = [
208+ { key: ' name' , label: ' Repository' , sortable: true },
209+ { key: ' code' , label: ' Code lines' , sortable: true , align: ' right' },
210+ { key: ' status' , label: ' Status' ,
211+ render : (v ) => <Badge variant = " success" >{ String (v )} </Badge > },
212+ ];
213+
214+ <Table columns = { columns } data = { rows } pageSize = { 10 } />
215+ ```
216+
217+ ** Props:**
218+
219+ | Prop | Type | Default | Description |
220+ | ---| ---| ---| ---|
221+ | ` columns ` | ` Column<T>[] ` | — | Column definitions |
222+ | ` data ` | ` T[] ` | — | Row data |
223+ | ` pageSize ` | ` number ` | ` 10 ` | Rows per page |
224+ | ` emptyMessage ` | ` string ` | ` 'No results' ` | Empty state text |
225+
226+ ** Column definition:**
227+
228+ | Key | Type | Default | Description |
229+ | ---| ---| ---| ---|
230+ | ` key ` | ` keyof T ` | — | Data key |
231+ | ` label ` | ` string ` | — | Column header text |
232+ | ` sortable ` | ` boolean ` | ` false ` | Enable sort on click |
233+ | ` align ` | ` 'left' \| 'right' ` | ` 'left' ` | Text alignment |
234+ | ` render ` | ` (value, row) => ReactNode ` | — | Custom cell renderer |
235+
236+ ---
237+
238+ ### ` Tabs `
239+
240+ ``` tsx
241+ import { Tabs } from ' @man4ish/ui' ;
242+ import type { Tab } from ' @man4ish/ui' ;
243+
244+ <Tabs
245+ tabs = { [
246+ { key: ' arch' , label: ' Architecture' , content: <ArchView /> },
247+ { key: ' health' , label: ' Health' , content: <HealthView /> },
248+ ]}
249+ defaultTab = " arch"
250+ onChange = { (key ) => console .log (' switched to' , key )}
251+ />
252+ ```
253+
254+ ** Props:**
255+
256+ | Prop | Type | Default | Description |
257+ | ---| ---| ---| ---|
258+ | ` tabs ` | ` Tab[] ` | — | Tab definitions |
259+ | ` defaultTab ` | ` string ` | first | Initially active tab key |
260+ | ` onChange ` | ` (key: string) => void ` | — | Called on tab switch |
261+
262+ ** Tab definition:**
263+
264+ | Key | Type | Default | Description |
265+ | ---| ---| ---| ---|
266+ | ` key ` | ` string ` | — | Unique identifier |
267+ | ` label ` | ` string ` | — | Tab button text |
268+ | ` content ` | ` ReactNode ` | — | Panel content |
269+
270+ ---
271+
272+ ### ` ProgressBar `
273+
274+ ``` tsx
275+ import { ProgressBar } from ' @man4ish/ui' ;
276+
277+ <ProgressBar value = { 98.7 } variant = " success" label = " 98.7%" />
278+ <ProgressBar value = { 60 } variant = " accent" />
279+ <ProgressBar value = { 25 } variant = " danger" size = " lg" />
280+ ```
281+
282+ | Prop | Type | Default | Description |
283+ | ---| ---| ---| ---|
284+ | ` value ` | ` number ` | — | Current value (0–max) |
285+ | ` max ` | ` number ` | ` 100 ` | Maximum value |
286+ | ` size ` | ` 'sm' \| 'md' \| 'lg' ` | ` 'md' ` | Bar height |
287+ | ` variant ` | ` 'success' \| 'danger' \| 'warning' \| 'accent' \| 'info' ` | ` 'accent' ` | Fill color |
288+ | ` showLabel ` | ` boolean ` | ` true ` | Show percentage label |
289+ | ` label ` | ` string ` | — | Override auto label text |
290+
291+ ---
292+
293+ ### ` Tooltip `
294+
295+ ``` tsx
296+ import { Tooltip } from ' @man4ish/ui' ;
297+
298+ <Tooltip content = " 27/27 services healthy" >
299+ <Badge variant = " success" >UP</Badge >
300+ </Tooltip >
301+ ```
302+
303+ | Prop | Type | Default | Description |
304+ | ---| ---| ---| ---|
305+ | ` content ` | ` string ` | — | Tooltip text shown on hover |
306+ | ` children ` | ` ReactNode ` | — | Element that triggers hover |
307+
308+ ---
309+
310+ ### ` Select `
311+
312+ ``` tsx
313+ import { Select } from ' @man4ish/ui' ;
314+ import type { SelectOption } from ' @man4ish/ui' ;
315+
316+ <Select
317+ label = " Category"
318+ options = { [
319+ { value: ' all' , label: ' All categories' },
320+ { value: ' core' , label: ' Core' },
321+ ]}
322+ value = { selected }
323+ onChange = { setSelected }
324+ placeholder = " Choose a category"
325+ />
326+ ```
327+
328+ | Prop | Type | Default | Description |
329+ | ---| ---| ---| ---|
330+ | ` options ` | ` SelectOption[] ` | — | Option list |
331+ | ` value ` | ` string ` | — | Controlled value |
332+ | ` onChange ` | ` (v: string) => void ` | — | Change handler |
333+ | ` label ` | ` string ` | — | Label above the select |
334+ | ` placeholder ` | ` string ` | — | Placeholder option |
335+ | ` disabled ` | ` boolean ` | ` false ` | Disables the select |
336+
337+ ---
338+
189339## Importing
190340
191341Everything is exported from the package root:
192342
193343``` ts
194- import { Button , Badge , Card , Input , StatusDot , Spinner } from ' @man4ish/ui' ;
344+ import {
345+ Button , Badge , Card , Input , StatusDot , Spinner ,
346+ Table , Tabs , ProgressBar , Tooltip , Select ,
347+ } from ' @man4ish/ui' ;
348+
349+ import type { Column , Tab , SelectOption } from ' @man4ish/ui' ;
195350```
196351
197352Tree-shaking is automatic — unused components are excluded from your bundle at build time.
@@ -210,6 +365,15 @@ npm run build
210365
211366# Watch mode (rebuilds on every save)
212367npm run dev
368+
369+ # Run tests
370+ npm run test
371+
372+ # Watch mode
373+ npm run test:watch
374+
375+ # View Storybook (visual catalogue of all components)
376+ npm run storybook
213377```
214378
215379Output lands in ` dist/ ` as ` index.js ` (ES module) and ` index.cjs ` (CommonJS) with ` index.d.ts ` type declarations.
@@ -232,17 +396,26 @@ npm link @man4ish/ui
232396```
233397omnibioai-ui/
234398├── src/
235- │ ├── index.ts ← package entry — re-exports all components
236- │ ├── Button/
237- │ ├── Badge/
238- │ ├── Card/
239- │ ├── Input/
240- │ ├── StatusDot/
241- │ └── Spinner/
242- ├── vite.config.ts ← library build config (ES + CJS, React external)
399+ │ ├── index.ts
400+ │ ├── test-setup.ts
401+ │ ├── components/
402+ │ │ ├── Button/ (Button.tsx, Button.css, Button.test.tsx, Button.stories.tsx)
403+ │ │ ├── Badge/ (Badge.tsx, Badge.css, Badge.test.tsx, Badge.stories.tsx)
404+ │ │ ├── Card/ (Card.tsx, Card.css, Card.test.tsx, Card.stories.tsx)
405+ │ │ ├── Input/ (Input.tsx, Input.css, Input.test.tsx, Input.stories.tsx)
406+ │ │ ├── StatusDot/ (StatusDot.tsx, StatusDot.css, StatusDot.test.tsx, StatusDot.stories.tsx)
407+ │ │ ├── Spinner/ (Spinner.tsx, Spinner.css, Spinner.test.tsx, Spinner.stories.tsx)
408+ │ │ ├── Table/ (Table.tsx, Table.css, Table.test.tsx, Table.stories.tsx)
409+ │ │ ├── Tabs/ (Tabs.tsx, Tabs.css, Tabs.test.tsx, Tabs.stories.tsx)
410+ │ │ ├── ProgressBar/ (ProgressBar.tsx, ProgressBar.css, ProgressBar.test.tsx, ProgressBar.stories.tsx)
411+ │ │ ├── Tooltip/ (Tooltip.tsx, Tooltip.css, Tooltip.test.tsx, Tooltip.stories.tsx)
412+ │ │ └── Select/ (Select.tsx, Select.css, Select.test.tsx, Select.stories.tsx)
413+ ├── .storybook/
414+ ├── vite.config.ts ← library build config
415+ ├── vitest.config.ts ← test config (separate from vite)
243416├── tsconfig.json
244- ├── package.json ← published as @man4ish/ui to GitHub Packages
245- └── .npmrc ← scoped registry config
417+ ├── CHANGELOG.md
418+ └── package.json
246419```
247420
248421---
@@ -264,6 +437,7 @@ Components reference CSS custom properties from `@man4ish/design-tokens`. No com
264437| [ ` @man4ish/design-tokens ` ] ( https://github.com/man4ish/omnibioai-design-tokens ) | CSS custom properties — required peer dependency |
265438| [ ` omnibioai-studio ` ] ( https://github.com/man4ish/omnibioai-studio ) | Electron + React app — primary consumer |
266439| [ ` omnibioai ` ] ( https://github.com/man4ish/omnibioai ) | Django backend — 150+ plugin bioinformatics platform |
440+ | ` omnibioai-control-center ` | Health dashboard + ecosystem report (consumes design tokens) |
267441
268442---
269443
0 commit comments