Skip to content

hds-feminine-cycle-ui

LibraryGitHub

Custom UI for cervical-fluid / cycle-tracking events in the HDS ecosystem — render the same data as FEMM, Billings (BOM), Creighton Model, or Mira charts. Layout-agnostic: the same cell renderer is reused as a timeline marker, a form picker button, a diary-card glyph, or a calendar-grid cell. Hosts position it.

Also ships CervixPositionMarker — a standalone glyph for body-vulva-cervix-position 3-D vector events (height / firmness / openness).

The grids below show every option key each method renders, with English labels. They are auto-generated from the live spec by npm run docs:images (script: scripts/render-method-images.mjs) — run after editing a spec to keep docs in sync.

FEMM visual vocabulary Billings (BOM) visual vocabulary Creighton visual vocabulary

The full 33-code grid:

Creighton 33-code grid Mira visual vocabulary

Standalone React component — three dimensions encoded in one 28-px glyph following the SHOW mnemonic (Soft, High, Open, Wet):

  • Height → horizontal “horizon” bar y-position. Low = bar at top of cell (shallow reach), High = bar at bottom (deep reach).
  • Firmness → ring stroke width. Soft = thin (fertile), Firm = thick.
  • Openness → inner-hole radius. Open = large hole, Closed = solid + center dot.

Mean of the three signals tints the ring slate (infertile) → teal (fertile).

Cervix-position sample glyphs
import {
RepresentationCell, // cycle-fluid cells (dot-circle | stamp-square)
CervixPositionMarker, // 3-D vector → SHOW glyph
composeCellInput, // events → CellInput (half-and-half on overlap)
detectFertilityWindow, // sliding-window peak/fertile detection
registry, // built-in + user-extensible registrations
samplePreviewEvents, // shared 7-day fixture for previews
femmSpec, billingsSpec, creightonSpec, miraSpec
} from 'hds-feminine-cycle-ui';

When a stored event’s source method differs from the chosen rep’s bound method (e.g. Mira-imported data displayed under FEMM), pass a closestOption callback that wraps the host’s EuclidianDistanceEngine.fromVector:

const closestOption = (methodId, vectors) => {
const engine = model.converters.getEngine('cervical-fluid');
return String(engine.fromVector(methodId, vectors).data ?? '');
};
const input = composeCellInput(events, rep, { closestOption });

The host typically pre-loads the cervical-fluid engine via model.converters.ensureEngine('cervical-fluid') so the first render can force-convert synchronously.

  • ESM, "type": "module", Node ≥ 24, peer-dep React 19.
  • TypeScript source in ts/, built js/ is not in git (built via prepare: tsc).
  • No runtime dependency on hds-lib or data-model — the package builds standalone.