@trailofdad/morphkit-ui
v0.1.0
Published
React UI component library for morphkit genetic calculations.
Downloads
176
Maintainers
Readme
@trailofdad/morphkit-ui
React UI component library for reptile genetic calculations, powered by @trailofdad/morphkit.
Overview
morphkit-ui provides a self-contained <MorphkitCalculator> component that can be embedded inside any React or Next.js application. It exposes a Dam/Sire pairing interface, drives morphkit's Web Worker calculation pipeline, and renders offspring outcome cards with probability bars, possible-het markers, and lethality warnings.
Installation
npm install @trailofdad/morphkit-ui @trailofdad/morphkitImport the component styles once in your app entry:
import '@trailofdad/morphkit-ui/styles';Usage
Standalone (manual trait entry)
The simplest usage — no pre-populated animals. The user manually enters traits for each parent.
import { MorphkitCalculator } from '@trailofdad/morphkit-ui';
function App() {
return (
<MorphkitCalculator
workerUrl={new URL('./morphkit.worker.js', import.meta.url)}
dictionaryUrl="https://cdn.example.com/morphkit-dictionary.json"
/>
);
}CRM-injected mode
Pass pre-populated sire and dam props from your host application. Panels remain editable.
import { MorphkitCalculator } from '@trailofdad/morphkit-ui';
import type { AnimalInput } from '@trailofdad/morphkit-ui';
const sire: AnimalInput = {
id: 'animal-42',
sex: 'male',
genotype: [
{ locusId: 'pastel_complex', alleles: ['Pastel', 'Normal'] },
{ locusId: 'clown_complex', alleles: ['Clown', 'Clown'] },
],
polygenics: [],
};
const dam: AnimalInput = {
id: 'animal-17',
sex: 'female',
genotype: [
{ locusId: 'clown_complex', alleles: ['Clown', 'Normal'] },
],
polygenics: ['Jungle'],
};
function PairingPage() {
return (
<MorphkitCalculator
sire={sire}
dam={dam}
workerUrl={new URL('./morphkit.worker.js', import.meta.url)}
dictionaryUrl="https://cdn.example.com/morphkit-dictionary.json"
onResult={(output) => console.log(output.outcomes)}
onError={(err) => console.error(err)}
/>
);
}Passing a pre-fetched dictionary
If your host app already manages the dictionary (e.g. cached in a global store), pass it directly:
import { MorphkitCalculator } from '@trailofdad/morphkit-ui';
import type { MorphkitDictionary } from '@trailofdad/morphkit-ui';
declare const dictionary: MorphkitDictionary;
<MorphkitCalculator
dictionary={dictionary}
workerUrl={new URL('./morphkit.worker.js', import.meta.url)}
/>Props
| Prop | Type | Required | Description |
|---|---|---|---|
| workerUrl | URL \| string | ✅ | URL of the compiled morphkit Web Worker bundle |
| sire | AnimalInput | — | Pre-populated sire (editable in the UI) |
| dam | AnimalInput | — | Pre-populated dam (editable in the UI) |
| dictionary | MorphkitDictionary | — | Pre-fetched dictionary; takes precedence over dictionaryUrl |
| dictionaryUrl | string | — | CDN URL to fetch the dictionary from |
| theme | MorphkitTheme | — | CSS custom property overrides (see Theming) |
| onResult | (output: MorphkitCalculationOutput) => void | — | Called after a successful calculation |
| onError | (error: Error) => void | — | Called when a calculation or dictionary load fails |
| className | string | — | Additional CSS class applied to the root element |
One of dictionary or dictionaryUrl must be provided.
Theming
morphkit-ui uses CSS custom properties (prefixed --mk-*) scoped to the component root, so it does not pollute global styles. Override them via the theme prop:
<MorphkitCalculator
theme={{
primaryColor: '262 83% 58%', // HSL values without hsl() wrapper
borderRadius: '0.75rem',
fontFamily: 'Inter, sans-serif',
}}
{...rest}
/>For more control, override the CSS variables directly in your stylesheet:
.your-wrapper {
--mk-primary: 262 83% 58%;
--mk-radius: 0.75rem;
--mk-background: 240 10% 3.9%;
--mk-foreground: 0 0% 98%;
}The full list of variables is defined in src/index.css.
Development
# Install dependencies
npm install
# Link local morphkit for development
cd ../morphkit && npm link
cd ../morphkit-ui && npm link @trailofdad/morphkit
# Start dev server with fixture data
npm run dev
# Run tests
npm test
# Watch mode
npm run test:watch
# Build the library
npm run buildArchitecture
src/
├── index.ts # Package entry — exports + re-exports
├── types.ts # MorphkitUIProps, MorphkitTheme
├── components/
│ ├── MorphkitCalculator.tsx # Root component
│ ├── AnimalPanel/
│ │ ├── AnimalPanel.tsx # Dam / Sire form
│ │ └── LocusRow.tsx # Single locus + allele inputs
│ ├── ResultsPanel/
│ │ ├── ResultsPanel.tsx # Outcome list
│ │ ├── OutcomeCard.tsx # Single AggregatedOutcome
│ │ └── ProbabilityBar.tsx # Visual probability strip
│ └── ui/ # Radix-based shadcn primitives
├── hooks/
│ ├── useCalculator.ts # Drives calculateMorphsAsync
│ └── useDictionary.ts # Fetches / caches MorphkitDictionary
└── test/
├── setup.ts # jest-dom matchers
└── fixtures.ts # Shared test dataLicense
MIT
