@alfadocs/ui-kit-debug 1.4.12 → 1.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/actions-cell-renderer-BD-jruqA.js +1784 -0
- package/dist/_chunks/actions-cell-renderer-BD-jruqA.js.map +1 -0
- package/dist/_chunks/{anamnesis-summary-rows-DAIpD0Or.js → anamnesis-summary-rows-B5MAYkJ-.js} +2150 -2092
- package/dist/_chunks/anamnesis-summary-rows-B5MAYkJ-.js.map +1 -0
- package/dist/_chunks/{bmi-calculator-CxPn0T0s.js → bmi-calculator-DC5SaqXT.js} +2 -2
- package/dist/_chunks/{bmi-calculator-CxPn0T0s.js.map → bmi-calculator-DC5SaqXT.js.map} +1 -1
- package/dist/_chunks/{cycle-calculator-D9M7IKfh.js → cycle-calculator-B_NlctlQ.js} +2 -2
- package/dist/_chunks/{cycle-calculator-D9M7IKfh.js.map → cycle-calculator-B_NlctlQ.js.map} +1 -1
- package/dist/_chunks/{due-date-calculator-BkqZEvL4.js → due-date-calculator-le1z3KpW.js} +2 -2
- package/dist/_chunks/{due-date-calculator-BkqZEvL4.js.map → due-date-calculator-le1z3KpW.js.map} +1 -1
- package/dist/_chunks/{fetal-weight-C7JXGg6E.js → fetal-weight-DXA6ZpMq.js} +2 -2
- package/dist/_chunks/{fetal-weight-C7JXGg6E.js.map → fetal-weight-DXA6ZpMq.js.map} +1 -1
- package/dist/_chunks/{file-manager-DzWYcRpE.js → file-manager-BjCM2fZB.js} +2 -2
- package/dist/_chunks/{file-manager-DzWYcRpE.js.map → file-manager-BjCM2fZB.js.map} +1 -1
- package/dist/_chunks/{hcg-doubling-CFJlMH7Z.js → hcg-doubling-BT6lki_i.js} +2 -2
- package/dist/_chunks/{hcg-doubling-CFJlMH7Z.js.map → hcg-doubling-BT6lki_i.js.map} +1 -1
- package/dist/_chunks/{link-cell-renderer-DCCca2m3.js → link-cell-renderer-C7GvyK66.js} +2 -2
- package/dist/_chunks/{link-cell-renderer-DCCca2m3.js.map → link-cell-renderer-C7GvyK66.js.map} +1 -1
- package/dist/_chunks/number-input-CM1q9zvH.js +414 -0
- package/dist/_chunks/number-input-CM1q9zvH.js.map +1 -0
- package/dist/_chunks/{optical-prescription-Brs0CeP3.js → optical-prescription-CQR_WJiS.js} +2 -2
- package/dist/_chunks/{optical-prescription-Brs0CeP3.js.map → optical-prescription-CQR_WJiS.js.map} +1 -1
- package/dist/_chunks/{patient-details-CGhnfdUB.js → patient-details-CnFgF3MU.js} +2 -2
- package/dist/_chunks/{patient-details-CGhnfdUB.js.map → patient-details-CnFgF3MU.js.map} +1 -1
- package/dist/_chunks/{patient-table-D2fhV4mV.js → patient-table-BXzcrC79.js} +3 -3
- package/dist/_chunks/{patient-table-D2fhV4mV.js.map → patient-table-BXzcrC79.js.map} +1 -1
- package/dist/_chunks/{pregnancy-dating-iI6_j2K2.js → pregnancy-dating-4tPV_Yko.js} +2 -2
- package/dist/_chunks/{pregnancy-dating-iI6_j2K2.js.map → pregnancy-dating-4tPV_Yko.js.map} +1 -1
- package/dist/_chunks/{pregnancy-weight-gain-Co-YFMJZ.js → pregnancy-weight-gain-BBgbWBGe.js} +2 -2
- package/dist/_chunks/{pregnancy-weight-gain-Co-YFMJZ.js.map → pregnancy-weight-gain-BBgbWBGe.js.map} +1 -1
- package/dist/_chunks/{signature-status-chip-DUcTgQ0E.js → signature-status-chip-DlLJk1VA.js} +16 -14
- package/dist/_chunks/signature-status-chip-DlLJk1VA.js.map +1 -0
- package/dist/_chunks/{unit-converter-BeTicruA.js → unit-converter-Dsk__pjA.js} +2 -2
- package/dist/_chunks/{unit-converter-BeTicruA.js.map → unit-converter-Dsk__pjA.js.map} +1 -1
- package/dist/agent-catalog.json +14 -8
- package/dist/agent-i18n/en.json +3 -2
- package/dist/components/bmi-calculator/index.js +1 -1
- package/dist/components/cycle-calculator/index.js +1 -1
- package/dist/components/data-table/data-table.agent.d.ts.map +1 -1
- package/dist/components/data-table/data-table.d.ts +19 -0
- package/dist/components/data-table/data-table.d.ts.map +1 -1
- package/dist/components/data-table/expanded-row-renderer.d.ts +47 -0
- package/dist/components/data-table/expanded-row-renderer.d.ts.map +1 -0
- package/dist/components/data-table/index.d.ts +2 -0
- package/dist/components/data-table/index.d.ts.map +1 -1
- package/dist/components/data-table/index.js +31 -27
- package/dist/components/due-date-calculator/index.js +1 -1
- package/dist/components/fetal-weight/index.js +1 -1
- package/dist/components/file-manager/index.js +1 -1
- package/dist/components/hcg-doubling/index.js +1 -1
- package/dist/components/number-input/index.js +1 -1
- package/dist/components/number-input/number-input.d.ts +11 -0
- package/dist/components/number-input/number-input.d.ts.map +1 -1
- package/dist/components/optical-prescription/index.js +1 -1
- package/dist/components/patient-details/index.js +1 -1
- package/dist/components/patient-table/index.js +1 -1
- package/dist/components/pregnancy-dating/index.js +1 -1
- package/dist/components/pregnancy-weight-gain/index.js +1 -1
- package/dist/components/signature-status-chip/index.js +1 -1
- package/dist/components/signature-status-chip/signature-status-chip.d.ts.map +1 -1
- package/dist/components/unit-converter/index.js +1 -1
- package/dist/host-compat.css +4 -1
- package/dist/i18n/locales/ar.d.ts +1 -0
- package/dist/i18n/locales/ar.d.ts.map +1 -1
- package/dist/i18n/locales/ar.js +1 -0
- package/dist/i18n/locales/ar.js.map +1 -1
- package/dist/i18n/locales/de.d.ts +1 -0
- package/dist/i18n/locales/de.d.ts.map +1 -1
- package/dist/i18n/locales/de.js +1 -0
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/el.d.ts +1 -0
- package/dist/i18n/locales/el.d.ts.map +1 -1
- package/dist/i18n/locales/el.js +1 -0
- package/dist/i18n/locales/el.js.map +1 -1
- package/dist/i18n/locales/en.d.ts +1 -0
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +1 -0
- package/dist/i18n/locales/en.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +1 -0
- package/dist/i18n/locales/es.d.ts.map +1 -1
- package/dist/i18n/locales/es.js +1 -0
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +1 -0
- package/dist/i18n/locales/fr.d.ts.map +1 -1
- package/dist/i18n/locales/fr.js +1 -0
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hi.d.ts +1 -0
- package/dist/i18n/locales/hi.d.ts.map +1 -1
- package/dist/i18n/locales/hi.js +1 -0
- package/dist/i18n/locales/hi.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +1 -0
- package/dist/i18n/locales/it.d.ts.map +1 -1
- package/dist/i18n/locales/it.js +1 -0
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/ja.d.ts +1 -0
- package/dist/i18n/locales/ja.d.ts.map +1 -1
- package/dist/i18n/locales/ja.js +1 -0
- package/dist/i18n/locales/ja.js.map +1 -1
- package/dist/i18n/locales/nl.d.ts +1 -0
- package/dist/i18n/locales/nl.d.ts.map +1 -1
- package/dist/i18n/locales/nl.js +1 -0
- package/dist/i18n/locales/nl.js.map +1 -1
- package/dist/i18n/locales/pl.d.ts +1 -0
- package/dist/i18n/locales/pl.d.ts.map +1 -1
- package/dist/i18n/locales/pl.js +1 -0
- package/dist/i18n/locales/pl.js.map +1 -1
- package/dist/i18n/locales/pt.d.ts +1 -0
- package/dist/i18n/locales/pt.d.ts.map +1 -1
- package/dist/i18n/locales/pt.js +1 -0
- package/dist/i18n/locales/pt.js.map +1 -1
- package/dist/i18n/locales/ro.d.ts +1 -0
- package/dist/i18n/locales/ro.d.ts.map +1 -1
- package/dist/i18n/locales/ro.js +1 -0
- package/dist/i18n/locales/ro.js.map +1 -1
- package/dist/i18n/locales/ru.d.ts +1 -0
- package/dist/i18n/locales/ru.d.ts.map +1 -1
- package/dist/i18n/locales/ru.js +1 -0
- package/dist/i18n/locales/ru.js.map +1 -1
- package/dist/i18n/locales/sq.d.ts +1 -0
- package/dist/i18n/locales/sq.d.ts.map +1 -1
- package/dist/i18n/locales/sq.js +1 -0
- package/dist/i18n/locales/sq.js.map +1 -1
- package/dist/i18n/locales/sv.d.ts +1 -0
- package/dist/i18n/locales/sv.d.ts.map +1 -1
- package/dist/i18n/locales/sv.js +1 -0
- package/dist/i18n/locales/sv.js.map +1 -1
- package/dist/i18n/locales/tr.d.ts +1 -0
- package/dist/i18n/locales/tr.d.ts.map +1 -1
- package/dist/i18n/locales/tr.js +1 -0
- package/dist/i18n/locales/tr.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +1 -0
- package/dist/i18n/locales/zh.d.ts.map +1 -1
- package/dist/i18n/locales/zh.js +1 -0
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.js +779 -775
- package/dist/locales/ar.json +1 -0
- package/dist/locales/de.json +1 -0
- package/dist/locales/el.json +1 -0
- package/dist/locales/en.json +1 -0
- package/dist/locales/es.json +1 -0
- package/dist/locales/fr.json +1 -0
- package/dist/locales/hi.json +1 -0
- package/dist/locales/it.json +1 -0
- package/dist/locales/ja.json +1 -0
- package/dist/locales/nl.json +1 -0
- package/dist/locales/pl.json +1 -0
- package/dist/locales/pt.json +1 -0
- package/dist/locales/ro.json +1 -0
- package/dist/locales/ru.json +1 -0
- package/dist/locales/sq.json +1 -0
- package/dist/locales/sv.json +1 -0
- package/dist/locales/tr.json +1 -0
- package/dist/locales/zh.json +1 -0
- package/dist/patterns/anamnesis/anamnesis-evolution.d.ts.map +1 -1
- package/dist/patterns/anamnesis/anamnesis-field.d.ts.map +1 -1
- package/dist/patterns/anamnesis/anamnesis-i18n.d.ts.map +1 -1
- package/dist/patterns/anamnesis/anamnesis-intake.d.ts +5 -1
- package/dist/patterns/anamnesis/anamnesis-intake.d.ts.map +1 -1
- package/dist/patterns/anamnesis/index.js +1 -1
- package/dist/tokens.css +5 -2
- package/package.json +1 -1
- package/dist/_chunks/actions-cell-renderer-C67oj7mR.js +0 -1581
- package/dist/_chunks/actions-cell-renderer-C67oj7mR.js.map +0 -1
- package/dist/_chunks/anamnesis-summary-rows-DAIpD0Or.js.map +0 -1
- package/dist/_chunks/number-input-DOe5VYei.js +0 -370
- package/dist/_chunks/number-input-DOe5VYei.js.map +0 -1
- package/dist/_chunks/signature-status-chip-DUcTgQ0E.js.map +0 -1
|
@@ -6,7 +6,7 @@ import { u as ce } from "./registry-DvAUVLHh.js";
|
|
|
6
6
|
import { R as E } from "./radio-TWf9Q-mp.js";
|
|
7
7
|
import { R as ue } from "./radio-group-BmIqhIT2.js";
|
|
8
8
|
import { F as G } from "./form-field-D1oqYisL.js";
|
|
9
|
-
import { N as L } from "./number-input-
|
|
9
|
+
import { N as L } from "./number-input-CM1q9zvH.js";
|
|
10
10
|
import { C as j } from "./card-DPmk26CL.js";
|
|
11
11
|
import { B as me } from "./badge-CIt-UFEx.js";
|
|
12
12
|
import { B as de, I as ge, b as pe } from "./insert-result-98J1QEp7.js";
|
|
@@ -431,4 +431,4 @@ we.displayName = "BmiCalculator";
|
|
|
431
431
|
export {
|
|
432
432
|
we as B
|
|
433
433
|
};
|
|
434
|
-
//# sourceMappingURL=bmi-calculator-
|
|
434
|
+
//# sourceMappingURL=bmi-calculator-DC5SaqXT.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bmi-calculator-CxPn0T0s.js","sources":["../../src/components/bmi-calculator/bmi-calculator.agent.ts","../../src/components/bmi-calculator/bmi-calculator.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — BmiCalculator. */\n/* */\n/* Height + weight → WHO body-mass-index. The agent-relevant surface is */\n/* the read-only computed result (bmi + WHO category) plus the canonical */\n/* metric inputs and the active unit system, with `set_value` actions to */\n/* drive height/weight and switch units. NO patient identity is exposed — */\n/* only the structural measurements and the derived index. The handle is */\n/* the curated `BmiCalculatorHandle`. See `src/docs/26-agent-readiness`. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { BmiCalculatorHandle } from './bmi-calculator';\n\nexport const bmiCalculatorAgent: AgentAdapter<BmiCalculatorHandle> = {\n id: 'bmi-calculator',\n capabilities: ['set_value', 'view_change'],\n state: {\n unitSystem: {\n type: \"'metric' | 'imperial'\",\n descriptionKey: 'ui.agent.bmiCalculator.state.unitSystem',\n description: 'Active unit system the inputs are entered in.',\n read: (handle) => handle.getUnitSystem(),\n },\n inputs: {\n type: '{ heightCm: number | null, weightKg: number | null }',\n descriptionKey: 'ui.agent.bmiCalculator.state.inputs',\n description:\n 'Canonical metric measurements regardless of the active unit system — height in centimetres and weight in kilograms, or null when unset.',\n read: (handle) => handle.getInputs(),\n },\n result: {\n type: '{ bmi: number, category: string } | null',\n descriptionKey: 'ui.agent.bmiCalculator.state.result',\n description:\n 'Computed BMI (kg/m²) and WHO category (underweight / normal / overweight / obese). Null until both height and weight are valid.',\n read: (handle) => handle.getResult(),\n },\n },\n actions: {\n set_value: {\n safety: 'write',\n argsType: '{ heightCm?: number | null, weightKg?: number | null }',\n argsSchema: {\n type: 'object',\n properties: {\n heightCm: {\n type: ['number', 'null'],\n description: 'Height in centimetres (canonical metric).',\n minimum: 0,\n },\n weightKg: {\n type: ['number', 'null'],\n description: 'Weight in kilograms (canonical metric).',\n minimum: 0,\n },\n },\n additionalProperties: false,\n },\n idempotent: true,\n descriptionKey: 'ui.agent.bmiCalculator.actions.setValue',\n description:\n 'Set height (cm) and/or weight (kg) in canonical metric units. Omitted fields are left unchanged.',\n examples: [\n {\n args: { heightCm: 175, weightKg: 72 },\n note: 'A 175 cm, 72 kg patient → BMI ~23.5 (normal).',\n },\n ],\n invoke: (\n handle,\n args: { heightCm?: number | null; weightKg?: number | null },\n ) => {\n handle.setMetric(args);\n },\n },\n set_unit_system: {\n safety: 'write',\n argsType: \"{ unitSystem: 'metric' | 'imperial' }\",\n argsSchema: {\n type: 'object',\n properties: {\n unitSystem: {\n enum: ['metric', 'imperial'],\n description: 'Unit system to display the inputs in.',\n },\n },\n required: ['unitSystem'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.bmiCalculator.actions.setUnitSystem',\n description:\n 'Switch the input unit system. Entered figures are preserved by conversion; the computed BMI is unchanged.',\n invoke: (handle, args: { unitSystem: 'metric' | 'imperial' }) => {\n handle.setUnitSystem(args.unitSystem);\n },\n },\n reset: {\n safety: 'write',\n idempotent: true,\n descriptionKey: 'ui.agent.bmiCalculator.actions.reset',\n description: 'Clear height and weight and the computed result.',\n invoke: (handle) => {\n handle.reset();\n },\n },\n get_result: {\n safety: 'read',\n returns: '{ bmi: number, category: string } | null',\n returnsSchema: {\n oneOf: [\n {\n type: 'object',\n properties: {\n bmi: { type: 'number', minimum: 0 },\n category: {\n enum: ['underweight', 'normal', 'overweight', 'obese'],\n },\n },\n required: ['bmi', 'category'],\n },\n { type: 'null' },\n ],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.bmiCalculator.actions.getResult',\n description:\n 'Return the computed BMI + WHO category, or null until both inputs are valid.',\n invoke: (handle) => handle.getResult(),\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'bmi-calculator',\n description: 'Marks the BmiCalculator wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the id prop. Required to address a specific calculator instance.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* BmiCalculator — height + weight → WHO body-mass-index, shown on a */\n/* banded-linear gauge. */\n/* */\n/* - Maths + unit conversion live in `./bmi` (pure, separately tested). */\n/* - Metric ⇄ imperial toggle persists the entered figures across the */\n/* switch by converting them (a patient measured in lb/ft doesn't */\n/* lose their numbers when a clinician flips to kg/cm). */\n/* - The gauge is the shared `BandedGauge`: a horizontal WHO-banded bar */\n/* (15–40) with a marker at the BMI's x-position. The SAME geometry */\n/* bakes into the inserted result-card PNG (banded variant), so the */\n/* on-screen widget and the rasterised card never drift. The band */\n/* fills come from semantic tokens (`--info` / `--success` / */\n/* `--warning-readable` / `--destructive`) — the contrast-safe */\n/* `--warning-readable` token handles the overweight orange in every */\n/* theme, so no `getComputedStyle` arc-colour sampling is needed. */\n/* ------------------------------------------------------------------ */\n\nimport { forwardRef, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { bmiCalculatorAgent } from './bmi-calculator.agent';\nimport { RadioGroup, Radio } from '../radio-group';\nimport { FormField } from '../form-field';\nimport { NumberInput } from '../number-input';\nimport { Card } from '../card';\nimport { Badge } from '../badge';\nimport {\n InsertButton,\n type InsertPayload,\n type InsertVariant,\n type InsertMode,\n} from '../_shared/insert-result';\nimport { BandedGauge, bmiBands } from '../_shared/banded-gauge';\nimport {\n type UnitSystem,\n type BmiCategory,\n computeBmi,\n bmiCategory,\n cmToFtIn,\n ftInToCm,\n kgToLb,\n lbToKg,\n} from './bmi';\n\n/* ------------------------------------------------------------------ */\n/* Result payload emitted to consumers */\n/* ------------------------------------------------------------------ */\n\nexport interface BmiResult {\n /** BMI in kg/m². */\n bmi: number;\n /** WHO category the BMI falls into. */\n category: BmiCategory;\n}\n\n/**\n * Curated imperative handle for agent / external automation. Reads/writes the\n * canonical metric measurements and the WHO result, and switches the display\n * unit system. Never exposes patient identity. Consumed by the\n * `bmi-calculator.agent.ts` adapter; the public `ref` stays the DOM element.\n */\nexport interface BmiCalculatorHandle {\n /** Active display unit system. */\n getUnitSystem: () => UnitSystem;\n /** Switch the display unit system (entered figures are converted, not lost). */\n setUnitSystem: (next: UnitSystem) => void;\n /** Canonical metric snapshot — height in cm and weight in kg, or null. */\n getInputs: () => { heightCm: number | null; weightKg: number | null };\n /** Set height (cm) and/or weight (kg) in canonical metric units. */\n setMetric: (next: {\n heightCm?: number | null;\n weightKg?: number | null;\n }) => void;\n /** Current computed result, or null until both inputs are valid. */\n getResult: () => BmiResult | null;\n /** Clear height and weight. */\n reset: () => void;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst rootVariants = cva('ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]', {\n variants: {\n width: {\n full: 'ds:w-full',\n auto: 'ds:inline-flex',\n },\n },\n defaultVariants: { width: 'full' },\n});\n\n/* ------------------------------------------------------------------ */\n/* Category → semantic intent for the Stat headline */\n/* ------------------------------------------------------------------ */\n\nconst CATEGORY_BADGE: Record<\n BmiCategory,\n 'info' | 'success' | 'warning' | 'error'\n> = {\n underweight: 'info',\n normal: 'success',\n overweight: 'warning',\n obese: 'error',\n};\n\n/* ------------------------------------------------------------------ */\n/* Category → semantic band token. */\n/* */\n/* The four WHO bands carry these tokens both on-screen (the shared */\n/* `bmiBands()` definition fills each zone with the same name) and in */\n/* the card chip's `highlightToken`. `overweight` uses */\n/* `--warning-readable` — the kit's contrast-safe orange that already */\n/* resolves correctly per theme (orange-600 in light/non-accessible, */\n/* `--warning` elsewhere), so NO `getComputedStyle` arc sampling or */\n/* `document.documentElement` override is needed. */\n/* ------------------------------------------------------------------ */\n\nconst CATEGORY_TOKEN: Record<BmiCategory, string> = {\n underweight: '--info',\n normal: '--success',\n overweight: '--warning-readable',\n obese: '--destructive',\n};\n\nexport interface BmiCalculatorProps extends VariantProps<typeof rootVariants> {\n /** Initial unit system. Defaults to `'metric'`. */\n defaultUnitSystem?: UnitSystem;\n /** Fires whenever a valid BMI can be computed (and with `null` when it can't). */\n onResultChange?: (result: BmiResult | null) => void;\n /** When provided, shows an \"Insert\" button that emits the result for an editor. */\n onInsert?: (payload: InsertPayload) => void;\n /**\n * Which verb the result button performs. Defaults to `'insert'`.\n * Use `'copy'` in an app-shell surface (no editor to insert into) — the\n * button writes the result to the clipboard as a multi-format `ClipboardItem`.\n */\n insertVariant?: InsertVariant;\n /** `copy` variant only — fired after a successful clipboard write. */\n onCopy?: (mode: InsertMode) => void;\n /** `copy` variant only — fired if the clipboard write can't proceed. */\n onError?: (error: unknown) => void;\n /**\n * Brand wordmark printed in the inserted/copied result-card footer.\n * Omitted → no brand line (and no footer hairline); a string → that custom\n * brand; `false` → no brand line. Brand is opt-in.\n */\n insertBrand?: string | false;\n /** Opaque instance id, emitted as `data-component-id`. */\n id?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n}\n\n/** Round to one decimal place — used when seeding a unit-switch. */\nconst round1 = (n: number): number => Math.round(n * 10) / 10;\n\nexport const BmiCalculator = forwardRef<HTMLDivElement, BmiCalculatorProps>(\n (\n {\n defaultUnitSystem = 'metric',\n onResultChange,\n onInsert,\n insertVariant = 'insert',\n onCopy,\n onError,\n insertBrand,\n id,\n width,\n className,\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation();\n const heightGroupId = useId();\n\n const [unitSystem, setUnitSystem] = useState<UnitSystem>(defaultUnitSystem);\n\n // Raw per-system inputs. Metric is canonical for cm/kg; imperial keeps\n // ft + in + lb so typing isn't fought by rounding round-trips.\n const [heightCm, setHeightCm] = useState<number | null>(null);\n const [weightKg, setWeightKg] = useState<number | null>(null);\n const [heightFt, setHeightFt] = useState<number | null>(null);\n const [heightIn, setHeightIn] = useState<number | null>(null);\n const [weightLb, setWeightLb] = useState<number | null>(null);\n\n const handleUnitChange = (next: string): void => {\n const target = next as UnitSystem;\n if (target === unitSystem) return;\n if (target === 'imperial') {\n if (heightCm !== null) {\n const { ft, in: inches } = cmToFtIn(heightCm);\n setHeightFt(ft);\n setHeightIn(round1(inches));\n }\n if (weightKg !== null) setWeightLb(round1(kgToLb(weightKg)));\n } else {\n if (heightFt !== null || heightIn !== null) {\n setHeightCm(round1(ftInToCm(heightFt ?? 0, heightIn ?? 0)));\n }\n if (weightLb !== null) setWeightKg(round1(lbToKg(weightLb)));\n }\n setUnitSystem(target);\n };\n\n /* Canonical metric figures for the active system. */\n const canonicalHeightCm =\n unitSystem === 'metric'\n ? heightCm\n : heightFt !== null || heightIn !== null\n ? ftInToCm(heightFt ?? 0, heightIn ?? 0)\n : null;\n const canonicalWeightKg =\n unitSystem === 'metric'\n ? weightKg\n : weightLb !== null\n ? lbToKg(weightLb)\n : null;\n\n const bmi = computeBmi(canonicalWeightKg, canonicalHeightCm);\n const category = bmi !== null ? bmiCategory(bmi) : null;\n\n const bmiFormatter = useMemo(\n () =>\n new Intl.NumberFormat(i18n.language, {\n minimumFractionDigits: 1,\n maximumFractionDigits: 1,\n }),\n [i18n.language],\n );\n\n // Notify consumers without re-firing on unrelated re-renders.\n useEffect(() => {\n onResultChange?.(\n bmi !== null && category !== null ? { bmi, category } : null,\n );\n }, [bmi, category, onResultChange]);\n\n // Live refs so the once-built agent handle reads/writes current state\n // without re-creating on every keystroke. Public `ref` stays the DOM node.\n const liveRef = useRef({\n unitSystem,\n canonicalHeightCm,\n canonicalWeightKg,\n bmi,\n category,\n handleUnitChange,\n });\n liveRef.current = {\n unitSystem,\n canonicalHeightCm,\n canonicalWeightKg,\n bmi,\n category,\n handleUnitChange,\n };\n const agentHandle = useMemo<BmiCalculatorHandle>(\n () => ({\n getUnitSystem: () => liveRef.current.unitSystem,\n setUnitSystem: (next) => liveRef.current.handleUnitChange(next),\n getInputs: () => ({\n heightCm: liveRef.current.canonicalHeightCm,\n weightKg: liveRef.current.canonicalWeightKg,\n }),\n setMetric: (next) => {\n // Write canonical metric figures into whichever raw store the\n // active unit system reads from, so the on-screen inputs reflect\n // the change without losing the user's chosen unit display.\n if ('heightCm' in next) {\n const cm = next.heightCm;\n if (liveRef.current.unitSystem === 'metric') {\n setHeightCm(cm ?? null);\n } else if (cm === null || cm === undefined) {\n setHeightFt(null);\n setHeightIn(null);\n } else {\n const { ft, in: inches } = cmToFtIn(cm);\n setHeightFt(ft);\n setHeightIn(round1(inches));\n }\n }\n if ('weightKg' in next) {\n const kg = next.weightKg;\n if (liveRef.current.unitSystem === 'metric') {\n setWeightKg(kg ?? null);\n } else {\n setWeightLb(\n kg === null || kg === undefined ? null : round1(kgToLb(kg)),\n );\n }\n }\n },\n getResult: () => {\n const { bmi: b, category: c } = liveRef.current;\n return b !== null && c !== null ? { bmi: b, category: c } : null;\n },\n reset: () => {\n setHeightCm(null);\n setWeightKg(null);\n setHeightFt(null);\n setHeightIn(null);\n setWeightLb(null);\n },\n }),\n [],\n );\n useAgentRegistration(bmiCalculatorAgent, agentHandle, id);\n\n const isMetric = unitSystem === 'metric';\n\n // Pre-translated gauge labels, shared by the on-screen widget and the\n // inserted card so both surfaces read identically. The shared `BandedGauge`\n // is i18n-agnostic — every visible string arrives already through `t()`.\n const gauge = useMemo(() => {\n if (bmi === null || category === null) return null;\n const { bands, min, max, ticks } = bmiBands();\n const valueLabel = bmiFormatter.format(bmi);\n const categoryLabel = t(`bmiCalculator.category.${category}`);\n const rangeLabel = t(`bmiCalculator.range.${category}`);\n const ariaLabel = t('bmiCalculator.gaugeAria', {\n bmi: valueLabel,\n category: categoryLabel,\n range: rangeLabel,\n });\n return {\n value: bmi,\n bands,\n min,\n max,\n ticks,\n valueLabel,\n categoryLabel,\n rangeLabel,\n ariaLabel,\n };\n }, [bmi, category, bmiFormatter, t]);\n\n return (\n <div\n ref={ref}\n data-component=\"bmi-calculator\"\n data-component-id={id}\n className={rootVariants({ width, className })}\n >\n <RadioGroup\n label={t('bmiCalculator.unitSystem.label')}\n variant=\"horizontal\"\n value={unitSystem}\n onValueChange={handleUnitChange}\n >\n <Radio label={t('bmiCalculator.unitSystem.metric')} value=\"metric\" />\n <Radio\n label={t('bmiCalculator.unitSystem.imperial')}\n value=\"imperial\"\n />\n </RadioGroup>\n\n <div className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:sm:grid-cols-2\">\n {isMetric ? (\n <FormField\n label={`${t('bmiCalculator.height')} (${t('bmiCalculator.units.cm')})`}\n >\n <NumberInput\n mode=\"decimal\"\n min={0}\n step={0.5}\n value={heightCm}\n onChange={setHeightCm}\n />\n </FormField>\n ) : (\n <div role=\"group\" aria-labelledby={heightGroupId}>\n <span\n id={heightGroupId}\n className=\"type-label ds:mb-[var(--spacing-xs)] ds:block ds:text-foreground\"\n >\n {t('bmiCalculator.height')}\n </span>\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n <NumberInput\n mode=\"integer\"\n min={0}\n value={heightFt}\n onChange={setHeightFt}\n aria-label={t('bmiCalculator.feet')}\n />\n <span className=\"type-label ds:text-muted-foreground\">\n {t('bmiCalculator.units.ft')}\n </span>\n <NumberInput\n mode=\"decimal\"\n min={0}\n max={11.9}\n step={0.5}\n value={heightIn}\n onChange={setHeightIn}\n aria-label={t('bmiCalculator.inches')}\n />\n <span className=\"type-label ds:text-muted-foreground\">\n {t('bmiCalculator.units.in')}\n </span>\n </div>\n </div>\n )}\n\n <FormField\n label={`${t('bmiCalculator.weight')} (${t(\n isMetric ? 'bmiCalculator.units.kg' : 'bmiCalculator.units.lb',\n )})`}\n >\n <NumberInput\n mode=\"decimal\"\n min={0}\n step={isMetric ? 0.1 : 0.5}\n value={isMetric ? weightKg : weightLb}\n onChange={isMetric ? setWeightKg : setWeightLb}\n />\n </FormField>\n </div>\n\n {/* Concise polite announcement when the result resolves — the gauge\n itself stays out of the live region to avoid re-reading on every\n keystroke. */}\n <p className=\"ds:sr-only\" role=\"status\" aria-live=\"polite\">\n {gauge ? gauge.ariaLabel : ''}\n </p>\n\n {bmi !== null && category !== null && gauge !== null ? (\n <Card variant=\"elevated\">\n <Card.Body className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-md)]\">\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-xs)] ds:text-center\">\n <span className=\"type-label ds:text-muted-foreground\">\n {t('bmiCalculator.category.label')}\n </span>\n <Badge variant={CATEGORY_BADGE[category]} size=\"lg\">\n {t(`bmiCalculator.category.${category}`)}\n </Badge>\n <p className=\"type-body ds:text-muted-foreground\">\n {gauge.rangeLabel}\n </p>\n </div>\n {/* `data-bmi-category` exposes the WHO band so the gauge's\n semantic colour is assertable without sampling pixels. The\n shared BandedGauge fills each zone via `var(<token>)`, so a\n theme switch repaints the bands with no JS re-sample. */}\n <div\n data-bmi-category={category}\n className=\"ds:w-full ds:max-w-[320px]\"\n >\n <BandedGauge model={gauge} className=\"ds:w-full\" />\n </div>\n {insertVariant === 'copy' || onInsert ? (\n <InsertButton\n onInsert={onInsert}\n variant={insertVariant}\n onCopy={onCopy}\n onError={onError}\n card={{\n title: t('insert.title.bmi'),\n icon: 'scale',\n highlight: t(`bmiCalculator.category.${category}`),\n // Chip shares the WHO-category semantic token so the\n // inserted PNG chip matches the on-screen band colour.\n highlightToken: CATEGORY_TOKEN[category],\n brand: insertBrand,\n // Banded gauge: the SAME geometry + WHO bands as the\n // on-screen widget, baked into the card PNG with\n // probe-resolved theme colours.\n gauge: {\n variant: 'banded',\n value: bmi,\n bands: gauge.bands,\n min: gauge.min,\n max: gauge.max,\n valueLabel: gauge.valueLabel,\n categoryLabel: gauge.categoryLabel,\n rangeLabel: gauge.rangeLabel,\n ariaLabel: gauge.ariaLabel,\n ticks: gauge.ticks,\n },\n fields: [\n {\n // Mirrors the on-screen scale glyph + header icon.\n icon: 'scale',\n label: t('insert.title.bmi'),\n value: gauge.valueLabel,\n },\n {\n // WHO band is a classification → tag glyph.\n icon: 'tag',\n label: t('bmiCalculator.category.label'),\n value: gauge.categoryLabel,\n },\n ],\n }}\n />\n ) : null}\n </Card.Body>\n </Card>\n ) : (\n <p className=\"type-body ds:text-muted-foreground\">\n {t('bmiCalculator.empty')}\n </p>\n )}\n </div>\n );\n },\n);\n\nBmiCalculator.displayName = 'BmiCalculator';\n"],"names":["bmiCalculatorAgent","handle","args","rootVariants","cva","CATEGORY_BADGE","CATEGORY_TOKEN","round1","n","BmiCalculator","forwardRef","defaultUnitSystem","onResultChange","onInsert","insertVariant","onCopy","onError","insertBrand","id","width","className","ref","t","i18n","useTranslation","heightGroupId","useId","unitSystem","setUnitSystem","useState","heightCm","setHeightCm","weightKg","setWeightKg","heightFt","setHeightFt","heightIn","setHeightIn","weightLb","setWeightLb","handleUnitChange","next","target","ft","inches","cmToFtIn","kgToLb","ftInToCm","lbToKg","canonicalHeightCm","canonicalWeightKg","bmi","computeBmi","category","bmiCategory","bmiFormatter","useMemo","useEffect","liveRef","useRef","agentHandle","cm","kg","b","c","useAgentRegistration","isMetric","gauge","bands","min","max","ticks","bmiBands","valueLabel","categoryLabel","rangeLabel","ariaLabel","jsxs","RadioGroup","jsx","Radio","FormField","NumberInput","Card","Badge","BandedGauge","InsertButton"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bmi-calculator-DC5SaqXT.js","sources":["../../src/components/bmi-calculator/bmi-calculator.agent.ts","../../src/components/bmi-calculator/bmi-calculator.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — BmiCalculator. */\n/* */\n/* Height + weight → WHO body-mass-index. The agent-relevant surface is */\n/* the read-only computed result (bmi + WHO category) plus the canonical */\n/* metric inputs and the active unit system, with `set_value` actions to */\n/* drive height/weight and switch units. NO patient identity is exposed — */\n/* only the structural measurements and the derived index. The handle is */\n/* the curated `BmiCalculatorHandle`. See `src/docs/26-agent-readiness`. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { BmiCalculatorHandle } from './bmi-calculator';\n\nexport const bmiCalculatorAgent: AgentAdapter<BmiCalculatorHandle> = {\n id: 'bmi-calculator',\n capabilities: ['set_value', 'view_change'],\n state: {\n unitSystem: {\n type: \"'metric' | 'imperial'\",\n descriptionKey: 'ui.agent.bmiCalculator.state.unitSystem',\n description: 'Active unit system the inputs are entered in.',\n read: (handle) => handle.getUnitSystem(),\n },\n inputs: {\n type: '{ heightCm: number | null, weightKg: number | null }',\n descriptionKey: 'ui.agent.bmiCalculator.state.inputs',\n description:\n 'Canonical metric measurements regardless of the active unit system — height in centimetres and weight in kilograms, or null when unset.',\n read: (handle) => handle.getInputs(),\n },\n result: {\n type: '{ bmi: number, category: string } | null',\n descriptionKey: 'ui.agent.bmiCalculator.state.result',\n description:\n 'Computed BMI (kg/m²) and WHO category (underweight / normal / overweight / obese). Null until both height and weight are valid.',\n read: (handle) => handle.getResult(),\n },\n },\n actions: {\n set_value: {\n safety: 'write',\n argsType: '{ heightCm?: number | null, weightKg?: number | null }',\n argsSchema: {\n type: 'object',\n properties: {\n heightCm: {\n type: ['number', 'null'],\n description: 'Height in centimetres (canonical metric).',\n minimum: 0,\n },\n weightKg: {\n type: ['number', 'null'],\n description: 'Weight in kilograms (canonical metric).',\n minimum: 0,\n },\n },\n additionalProperties: false,\n },\n idempotent: true,\n descriptionKey: 'ui.agent.bmiCalculator.actions.setValue',\n description:\n 'Set height (cm) and/or weight (kg) in canonical metric units. Omitted fields are left unchanged.',\n examples: [\n {\n args: { heightCm: 175, weightKg: 72 },\n note: 'A 175 cm, 72 kg patient → BMI ~23.5 (normal).',\n },\n ],\n invoke: (\n handle,\n args: { heightCm?: number | null; weightKg?: number | null },\n ) => {\n handle.setMetric(args);\n },\n },\n set_unit_system: {\n safety: 'write',\n argsType: \"{ unitSystem: 'metric' | 'imperial' }\",\n argsSchema: {\n type: 'object',\n properties: {\n unitSystem: {\n enum: ['metric', 'imperial'],\n description: 'Unit system to display the inputs in.',\n },\n },\n required: ['unitSystem'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.bmiCalculator.actions.setUnitSystem',\n description:\n 'Switch the input unit system. Entered figures are preserved by conversion; the computed BMI is unchanged.',\n invoke: (handle, args: { unitSystem: 'metric' | 'imperial' }) => {\n handle.setUnitSystem(args.unitSystem);\n },\n },\n reset: {\n safety: 'write',\n idempotent: true,\n descriptionKey: 'ui.agent.bmiCalculator.actions.reset',\n description: 'Clear height and weight and the computed result.',\n invoke: (handle) => {\n handle.reset();\n },\n },\n get_result: {\n safety: 'read',\n returns: '{ bmi: number, category: string } | null',\n returnsSchema: {\n oneOf: [\n {\n type: 'object',\n properties: {\n bmi: { type: 'number', minimum: 0 },\n category: {\n enum: ['underweight', 'normal', 'overweight', 'obese'],\n },\n },\n required: ['bmi', 'category'],\n },\n { type: 'null' },\n ],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.bmiCalculator.actions.getResult',\n description:\n 'Return the computed BMI + WHO category, or null until both inputs are valid.',\n invoke: (handle) => handle.getResult(),\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'bmi-calculator',\n description: 'Marks the BmiCalculator wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the id prop. Required to address a specific calculator instance.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* BmiCalculator — height + weight → WHO body-mass-index, shown on a */\n/* banded-linear gauge. */\n/* */\n/* - Maths + unit conversion live in `./bmi` (pure, separately tested). */\n/* - Metric ⇄ imperial toggle persists the entered figures across the */\n/* switch by converting them (a patient measured in lb/ft doesn't */\n/* lose their numbers when a clinician flips to kg/cm). */\n/* - The gauge is the shared `BandedGauge`: a horizontal WHO-banded bar */\n/* (15–40) with a marker at the BMI's x-position. The SAME geometry */\n/* bakes into the inserted result-card PNG (banded variant), so the */\n/* on-screen widget and the rasterised card never drift. The band */\n/* fills come from semantic tokens (`--info` / `--success` / */\n/* `--warning-readable` / `--destructive`) — the contrast-safe */\n/* `--warning-readable` token handles the overweight orange in every */\n/* theme, so no `getComputedStyle` arc-colour sampling is needed. */\n/* ------------------------------------------------------------------ */\n\nimport { forwardRef, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { bmiCalculatorAgent } from './bmi-calculator.agent';\nimport { RadioGroup, Radio } from '../radio-group';\nimport { FormField } from '../form-field';\nimport { NumberInput } from '../number-input';\nimport { Card } from '../card';\nimport { Badge } from '../badge';\nimport {\n InsertButton,\n type InsertPayload,\n type InsertVariant,\n type InsertMode,\n} from '../_shared/insert-result';\nimport { BandedGauge, bmiBands } from '../_shared/banded-gauge';\nimport {\n type UnitSystem,\n type BmiCategory,\n computeBmi,\n bmiCategory,\n cmToFtIn,\n ftInToCm,\n kgToLb,\n lbToKg,\n} from './bmi';\n\n/* ------------------------------------------------------------------ */\n/* Result payload emitted to consumers */\n/* ------------------------------------------------------------------ */\n\nexport interface BmiResult {\n /** BMI in kg/m². */\n bmi: number;\n /** WHO category the BMI falls into. */\n category: BmiCategory;\n}\n\n/**\n * Curated imperative handle for agent / external automation. Reads/writes the\n * canonical metric measurements and the WHO result, and switches the display\n * unit system. Never exposes patient identity. Consumed by the\n * `bmi-calculator.agent.ts` adapter; the public `ref` stays the DOM element.\n */\nexport interface BmiCalculatorHandle {\n /** Active display unit system. */\n getUnitSystem: () => UnitSystem;\n /** Switch the display unit system (entered figures are converted, not lost). */\n setUnitSystem: (next: UnitSystem) => void;\n /** Canonical metric snapshot — height in cm and weight in kg, or null. */\n getInputs: () => { heightCm: number | null; weightKg: number | null };\n /** Set height (cm) and/or weight (kg) in canonical metric units. */\n setMetric: (next: {\n heightCm?: number | null;\n weightKg?: number | null;\n }) => void;\n /** Current computed result, or null until both inputs are valid. */\n getResult: () => BmiResult | null;\n /** Clear height and weight. */\n reset: () => void;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst rootVariants = cva('ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]', {\n variants: {\n width: {\n full: 'ds:w-full',\n auto: 'ds:inline-flex',\n },\n },\n defaultVariants: { width: 'full' },\n});\n\n/* ------------------------------------------------------------------ */\n/* Category → semantic intent for the Stat headline */\n/* ------------------------------------------------------------------ */\n\nconst CATEGORY_BADGE: Record<\n BmiCategory,\n 'info' | 'success' | 'warning' | 'error'\n> = {\n underweight: 'info',\n normal: 'success',\n overweight: 'warning',\n obese: 'error',\n};\n\n/* ------------------------------------------------------------------ */\n/* Category → semantic band token. */\n/* */\n/* The four WHO bands carry these tokens both on-screen (the shared */\n/* `bmiBands()` definition fills each zone with the same name) and in */\n/* the card chip's `highlightToken`. `overweight` uses */\n/* `--warning-readable` — the kit's contrast-safe orange that already */\n/* resolves correctly per theme (orange-600 in light/non-accessible, */\n/* `--warning` elsewhere), so NO `getComputedStyle` arc sampling or */\n/* `document.documentElement` override is needed. */\n/* ------------------------------------------------------------------ */\n\nconst CATEGORY_TOKEN: Record<BmiCategory, string> = {\n underweight: '--info',\n normal: '--success',\n overweight: '--warning-readable',\n obese: '--destructive',\n};\n\nexport interface BmiCalculatorProps extends VariantProps<typeof rootVariants> {\n /** Initial unit system. Defaults to `'metric'`. */\n defaultUnitSystem?: UnitSystem;\n /** Fires whenever a valid BMI can be computed (and with `null` when it can't). */\n onResultChange?: (result: BmiResult | null) => void;\n /** When provided, shows an \"Insert\" button that emits the result for an editor. */\n onInsert?: (payload: InsertPayload) => void;\n /**\n * Which verb the result button performs. Defaults to `'insert'`.\n * Use `'copy'` in an app-shell surface (no editor to insert into) — the\n * button writes the result to the clipboard as a multi-format `ClipboardItem`.\n */\n insertVariant?: InsertVariant;\n /** `copy` variant only — fired after a successful clipboard write. */\n onCopy?: (mode: InsertMode) => void;\n /** `copy` variant only — fired if the clipboard write can't proceed. */\n onError?: (error: unknown) => void;\n /**\n * Brand wordmark printed in the inserted/copied result-card footer.\n * Omitted → no brand line (and no footer hairline); a string → that custom\n * brand; `false` → no brand line. Brand is opt-in.\n */\n insertBrand?: string | false;\n /** Opaque instance id, emitted as `data-component-id`. */\n id?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n}\n\n/** Round to one decimal place — used when seeding a unit-switch. */\nconst round1 = (n: number): number => Math.round(n * 10) / 10;\n\nexport const BmiCalculator = forwardRef<HTMLDivElement, BmiCalculatorProps>(\n (\n {\n defaultUnitSystem = 'metric',\n onResultChange,\n onInsert,\n insertVariant = 'insert',\n onCopy,\n onError,\n insertBrand,\n id,\n width,\n className,\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation();\n const heightGroupId = useId();\n\n const [unitSystem, setUnitSystem] = useState<UnitSystem>(defaultUnitSystem);\n\n // Raw per-system inputs. Metric is canonical for cm/kg; imperial keeps\n // ft + in + lb so typing isn't fought by rounding round-trips.\n const [heightCm, setHeightCm] = useState<number | null>(null);\n const [weightKg, setWeightKg] = useState<number | null>(null);\n const [heightFt, setHeightFt] = useState<number | null>(null);\n const [heightIn, setHeightIn] = useState<number | null>(null);\n const [weightLb, setWeightLb] = useState<number | null>(null);\n\n const handleUnitChange = (next: string): void => {\n const target = next as UnitSystem;\n if (target === unitSystem) return;\n if (target === 'imperial') {\n if (heightCm !== null) {\n const { ft, in: inches } = cmToFtIn(heightCm);\n setHeightFt(ft);\n setHeightIn(round1(inches));\n }\n if (weightKg !== null) setWeightLb(round1(kgToLb(weightKg)));\n } else {\n if (heightFt !== null || heightIn !== null) {\n setHeightCm(round1(ftInToCm(heightFt ?? 0, heightIn ?? 0)));\n }\n if (weightLb !== null) setWeightKg(round1(lbToKg(weightLb)));\n }\n setUnitSystem(target);\n };\n\n /* Canonical metric figures for the active system. */\n const canonicalHeightCm =\n unitSystem === 'metric'\n ? heightCm\n : heightFt !== null || heightIn !== null\n ? ftInToCm(heightFt ?? 0, heightIn ?? 0)\n : null;\n const canonicalWeightKg =\n unitSystem === 'metric'\n ? weightKg\n : weightLb !== null\n ? lbToKg(weightLb)\n : null;\n\n const bmi = computeBmi(canonicalWeightKg, canonicalHeightCm);\n const category = bmi !== null ? bmiCategory(bmi) : null;\n\n const bmiFormatter = useMemo(\n () =>\n new Intl.NumberFormat(i18n.language, {\n minimumFractionDigits: 1,\n maximumFractionDigits: 1,\n }),\n [i18n.language],\n );\n\n // Notify consumers without re-firing on unrelated re-renders.\n useEffect(() => {\n onResultChange?.(\n bmi !== null && category !== null ? { bmi, category } : null,\n );\n }, [bmi, category, onResultChange]);\n\n // Live refs so the once-built agent handle reads/writes current state\n // without re-creating on every keystroke. Public `ref` stays the DOM node.\n const liveRef = useRef({\n unitSystem,\n canonicalHeightCm,\n canonicalWeightKg,\n bmi,\n category,\n handleUnitChange,\n });\n liveRef.current = {\n unitSystem,\n canonicalHeightCm,\n canonicalWeightKg,\n bmi,\n category,\n handleUnitChange,\n };\n const agentHandle = useMemo<BmiCalculatorHandle>(\n () => ({\n getUnitSystem: () => liveRef.current.unitSystem,\n setUnitSystem: (next) => liveRef.current.handleUnitChange(next),\n getInputs: () => ({\n heightCm: liveRef.current.canonicalHeightCm,\n weightKg: liveRef.current.canonicalWeightKg,\n }),\n setMetric: (next) => {\n // Write canonical metric figures into whichever raw store the\n // active unit system reads from, so the on-screen inputs reflect\n // the change without losing the user's chosen unit display.\n if ('heightCm' in next) {\n const cm = next.heightCm;\n if (liveRef.current.unitSystem === 'metric') {\n setHeightCm(cm ?? null);\n } else if (cm === null || cm === undefined) {\n setHeightFt(null);\n setHeightIn(null);\n } else {\n const { ft, in: inches } = cmToFtIn(cm);\n setHeightFt(ft);\n setHeightIn(round1(inches));\n }\n }\n if ('weightKg' in next) {\n const kg = next.weightKg;\n if (liveRef.current.unitSystem === 'metric') {\n setWeightKg(kg ?? null);\n } else {\n setWeightLb(\n kg === null || kg === undefined ? null : round1(kgToLb(kg)),\n );\n }\n }\n },\n getResult: () => {\n const { bmi: b, category: c } = liveRef.current;\n return b !== null && c !== null ? { bmi: b, category: c } : null;\n },\n reset: () => {\n setHeightCm(null);\n setWeightKg(null);\n setHeightFt(null);\n setHeightIn(null);\n setWeightLb(null);\n },\n }),\n [],\n );\n useAgentRegistration(bmiCalculatorAgent, agentHandle, id);\n\n const isMetric = unitSystem === 'metric';\n\n // Pre-translated gauge labels, shared by the on-screen widget and the\n // inserted card so both surfaces read identically. The shared `BandedGauge`\n // is i18n-agnostic — every visible string arrives already through `t()`.\n const gauge = useMemo(() => {\n if (bmi === null || category === null) return null;\n const { bands, min, max, ticks } = bmiBands();\n const valueLabel = bmiFormatter.format(bmi);\n const categoryLabel = t(`bmiCalculator.category.${category}`);\n const rangeLabel = t(`bmiCalculator.range.${category}`);\n const ariaLabel = t('bmiCalculator.gaugeAria', {\n bmi: valueLabel,\n category: categoryLabel,\n range: rangeLabel,\n });\n return {\n value: bmi,\n bands,\n min,\n max,\n ticks,\n valueLabel,\n categoryLabel,\n rangeLabel,\n ariaLabel,\n };\n }, [bmi, category, bmiFormatter, t]);\n\n return (\n <div\n ref={ref}\n data-component=\"bmi-calculator\"\n data-component-id={id}\n className={rootVariants({ width, className })}\n >\n <RadioGroup\n label={t('bmiCalculator.unitSystem.label')}\n variant=\"horizontal\"\n value={unitSystem}\n onValueChange={handleUnitChange}\n >\n <Radio label={t('bmiCalculator.unitSystem.metric')} value=\"metric\" />\n <Radio\n label={t('bmiCalculator.unitSystem.imperial')}\n value=\"imperial\"\n />\n </RadioGroup>\n\n <div className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:sm:grid-cols-2\">\n {isMetric ? (\n <FormField\n label={`${t('bmiCalculator.height')} (${t('bmiCalculator.units.cm')})`}\n >\n <NumberInput\n mode=\"decimal\"\n min={0}\n step={0.5}\n value={heightCm}\n onChange={setHeightCm}\n />\n </FormField>\n ) : (\n <div role=\"group\" aria-labelledby={heightGroupId}>\n <span\n id={heightGroupId}\n className=\"type-label ds:mb-[var(--spacing-xs)] ds:block ds:text-foreground\"\n >\n {t('bmiCalculator.height')}\n </span>\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n <NumberInput\n mode=\"integer\"\n min={0}\n value={heightFt}\n onChange={setHeightFt}\n aria-label={t('bmiCalculator.feet')}\n />\n <span className=\"type-label ds:text-muted-foreground\">\n {t('bmiCalculator.units.ft')}\n </span>\n <NumberInput\n mode=\"decimal\"\n min={0}\n max={11.9}\n step={0.5}\n value={heightIn}\n onChange={setHeightIn}\n aria-label={t('bmiCalculator.inches')}\n />\n <span className=\"type-label ds:text-muted-foreground\">\n {t('bmiCalculator.units.in')}\n </span>\n </div>\n </div>\n )}\n\n <FormField\n label={`${t('bmiCalculator.weight')} (${t(\n isMetric ? 'bmiCalculator.units.kg' : 'bmiCalculator.units.lb',\n )})`}\n >\n <NumberInput\n mode=\"decimal\"\n min={0}\n step={isMetric ? 0.1 : 0.5}\n value={isMetric ? weightKg : weightLb}\n onChange={isMetric ? setWeightKg : setWeightLb}\n />\n </FormField>\n </div>\n\n {/* Concise polite announcement when the result resolves — the gauge\n itself stays out of the live region to avoid re-reading on every\n keystroke. */}\n <p className=\"ds:sr-only\" role=\"status\" aria-live=\"polite\">\n {gauge ? gauge.ariaLabel : ''}\n </p>\n\n {bmi !== null && category !== null && gauge !== null ? (\n <Card variant=\"elevated\">\n <Card.Body className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-md)]\">\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-xs)] ds:text-center\">\n <span className=\"type-label ds:text-muted-foreground\">\n {t('bmiCalculator.category.label')}\n </span>\n <Badge variant={CATEGORY_BADGE[category]} size=\"lg\">\n {t(`bmiCalculator.category.${category}`)}\n </Badge>\n <p className=\"type-body ds:text-muted-foreground\">\n {gauge.rangeLabel}\n </p>\n </div>\n {/* `data-bmi-category` exposes the WHO band so the gauge's\n semantic colour is assertable without sampling pixels. The\n shared BandedGauge fills each zone via `var(<token>)`, so a\n theme switch repaints the bands with no JS re-sample. */}\n <div\n data-bmi-category={category}\n className=\"ds:w-full ds:max-w-[320px]\"\n >\n <BandedGauge model={gauge} className=\"ds:w-full\" />\n </div>\n {insertVariant === 'copy' || onInsert ? (\n <InsertButton\n onInsert={onInsert}\n variant={insertVariant}\n onCopy={onCopy}\n onError={onError}\n card={{\n title: t('insert.title.bmi'),\n icon: 'scale',\n highlight: t(`bmiCalculator.category.${category}`),\n // Chip shares the WHO-category semantic token so the\n // inserted PNG chip matches the on-screen band colour.\n highlightToken: CATEGORY_TOKEN[category],\n brand: insertBrand,\n // Banded gauge: the SAME geometry + WHO bands as the\n // on-screen widget, baked into the card PNG with\n // probe-resolved theme colours.\n gauge: {\n variant: 'banded',\n value: bmi,\n bands: gauge.bands,\n min: gauge.min,\n max: gauge.max,\n valueLabel: gauge.valueLabel,\n categoryLabel: gauge.categoryLabel,\n rangeLabel: gauge.rangeLabel,\n ariaLabel: gauge.ariaLabel,\n ticks: gauge.ticks,\n },\n fields: [\n {\n // Mirrors the on-screen scale glyph + header icon.\n icon: 'scale',\n label: t('insert.title.bmi'),\n value: gauge.valueLabel,\n },\n {\n // WHO band is a classification → tag glyph.\n icon: 'tag',\n label: t('bmiCalculator.category.label'),\n value: gauge.categoryLabel,\n },\n ],\n }}\n />\n ) : null}\n </Card.Body>\n </Card>\n ) : (\n <p className=\"type-body ds:text-muted-foreground\">\n {t('bmiCalculator.empty')}\n </p>\n )}\n </div>\n );\n },\n);\n\nBmiCalculator.displayName = 'BmiCalculator';\n"],"names":["bmiCalculatorAgent","handle","args","rootVariants","cva","CATEGORY_BADGE","CATEGORY_TOKEN","round1","n","BmiCalculator","forwardRef","defaultUnitSystem","onResultChange","onInsert","insertVariant","onCopy","onError","insertBrand","id","width","className","ref","t","i18n","useTranslation","heightGroupId","useId","unitSystem","setUnitSystem","useState","heightCm","setHeightCm","weightKg","setWeightKg","heightFt","setHeightFt","heightIn","setHeightIn","weightLb","setWeightLb","handleUnitChange","next","target","ft","inches","cmToFtIn","kgToLb","ftInToCm","lbToKg","canonicalHeightCm","canonicalWeightKg","bmi","computeBmi","category","bmiCategory","bmiFormatter","useMemo","useEffect","liveRef","useRef","agentHandle","cm","kg","b","c","useAgentRegistration","isMetric","gauge","bands","min","max","ticks","bmiBands","valueLabel","categoryLabel","rangeLabel","ariaLabel","jsxs","RadioGroup","jsx","Radio","FormField","NumberInput","Card","Badge","BandedGauge","InsertButton"],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import { useTranslation as z } from "react-i18next";
|
|
|
5
5
|
import { u as B } from "./registry-DvAUVLHh.js";
|
|
6
6
|
import { F as S } from "./form-field-D1oqYisL.js";
|
|
7
7
|
import { D as Y } from "./date-picker-Bp64zk2p.js";
|
|
8
|
-
import { N as H } from "./number-input-
|
|
8
|
+
import { N as H } from "./number-input-CM1q9zvH.js";
|
|
9
9
|
import { C as M } from "./card-DPmk26CL.js";
|
|
10
10
|
import { B as T } from "./badge-CIt-UFEx.js";
|
|
11
11
|
import { I as U } from "./insert-result-98J1QEp7.js";
|
|
@@ -422,4 +422,4 @@ export {
|
|
|
422
422
|
ie as L,
|
|
423
423
|
se as p
|
|
424
424
|
};
|
|
425
|
-
//# sourceMappingURL=cycle-calculator-
|
|
425
|
+
//# sourceMappingURL=cycle-calculator-B_NlctlQ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cycle-calculator-D9M7IKfh.js","sources":["../../node_modules/lucide-react/dist/esm/icons/droplet.mjs","../../src/components/cycle-calculator/cycle-calculator.agent.ts","../../src/components/cycle-calculator/cycle.ts","../../src/components/cycle-calculator/cycle-calculator.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M12 22a7 7 0 0 0 7-7c0-2-1-3.9-3-5.5s-3.5-4-4-6.5c-.5 2.5-2 4.9-4 6.5C6 11.1 5 13 5 15a7 7 0 0 0 7 7z\",\n key: \"c7niix\"\n }\n ]\n];\nconst Droplet = createLucideIcon(\"droplet\", __iconNode);\n\nexport { __iconNode, Droplet as default };\n//# sourceMappingURL=droplet.mjs.map\n","/* -------------------------------------------------------------------- */\n/* Agent adapter — CycleCalculator. */\n/* */\n/* Menstrual-cycle predictor: takes a last-period date (+ optional cycle */\n/* and period lengths) and computes ovulation, fertile window and the */\n/* next few periods. The agent surface is the three inputs plus the */\n/* computed prediction; the handle is the curated `CycleCalculatorHandle` */\n/* (the public `ref` stays the root <div>, exactly as `slider.tsx` and */\n/* `bmi-calculator.tsx` keep theirs). */\n/* */\n/* Dates cross the boundary as local-time `yyyy-MM-dd` strings, never */\n/* `Date` objects, so nothing shifts a day under JSON/UTC serialisation. */\n/* */\n/* PHI (§7): never exposes patient identity — the slots return the */\n/* operator's own structural inputs (a date, two day counts) and the */\n/* dates derived from them, the same \"filter model\" precedent §7 sets. */\n/* See `src/docs/26-agent-readiness.mdx`. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { CycleCalculatorHandle } from './cycle-calculator';\n\n/** Shared JSON Schema fragment for a local-time calendar date. */\nconst isoDate = {\n type: 'string',\n pattern: '^\\\\d{4}-\\\\d{2}-\\\\d{2}$',\n} as const;\n\nexport const cycleCalculatorAgent: AgentAdapter<CycleCalculatorHandle> = {\n id: 'cycle-calculator',\n // set_value → the three `set_*` actions + the `inputs` state slot.\n capabilities: ['set_value'],\n state: {\n inputs: {\n type: '{ lastPeriodStart: string | null, cycleLength: number | null, periodLength: number | null }',\n descriptionKey: 'ui.agent.cycleCalculator.state.inputs',\n description:\n 'The three cycle inputs as entered — last-period start date (`yyyy-MM-dd`), average cycle length in days, and period (bleed) length in days. Null where unset.',\n read: (handle) => handle.getInputs(),\n },\n result: {\n type: '{ ovulation: string, fertileWindow: { start: string, end: string }, nextPeriod: string, periodRange: { start: string, end: string } | null, upcomingPeriods: string[] } | null',\n descriptionKey: 'ui.agent.cycleCalculator.state.result',\n description:\n 'Computed prediction — ovulation date, fertile window, next period, current bleed range and the next few period starts, all `yyyy-MM-dd`. Null until a last-period date is set.',\n read: (handle) => handle.getResult(),\n },\n },\n actions: {\n set_last_period: {\n // Drives the same local input state a user types into; nothing is\n // persisted to a record, and the value is reversible in the same UI.\n safety: 'write',\n argsType: '{ date: string | null }',\n argsSchema: {\n type: 'object',\n properties: {\n date: {\n oneOf: [\n { ...isoDate, description: 'Local calendar date, `yyyy-MM-dd`.' },\n { type: 'null' },\n ],\n description:\n 'Start date of the last period, or null to clear it. Must not be in the future.',\n },\n },\n required: ['date'],\n additionalProperties: false,\n },\n idempotent: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the date was applied.',\n },\n errors: [\n 'Returns false for an unparseable date or a date in the future — the on-screen DatePicker caps at today.',\n ],\n examples: [\n { args: { date: '2026-08-01' }, note: 'Last period started 1 August.' },\n ],\n descriptionKey: 'ui.agent.cycleCalculator.actions.setLastPeriod',\n description:\n 'Set the start date of the last period. This is the only required input — the prediction stays null without it.',\n invoke: (handle, args: { date: string | null }) =>\n handle.setLastPeriod(args.date),\n },\n set_cycle_length: {\n safety: 'write',\n argsType: '{ days: number | null }',\n argsSchema: {\n type: 'object',\n properties: {\n days: {\n oneOf: [\n { type: 'integer', minimum: 20, maximum: 45 },\n { type: 'null' },\n ],\n description:\n 'Average cycle length in days (20–45), or null to fall back to the 28-day default.',\n },\n },\n required: ['days'],\n additionalProperties: false,\n },\n idempotent: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the value was applied.',\n },\n errors: [\n 'Returns false outside 20–45 days — the same bounds the on-screen NumberInput enforces.',\n ],\n descriptionKey: 'ui.agent.cycleCalculator.actions.setCycleLength',\n description:\n 'Set the average cycle length in days. Shifts ovulation, the fertile window and every upcoming period.',\n invoke: (handle, args: { days: number | null }) =>\n handle.setCycleLength(args.days),\n },\n set_period_length: {\n safety: 'write',\n argsType: '{ days: number | null }',\n argsSchema: {\n type: 'object',\n properties: {\n days: {\n oneOf: [\n { type: 'integer', minimum: 1, maximum: 14 },\n { type: 'null' },\n ],\n description:\n 'Period (bleed) length in days (1–14), or null to omit the bleed range.',\n },\n },\n required: ['days'],\n additionalProperties: false,\n },\n idempotent: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the value was applied.',\n },\n errors: [\n 'Returns false outside 1–14 days — the same bounds the on-screen NumberInput enforces.',\n ],\n descriptionKey: 'ui.agent.cycleCalculator.actions.setPeriodLength',\n description:\n 'Set the period (bleed) length in days. Optional — it only adds the current bleed range to the result.',\n invoke: (handle, args: { days: number | null }) =>\n handle.setPeriodLength(args.days),\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'cycle-calculator',\n description: 'Marks the CycleCalculator wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the id prop. Also the registry key — without an `id` the instance does not register and only the DOM channel works.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* Menstrual-cycle prediction — pure, framework-free, unit-testable. */\n/* */\n/* Uses the standard fixed-luteal-phase model: ovulation falls ~14 days */\n/* before the next period, so on a cycle of length L ovulation is day */\n/* (L − 14). The fertile window spans the 5 days before ovulation */\n/* (sperm survival) through 1 day after (oocyte viability). */\n/* ------------------------------------------------------------------ */\n\nimport { addDays } from 'date-fns';\n\n/** Standard menstrual-cycle length. */\nexport const DEFAULT_CYCLE_LENGTH = 28;\n/** Luteal phase is biologically near-constant at ~14 days. */\nexport const LUTEAL_PHASE_DAYS = 14;\n/** Sperm survive up to ~5 days before ovulation. */\nexport const FERTILE_DAYS_BEFORE = 5;\n/** The oocyte is viable ~1 day after ovulation. */\nexport const FERTILE_DAYS_AFTER = 1;\n\nexport interface CycleInput {\n /** First day of the most recent period. */\n lastPeriodStart: Date;\n /** Average cycle length in days. Defaults to 28. */\n cycleLength?: number;\n /** Period (bleed) length in days. Optional — used for the period range. */\n periodLength?: number;\n}\n\nexport interface DateRange {\n start: Date;\n end: Date;\n}\n\nexport interface CyclePrediction {\n /** Start date of the next period. */\n nextPeriod: Date;\n /** Estimated ovulation date. */\n ovulation: Date;\n /** Fertile window (5 days before ovulation → 1 day after). */\n fertileWindow: DateRange;\n /** Start dates of the next few periods (length = `occurrences`). */\n upcomingPeriods: Date[];\n /**\n * The current period's bleed range (first day → last day), or `null` when no\n * `periodLength` was given.\n */\n periodRange: DateRange | null;\n}\n\n/**\n * Predict ovulation, the fertile window and upcoming periods from the last\n * period's start date. `occurrences` controls how many future periods to\n * list (default 3).\n */\nexport function predictCycle(\n input: CycleInput,\n occurrences = 3,\n): CyclePrediction {\n const cycle = input.cycleLength ?? DEFAULT_CYCLE_LENGTH;\n const { lastPeriodStart } = input;\n\n const ovulation = addDays(lastPeriodStart, cycle - LUTEAL_PHASE_DAYS);\n const fertileWindow: DateRange = {\n start: addDays(ovulation, -FERTILE_DAYS_BEFORE),\n end: addDays(ovulation, FERTILE_DAYS_AFTER),\n };\n const nextPeriod = addDays(lastPeriodStart, cycle);\n const upcomingPeriods = Array.from({ length: occurrences }, (_, i) =>\n addDays(lastPeriodStart, cycle * (i + 1)),\n );\n const periodRange: DateRange | null =\n input.periodLength && input.periodLength > 0\n ? {\n start: lastPeriodStart,\n end: addDays(lastPeriodStart, input.periodLength - 1),\n }\n : null;\n\n return { nextPeriod, ovulation, fertileWindow, upcomingPeriods, periodRange };\n}\n","/* ------------------------------------------------------------------ */\n/* CycleCalculator — predict ovulation, fertile window and upcoming */\n/* periods from the last period's start date. */\n/* */\n/* Maths lives in `./cycle` (pure, separately tested). */\n/* ------------------------------------------------------------------ */\n\nimport { forwardRef, useEffect, useMemo, useRef, useState } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { format, isAfter, parseISO } from 'date-fns';\nimport { Heart, Check, Droplet } from 'lucide-react';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { cycleCalculatorAgent } from './cycle-calculator.agent';\nimport { FormField } from '../form-field';\nimport { DatePicker } from '../date-picker';\nimport { NumberInput } from '../number-input';\nimport { Card } from '../card';\nimport { Badge } from '../badge';\nimport {\n InsertButton,\n type InsertPayload,\n type InsertVariant,\n type InsertMode,\n} from '../_shared/insert-result';\nimport {\n type CyclePrediction,\n predictCycle,\n DEFAULT_CYCLE_LENGTH,\n} from './cycle';\n\nconst rootVariants = cva('ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]', {\n variants: {\n width: { full: 'ds:w-full', auto: 'ds:inline-flex' },\n },\n defaultVariants: { width: 'full' },\n});\n\n/**\n * DS token NAME backing the result-card chip — the fertile window is the\n * headline fertility datum, shown on screen with the `accent` Badge variant\n * (which fills `--accent`). The card chip reuses that token so the inserted\n * PNG chip matches the on-screen fertile-window badge.\n */\nconst HIGHLIGHT_TOKEN = '--accent';\n\n/* ------------------------------------------------------------------ */\n/* Agent boundary */\n/* */\n/* Dates cross the agent boundary as local-time `yyyy-MM-dd` strings, */\n/* never `Date` objects — a Date JSON-serialises to UTC and silently */\n/* shifts the day for anyone east or west of Greenwich. */\n/* ------------------------------------------------------------------ */\n\nconst toIsoDate = (d: Date): string => format(d, 'yyyy-MM-dd');\n\nconst fromIsoDate = (iso: string): Date | null => {\n const d = parseISO(iso);\n return Number.isNaN(d.getTime()) ? null : d;\n};\n\n/** UI input bounds, mirrored by the agent handle so it can't out-type a user. */\nconst CYCLE_LENGTH_RANGE = { min: 20, max: 45 } as const;\nconst PERIOD_LENGTH_RANGE = { min: 1, max: 14 } as const;\n\nconst inRange = (\n n: number | null,\n { min, max }: { min: number; max: number },\n): boolean => n === null || (Number.isFinite(n) && n >= min && n <= max);\n\n/** `CyclePrediction` projected onto the agent boundary — ISO dates, no Dates. */\nexport interface CyclePredictionSnapshot {\n /** Estimated ovulation date, `yyyy-MM-dd`. */\n ovulation: string;\n /** Fertile window, `yyyy-MM-dd` endpoints. */\n fertileWindow: { start: string; end: string };\n /** Start of the next period, `yyyy-MM-dd`. */\n nextPeriod: string;\n /** Current period's bleed range, or null when no period length was given. */\n periodRange: { start: string; end: string } | null;\n /** Start dates of the next few periods, `yyyy-MM-dd`. */\n upcomingPeriods: string[];\n}\n\n/**\n * Curated imperative handle for agent / external automation. Reads the three\n * cycle inputs and the computed prediction, and drives the inputs the way a\n * user would. Never exposes patient identity — only structural dates and day\n * counts. Consumed by `cycle-calculator.agent.ts`; the public `ref` stays the\n * root DOM element.\n */\nexport interface CycleCalculatorHandle {\n /** Current inputs — ISO date + day counts, or null when unset. */\n getInputs: () => {\n lastPeriodStart: string | null;\n cycleLength: number | null;\n periodLength: number | null;\n };\n /** Computed prediction, or null until a last-period date is set. */\n getResult: () => CyclePredictionSnapshot | null;\n /** Set the last period's start date (`yyyy-MM-dd`, not in the future). */\n setLastPeriod: (isoDate: string | null) => boolean;\n /** Set the average cycle length in days (20–45). */\n setCycleLength: (days: number | null) => boolean;\n /** Set the period (bleed) length in days (1–14). */\n setPeriodLength: (days: number | null) => boolean;\n}\n\nexport interface CycleCalculatorProps extends VariantProps<\n typeof rootVariants\n> {\n /** Initial cycle length in days. Defaults to 28. */\n defaultCycleLength?: number;\n /** Fires whenever a prediction can be computed (and `null` when it can't). */\n onResultChange?: (result: CyclePrediction | null) => void;\n /** When provided, shows the result-action buttons that emit / copy the result. */\n onInsert?: (payload: InsertPayload) => void;\n /**\n * Which verb the result button performs. Defaults to `'insert'`.\n * Use `'copy'` in an app-shell surface (no editor to insert into) — the\n * button writes the result to the clipboard as a multi-format `ClipboardItem`.\n */\n insertVariant?: InsertVariant;\n /** `copy` variant only — fired after a successful clipboard write. */\n onCopy?: (mode: InsertMode) => void;\n /** `copy` variant only — fired if the clipboard write can't proceed. */\n onError?: (error: unknown) => void;\n /**\n * Brand wordmark printed in the inserted/copied result-card footer.\n * Omitted → no brand line (and no footer hairline); a string → that custom\n * brand; `false` → no brand line. Brand is opt-in.\n */\n insertBrand?: string | false;\n /** Opaque instance id, emitted as `data-component-id`. */\n id?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n}\n\nexport const CycleCalculator = forwardRef<HTMLDivElement, CycleCalculatorProps>(\n (\n {\n defaultCycleLength = DEFAULT_CYCLE_LENGTH,\n onResultChange,\n onInsert,\n insertVariant = 'insert',\n onCopy,\n onError,\n insertBrand,\n id,\n width,\n className,\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation();\n\n const [lastPeriod, setLastPeriod] = useState<Date | undefined>(undefined);\n const [cycleLength, setCycleLength] = useState<number | null>(\n defaultCycleLength,\n );\n const [periodLength, setPeriodLength] = useState<number | null>(null);\n\n const result = useMemo<CyclePrediction | null>(() => {\n if (!lastPeriod) return null;\n return predictCycle({\n lastPeriodStart: lastPeriod,\n cycleLength: cycleLength ?? DEFAULT_CYCLE_LENGTH,\n periodLength: periodLength ?? undefined,\n });\n }, [lastPeriod, cycleLength, periodLength]);\n\n const dateFormatter = useMemo(\n () => new Intl.DateTimeFormat(i18n.language, { dateStyle: 'medium' }),\n [i18n.language],\n );\n\n useEffect(() => {\n onResultChange?.(result);\n }, [result, onResultChange]);\n\n const today = useMemo(() => new Date(), []);\n\n /* ── Agent handle ────────────────────────────────────────────────── */\n const liveRef = useRef({ lastPeriod, cycleLength, periodLength, result });\n liveRef.current = { lastPeriod, cycleLength, periodLength, result };\n\n const agentHandle = useMemo<CycleCalculatorHandle>(\n () => ({\n getInputs: () => ({\n lastPeriodStart: liveRef.current.lastPeriod\n ? toIsoDate(liveRef.current.lastPeriod)\n : null,\n cycleLength: liveRef.current.cycleLength,\n periodLength: liveRef.current.periodLength,\n }),\n getResult: () => {\n const r = liveRef.current.result;\n if (!r) return null;\n return {\n ovulation: toIsoDate(r.ovulation),\n fertileWindow: {\n start: toIsoDate(r.fertileWindow.start),\n end: toIsoDate(r.fertileWindow.end),\n },\n nextPeriod: toIsoDate(r.nextPeriod),\n periodRange: r.periodRange\n ? {\n start: toIsoDate(r.periodRange.start),\n end: toIsoDate(r.periodRange.end),\n }\n : null,\n upcomingPeriods: r.upcomingPeriods.map(toIsoDate),\n };\n },\n setLastPeriod: (isoDate) => {\n if (isoDate === null) {\n setLastPeriod(undefined);\n return true;\n }\n const parsed = fromIsoDate(isoDate);\n // The DatePicker caps at today; the handle honours the same bound.\n if (!parsed || isAfter(parsed, new Date())) return false;\n setLastPeriod(parsed);\n return true;\n },\n setCycleLength: (days) => {\n if (!inRange(days, CYCLE_LENGTH_RANGE)) return false;\n setCycleLength(days);\n return true;\n },\n setPeriodLength: (days) => {\n if (!inRange(days, PERIOD_LENGTH_RANGE)) return false;\n setPeriodLength(days);\n return true;\n },\n }),\n [],\n );\n useAgentRegistration(cycleCalculatorAgent, agentHandle, id);\n\n const fmt = (d: Date): string => dateFormatter.format(d);\n\n return (\n <div\n ref={ref}\n data-component=\"cycle-calculator\"\n data-component-id={id}\n className={rootVariants({ width, className })}\n >\n <div className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:sm:grid-cols-2\">\n <FormField label={t('cycleCalculator.lastPeriod')}>\n <DatePicker\n value={lastPeriod}\n onChange={setLastPeriod}\n maxDate={today}\n />\n </FormField>\n <FormField\n label={t('cycleCalculator.cycleLength')}\n description={t('cycleCalculator.cycleLengthHint')}\n >\n <NumberInput\n mode=\"integer\"\n min={CYCLE_LENGTH_RANGE.min}\n max={CYCLE_LENGTH_RANGE.max}\n value={cycleLength}\n onChange={setCycleLength}\n />\n </FormField>\n <FormField\n label={t('cycleCalculator.periodLength')}\n description={t('cycleCalculator.periodLengthHint')}\n >\n <NumberInput\n mode=\"integer\"\n min={PERIOD_LENGTH_RANGE.min}\n max={PERIOD_LENGTH_RANGE.max}\n value={periodLength}\n onChange={setPeriodLength}\n />\n </FormField>\n </div>\n\n <p className=\"ds:sr-only\" role=\"status\" aria-live=\"polite\">\n {result\n ? `${t('cycleCalculator.ovulation')}: ${fmt(result.ovulation)}. ${t(\n 'cycleCalculator.nextPeriod',\n )}: ${fmt(result.nextPeriod)}.`\n : ''}\n </p>\n\n {result ? (\n <Card variant=\"elevated\">\n <Card.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <dl className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:sm:grid-cols-3\">\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-xs)] ds:text-center\">\n <dt className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.ovulation')}\n </dt>\n <dd>\n <Badge\n variant=\"success\"\n size=\"lg\"\n leading={<Check aria-hidden />}\n >\n {fmt(result.ovulation)}\n </Badge>\n </dd>\n </div>\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-xs)] ds:text-center\">\n <dt className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.fertileWindow')}\n </dt>\n <dd>\n <Badge\n variant=\"accent\"\n size=\"lg\"\n leading={<Heart aria-hidden />}\n >\n {fmt(result.fertileWindow.start)} –{' '}\n {fmt(result.fertileWindow.end)}\n </Badge>\n </dd>\n </div>\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-xs)] ds:text-center\">\n <dt className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.nextPeriod')}\n </dt>\n <dd>\n <Badge\n variant=\"error\"\n size=\"lg\"\n leading={<Droplet aria-hidden />}\n >\n {fmt(result.nextPeriod)}\n </Badge>\n </dd>\n </div>\n </dl>\n\n {result.periodRange ? (\n <div className=\"ds:flex ds:flex-col ds:items-start ds:gap-[var(--spacing-2xs)]\">\n <span className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.periodRange')}\n </span>\n <span className=\"type-body ds:text-foreground\">\n {fmt(result.periodRange.start)} –{' '}\n {fmt(result.periodRange.end)}\n </span>\n </div>\n ) : null}\n\n <div className=\"ds:flex ds:flex-col ds:items-start ds:gap-[var(--spacing-2xs)]\">\n <span className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.upcomingPeriods')}\n </span>\n <ul className=\"ds:flex ds:flex-wrap ds:gap-x-[var(--spacing-md)] ds:gap-y-[var(--spacing-2xs)]\">\n {result.upcomingPeriods.map((d) => (\n <li\n key={d.getTime()}\n className=\"type-body ds:text-foreground\"\n >\n {fmt(d)}\n </li>\n ))}\n </ul>\n </div>\n\n {insertVariant === 'copy' || onInsert ? (\n <InsertButton\n onInsert={onInsert}\n variant={insertVariant}\n onCopy={onCopy}\n onError={onError}\n card={{\n title: t('insert.title.cycle'),\n icon: 'heart',\n highlight: `${fmt(result.fertileWindow.start)} – ${fmt(\n result.fertileWindow.end,\n )}`,\n // Chip reuses the on-screen fertile-window badge's accent\n // token so the inserted PNG chip matches the screen.\n highlightToken: HIGHLIGHT_TOKEN,\n brand: insertBrand,\n fields: [\n {\n // Ovulation is a predicted date → calendar glyph (the\n // on-screen badge uses a Check tick, which ICON_GEOMETRY\n // does not carry, so the calendar reads the date meaning).\n icon: 'calendar',\n label: t('cycleCalculator.ovulation'),\n value: fmt(result.ovulation),\n },\n {\n // Fertile window → heart glyph, matching the on-screen\n // fertile-window badge's Heart icon.\n icon: 'heart',\n label: t('cycleCalculator.fertileWindow'),\n value: `${fmt(result.fertileWindow.start)} – ${fmt(\n result.fertileWindow.end,\n )}`,\n },\n {\n // Next period → droplets glyph, matching the on-screen\n // next-period badge's Droplet icon.\n icon: 'droplets',\n label: t('cycleCalculator.nextPeriod'),\n value: fmt(result.nextPeriod),\n },\n ],\n }}\n />\n ) : null}\n </Card.Body>\n </Card>\n ) : (\n <p className=\"type-body ds:text-muted-foreground\">\n {t('cycleCalculator.empty')}\n </p>\n )}\n </div>\n );\n },\n);\n\nCycleCalculator.displayName = 'CycleCalculator';\n"],"names":["__iconNode","Droplet","createLucideIcon","isoDate","cycleCalculatorAgent","handle","args","DEFAULT_CYCLE_LENGTH","LUTEAL_PHASE_DAYS","FERTILE_DAYS_AFTER","predictCycle","input","occurrences","cycle","lastPeriodStart","ovulation","addDays","fertileWindow","nextPeriod","upcomingPeriods","_","i","periodRange","rootVariants","cva","HIGHLIGHT_TOKEN","toIsoDate","d","format","fromIsoDate","iso","parseISO","CYCLE_LENGTH_RANGE","PERIOD_LENGTH_RANGE","inRange","n","min","max","CycleCalculator","forwardRef","defaultCycleLength","onResultChange","onInsert","insertVariant","onCopy","onError","insertBrand","id","width","className","ref","t","i18n","useTranslation","lastPeriod","setLastPeriod","useState","cycleLength","setCycleLength","periodLength","setPeriodLength","result","useMemo","dateFormatter","useEffect","today","liveRef","useRef","agentHandle","parsed","isAfter","days","useAgentRegistration","fmt","jsxs","jsx","FormField","DatePicker","NumberInput","Card","Badge","Check","Heart","InsertButton"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"cycle-calculator-B_NlctlQ.js","sources":["../../node_modules/lucide-react/dist/esm/icons/droplet.mjs","../../src/components/cycle-calculator/cycle-calculator.agent.ts","../../src/components/cycle-calculator/cycle.ts","../../src/components/cycle-calculator/cycle-calculator.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M12 22a7 7 0 0 0 7-7c0-2-1-3.9-3-5.5s-3.5-4-4-6.5c-.5 2.5-2 4.9-4 6.5C6 11.1 5 13 5 15a7 7 0 0 0 7 7z\",\n key: \"c7niix\"\n }\n ]\n];\nconst Droplet = createLucideIcon(\"droplet\", __iconNode);\n\nexport { __iconNode, Droplet as default };\n//# sourceMappingURL=droplet.mjs.map\n","/* -------------------------------------------------------------------- */\n/* Agent adapter — CycleCalculator. */\n/* */\n/* Menstrual-cycle predictor: takes a last-period date (+ optional cycle */\n/* and period lengths) and computes ovulation, fertile window and the */\n/* next few periods. The agent surface is the three inputs plus the */\n/* computed prediction; the handle is the curated `CycleCalculatorHandle` */\n/* (the public `ref` stays the root <div>, exactly as `slider.tsx` and */\n/* `bmi-calculator.tsx` keep theirs). */\n/* */\n/* Dates cross the boundary as local-time `yyyy-MM-dd` strings, never */\n/* `Date` objects, so nothing shifts a day under JSON/UTC serialisation. */\n/* */\n/* PHI (§7): never exposes patient identity — the slots return the */\n/* operator's own structural inputs (a date, two day counts) and the */\n/* dates derived from them, the same \"filter model\" precedent §7 sets. */\n/* See `src/docs/26-agent-readiness.mdx`. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { CycleCalculatorHandle } from './cycle-calculator';\n\n/** Shared JSON Schema fragment for a local-time calendar date. */\nconst isoDate = {\n type: 'string',\n pattern: '^\\\\d{4}-\\\\d{2}-\\\\d{2}$',\n} as const;\n\nexport const cycleCalculatorAgent: AgentAdapter<CycleCalculatorHandle> = {\n id: 'cycle-calculator',\n // set_value → the three `set_*` actions + the `inputs` state slot.\n capabilities: ['set_value'],\n state: {\n inputs: {\n type: '{ lastPeriodStart: string | null, cycleLength: number | null, periodLength: number | null }',\n descriptionKey: 'ui.agent.cycleCalculator.state.inputs',\n description:\n 'The three cycle inputs as entered — last-period start date (`yyyy-MM-dd`), average cycle length in days, and period (bleed) length in days. Null where unset.',\n read: (handle) => handle.getInputs(),\n },\n result: {\n type: '{ ovulation: string, fertileWindow: { start: string, end: string }, nextPeriod: string, periodRange: { start: string, end: string } | null, upcomingPeriods: string[] } | null',\n descriptionKey: 'ui.agent.cycleCalculator.state.result',\n description:\n 'Computed prediction — ovulation date, fertile window, next period, current bleed range and the next few period starts, all `yyyy-MM-dd`. Null until a last-period date is set.',\n read: (handle) => handle.getResult(),\n },\n },\n actions: {\n set_last_period: {\n // Drives the same local input state a user types into; nothing is\n // persisted to a record, and the value is reversible in the same UI.\n safety: 'write',\n argsType: '{ date: string | null }',\n argsSchema: {\n type: 'object',\n properties: {\n date: {\n oneOf: [\n { ...isoDate, description: 'Local calendar date, `yyyy-MM-dd`.' },\n { type: 'null' },\n ],\n description:\n 'Start date of the last period, or null to clear it. Must not be in the future.',\n },\n },\n required: ['date'],\n additionalProperties: false,\n },\n idempotent: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the date was applied.',\n },\n errors: [\n 'Returns false for an unparseable date or a date in the future — the on-screen DatePicker caps at today.',\n ],\n examples: [\n { args: { date: '2026-08-01' }, note: 'Last period started 1 August.' },\n ],\n descriptionKey: 'ui.agent.cycleCalculator.actions.setLastPeriod',\n description:\n 'Set the start date of the last period. This is the only required input — the prediction stays null without it.',\n invoke: (handle, args: { date: string | null }) =>\n handle.setLastPeriod(args.date),\n },\n set_cycle_length: {\n safety: 'write',\n argsType: '{ days: number | null }',\n argsSchema: {\n type: 'object',\n properties: {\n days: {\n oneOf: [\n { type: 'integer', minimum: 20, maximum: 45 },\n { type: 'null' },\n ],\n description:\n 'Average cycle length in days (20–45), or null to fall back to the 28-day default.',\n },\n },\n required: ['days'],\n additionalProperties: false,\n },\n idempotent: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the value was applied.',\n },\n errors: [\n 'Returns false outside 20–45 days — the same bounds the on-screen NumberInput enforces.',\n ],\n descriptionKey: 'ui.agent.cycleCalculator.actions.setCycleLength',\n description:\n 'Set the average cycle length in days. Shifts ovulation, the fertile window and every upcoming period.',\n invoke: (handle, args: { days: number | null }) =>\n handle.setCycleLength(args.days),\n },\n set_period_length: {\n safety: 'write',\n argsType: '{ days: number | null }',\n argsSchema: {\n type: 'object',\n properties: {\n days: {\n oneOf: [\n { type: 'integer', minimum: 1, maximum: 14 },\n { type: 'null' },\n ],\n description:\n 'Period (bleed) length in days (1–14), or null to omit the bleed range.',\n },\n },\n required: ['days'],\n additionalProperties: false,\n },\n idempotent: true,\n returns: 'boolean',\n returnsSchema: {\n type: 'boolean',\n description: 'True when the value was applied.',\n },\n errors: [\n 'Returns false outside 1–14 days — the same bounds the on-screen NumberInput enforces.',\n ],\n descriptionKey: 'ui.agent.cycleCalculator.actions.setPeriodLength',\n description:\n 'Set the period (bleed) length in days. Optional — it only adds the current bleed range to the result.',\n invoke: (handle, args: { days: number | null }) =>\n handle.setPeriodLength(args.days),\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'cycle-calculator',\n description: 'Marks the CycleCalculator wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the id prop. Also the registry key — without an `id` the instance does not register and only the DOM channel works.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* Menstrual-cycle prediction — pure, framework-free, unit-testable. */\n/* */\n/* Uses the standard fixed-luteal-phase model: ovulation falls ~14 days */\n/* before the next period, so on a cycle of length L ovulation is day */\n/* (L − 14). The fertile window spans the 5 days before ovulation */\n/* (sperm survival) through 1 day after (oocyte viability). */\n/* ------------------------------------------------------------------ */\n\nimport { addDays } from 'date-fns';\n\n/** Standard menstrual-cycle length. */\nexport const DEFAULT_CYCLE_LENGTH = 28;\n/** Luteal phase is biologically near-constant at ~14 days. */\nexport const LUTEAL_PHASE_DAYS = 14;\n/** Sperm survive up to ~5 days before ovulation. */\nexport const FERTILE_DAYS_BEFORE = 5;\n/** The oocyte is viable ~1 day after ovulation. */\nexport const FERTILE_DAYS_AFTER = 1;\n\nexport interface CycleInput {\n /** First day of the most recent period. */\n lastPeriodStart: Date;\n /** Average cycle length in days. Defaults to 28. */\n cycleLength?: number;\n /** Period (bleed) length in days. Optional — used for the period range. */\n periodLength?: number;\n}\n\nexport interface DateRange {\n start: Date;\n end: Date;\n}\n\nexport interface CyclePrediction {\n /** Start date of the next period. */\n nextPeriod: Date;\n /** Estimated ovulation date. */\n ovulation: Date;\n /** Fertile window (5 days before ovulation → 1 day after). */\n fertileWindow: DateRange;\n /** Start dates of the next few periods (length = `occurrences`). */\n upcomingPeriods: Date[];\n /**\n * The current period's bleed range (first day → last day), or `null` when no\n * `periodLength` was given.\n */\n periodRange: DateRange | null;\n}\n\n/**\n * Predict ovulation, the fertile window and upcoming periods from the last\n * period's start date. `occurrences` controls how many future periods to\n * list (default 3).\n */\nexport function predictCycle(\n input: CycleInput,\n occurrences = 3,\n): CyclePrediction {\n const cycle = input.cycleLength ?? DEFAULT_CYCLE_LENGTH;\n const { lastPeriodStart } = input;\n\n const ovulation = addDays(lastPeriodStart, cycle - LUTEAL_PHASE_DAYS);\n const fertileWindow: DateRange = {\n start: addDays(ovulation, -FERTILE_DAYS_BEFORE),\n end: addDays(ovulation, FERTILE_DAYS_AFTER),\n };\n const nextPeriod = addDays(lastPeriodStart, cycle);\n const upcomingPeriods = Array.from({ length: occurrences }, (_, i) =>\n addDays(lastPeriodStart, cycle * (i + 1)),\n );\n const periodRange: DateRange | null =\n input.periodLength && input.periodLength > 0\n ? {\n start: lastPeriodStart,\n end: addDays(lastPeriodStart, input.periodLength - 1),\n }\n : null;\n\n return { nextPeriod, ovulation, fertileWindow, upcomingPeriods, periodRange };\n}\n","/* ------------------------------------------------------------------ */\n/* CycleCalculator — predict ovulation, fertile window and upcoming */\n/* periods from the last period's start date. */\n/* */\n/* Maths lives in `./cycle` (pure, separately tested). */\n/* ------------------------------------------------------------------ */\n\nimport { forwardRef, useEffect, useMemo, useRef, useState } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { format, isAfter, parseISO } from 'date-fns';\nimport { Heart, Check, Droplet } from 'lucide-react';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { cycleCalculatorAgent } from './cycle-calculator.agent';\nimport { FormField } from '../form-field';\nimport { DatePicker } from '../date-picker';\nimport { NumberInput } from '../number-input';\nimport { Card } from '../card';\nimport { Badge } from '../badge';\nimport {\n InsertButton,\n type InsertPayload,\n type InsertVariant,\n type InsertMode,\n} from '../_shared/insert-result';\nimport {\n type CyclePrediction,\n predictCycle,\n DEFAULT_CYCLE_LENGTH,\n} from './cycle';\n\nconst rootVariants = cva('ds:flex ds:flex-col ds:gap-[var(--spacing-lg)]', {\n variants: {\n width: { full: 'ds:w-full', auto: 'ds:inline-flex' },\n },\n defaultVariants: { width: 'full' },\n});\n\n/**\n * DS token NAME backing the result-card chip — the fertile window is the\n * headline fertility datum, shown on screen with the `accent` Badge variant\n * (which fills `--accent`). The card chip reuses that token so the inserted\n * PNG chip matches the on-screen fertile-window badge.\n */\nconst HIGHLIGHT_TOKEN = '--accent';\n\n/* ------------------------------------------------------------------ */\n/* Agent boundary */\n/* */\n/* Dates cross the agent boundary as local-time `yyyy-MM-dd` strings, */\n/* never `Date` objects — a Date JSON-serialises to UTC and silently */\n/* shifts the day for anyone east or west of Greenwich. */\n/* ------------------------------------------------------------------ */\n\nconst toIsoDate = (d: Date): string => format(d, 'yyyy-MM-dd');\n\nconst fromIsoDate = (iso: string): Date | null => {\n const d = parseISO(iso);\n return Number.isNaN(d.getTime()) ? null : d;\n};\n\n/** UI input bounds, mirrored by the agent handle so it can't out-type a user. */\nconst CYCLE_LENGTH_RANGE = { min: 20, max: 45 } as const;\nconst PERIOD_LENGTH_RANGE = { min: 1, max: 14 } as const;\n\nconst inRange = (\n n: number | null,\n { min, max }: { min: number; max: number },\n): boolean => n === null || (Number.isFinite(n) && n >= min && n <= max);\n\n/** `CyclePrediction` projected onto the agent boundary — ISO dates, no Dates. */\nexport interface CyclePredictionSnapshot {\n /** Estimated ovulation date, `yyyy-MM-dd`. */\n ovulation: string;\n /** Fertile window, `yyyy-MM-dd` endpoints. */\n fertileWindow: { start: string; end: string };\n /** Start of the next period, `yyyy-MM-dd`. */\n nextPeriod: string;\n /** Current period's bleed range, or null when no period length was given. */\n periodRange: { start: string; end: string } | null;\n /** Start dates of the next few periods, `yyyy-MM-dd`. */\n upcomingPeriods: string[];\n}\n\n/**\n * Curated imperative handle for agent / external automation. Reads the three\n * cycle inputs and the computed prediction, and drives the inputs the way a\n * user would. Never exposes patient identity — only structural dates and day\n * counts. Consumed by `cycle-calculator.agent.ts`; the public `ref` stays the\n * root DOM element.\n */\nexport interface CycleCalculatorHandle {\n /** Current inputs — ISO date + day counts, or null when unset. */\n getInputs: () => {\n lastPeriodStart: string | null;\n cycleLength: number | null;\n periodLength: number | null;\n };\n /** Computed prediction, or null until a last-period date is set. */\n getResult: () => CyclePredictionSnapshot | null;\n /** Set the last period's start date (`yyyy-MM-dd`, not in the future). */\n setLastPeriod: (isoDate: string | null) => boolean;\n /** Set the average cycle length in days (20–45). */\n setCycleLength: (days: number | null) => boolean;\n /** Set the period (bleed) length in days (1–14). */\n setPeriodLength: (days: number | null) => boolean;\n}\n\nexport interface CycleCalculatorProps extends VariantProps<\n typeof rootVariants\n> {\n /** Initial cycle length in days. Defaults to 28. */\n defaultCycleLength?: number;\n /** Fires whenever a prediction can be computed (and `null` when it can't). */\n onResultChange?: (result: CyclePrediction | null) => void;\n /** When provided, shows the result-action buttons that emit / copy the result. */\n onInsert?: (payload: InsertPayload) => void;\n /**\n * Which verb the result button performs. Defaults to `'insert'`.\n * Use `'copy'` in an app-shell surface (no editor to insert into) — the\n * button writes the result to the clipboard as a multi-format `ClipboardItem`.\n */\n insertVariant?: InsertVariant;\n /** `copy` variant only — fired after a successful clipboard write. */\n onCopy?: (mode: InsertMode) => void;\n /** `copy` variant only — fired if the clipboard write can't proceed. */\n onError?: (error: unknown) => void;\n /**\n * Brand wordmark printed in the inserted/copied result-card footer.\n * Omitted → no brand line (and no footer hairline); a string → that custom\n * brand; `false` → no brand line. Brand is opt-in.\n */\n insertBrand?: string | false;\n /** Opaque instance id, emitted as `data-component-id`. */\n id?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n}\n\nexport const CycleCalculator = forwardRef<HTMLDivElement, CycleCalculatorProps>(\n (\n {\n defaultCycleLength = DEFAULT_CYCLE_LENGTH,\n onResultChange,\n onInsert,\n insertVariant = 'insert',\n onCopy,\n onError,\n insertBrand,\n id,\n width,\n className,\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation();\n\n const [lastPeriod, setLastPeriod] = useState<Date | undefined>(undefined);\n const [cycleLength, setCycleLength] = useState<number | null>(\n defaultCycleLength,\n );\n const [periodLength, setPeriodLength] = useState<number | null>(null);\n\n const result = useMemo<CyclePrediction | null>(() => {\n if (!lastPeriod) return null;\n return predictCycle({\n lastPeriodStart: lastPeriod,\n cycleLength: cycleLength ?? DEFAULT_CYCLE_LENGTH,\n periodLength: periodLength ?? undefined,\n });\n }, [lastPeriod, cycleLength, periodLength]);\n\n const dateFormatter = useMemo(\n () => new Intl.DateTimeFormat(i18n.language, { dateStyle: 'medium' }),\n [i18n.language],\n );\n\n useEffect(() => {\n onResultChange?.(result);\n }, [result, onResultChange]);\n\n const today = useMemo(() => new Date(), []);\n\n /* ── Agent handle ────────────────────────────────────────────────── */\n const liveRef = useRef({ lastPeriod, cycleLength, periodLength, result });\n liveRef.current = { lastPeriod, cycleLength, periodLength, result };\n\n const agentHandle = useMemo<CycleCalculatorHandle>(\n () => ({\n getInputs: () => ({\n lastPeriodStart: liveRef.current.lastPeriod\n ? toIsoDate(liveRef.current.lastPeriod)\n : null,\n cycleLength: liveRef.current.cycleLength,\n periodLength: liveRef.current.periodLength,\n }),\n getResult: () => {\n const r = liveRef.current.result;\n if (!r) return null;\n return {\n ovulation: toIsoDate(r.ovulation),\n fertileWindow: {\n start: toIsoDate(r.fertileWindow.start),\n end: toIsoDate(r.fertileWindow.end),\n },\n nextPeriod: toIsoDate(r.nextPeriod),\n periodRange: r.periodRange\n ? {\n start: toIsoDate(r.periodRange.start),\n end: toIsoDate(r.periodRange.end),\n }\n : null,\n upcomingPeriods: r.upcomingPeriods.map(toIsoDate),\n };\n },\n setLastPeriod: (isoDate) => {\n if (isoDate === null) {\n setLastPeriod(undefined);\n return true;\n }\n const parsed = fromIsoDate(isoDate);\n // The DatePicker caps at today; the handle honours the same bound.\n if (!parsed || isAfter(parsed, new Date())) return false;\n setLastPeriod(parsed);\n return true;\n },\n setCycleLength: (days) => {\n if (!inRange(days, CYCLE_LENGTH_RANGE)) return false;\n setCycleLength(days);\n return true;\n },\n setPeriodLength: (days) => {\n if (!inRange(days, PERIOD_LENGTH_RANGE)) return false;\n setPeriodLength(days);\n return true;\n },\n }),\n [],\n );\n useAgentRegistration(cycleCalculatorAgent, agentHandle, id);\n\n const fmt = (d: Date): string => dateFormatter.format(d);\n\n return (\n <div\n ref={ref}\n data-component=\"cycle-calculator\"\n data-component-id={id}\n className={rootVariants({ width, className })}\n >\n <div className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:sm:grid-cols-2\">\n <FormField label={t('cycleCalculator.lastPeriod')}>\n <DatePicker\n value={lastPeriod}\n onChange={setLastPeriod}\n maxDate={today}\n />\n </FormField>\n <FormField\n label={t('cycleCalculator.cycleLength')}\n description={t('cycleCalculator.cycleLengthHint')}\n >\n <NumberInput\n mode=\"integer\"\n min={CYCLE_LENGTH_RANGE.min}\n max={CYCLE_LENGTH_RANGE.max}\n value={cycleLength}\n onChange={setCycleLength}\n />\n </FormField>\n <FormField\n label={t('cycleCalculator.periodLength')}\n description={t('cycleCalculator.periodLengthHint')}\n >\n <NumberInput\n mode=\"integer\"\n min={PERIOD_LENGTH_RANGE.min}\n max={PERIOD_LENGTH_RANGE.max}\n value={periodLength}\n onChange={setPeriodLength}\n />\n </FormField>\n </div>\n\n <p className=\"ds:sr-only\" role=\"status\" aria-live=\"polite\">\n {result\n ? `${t('cycleCalculator.ovulation')}: ${fmt(result.ovulation)}. ${t(\n 'cycleCalculator.nextPeriod',\n )}: ${fmt(result.nextPeriod)}.`\n : ''}\n </p>\n\n {result ? (\n <Card variant=\"elevated\">\n <Card.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <dl className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:sm:grid-cols-3\">\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-xs)] ds:text-center\">\n <dt className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.ovulation')}\n </dt>\n <dd>\n <Badge\n variant=\"success\"\n size=\"lg\"\n leading={<Check aria-hidden />}\n >\n {fmt(result.ovulation)}\n </Badge>\n </dd>\n </div>\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-xs)] ds:text-center\">\n <dt className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.fertileWindow')}\n </dt>\n <dd>\n <Badge\n variant=\"accent\"\n size=\"lg\"\n leading={<Heart aria-hidden />}\n >\n {fmt(result.fertileWindow.start)} –{' '}\n {fmt(result.fertileWindow.end)}\n </Badge>\n </dd>\n </div>\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-xs)] ds:text-center\">\n <dt className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.nextPeriod')}\n </dt>\n <dd>\n <Badge\n variant=\"error\"\n size=\"lg\"\n leading={<Droplet aria-hidden />}\n >\n {fmt(result.nextPeriod)}\n </Badge>\n </dd>\n </div>\n </dl>\n\n {result.periodRange ? (\n <div className=\"ds:flex ds:flex-col ds:items-start ds:gap-[var(--spacing-2xs)]\">\n <span className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.periodRange')}\n </span>\n <span className=\"type-body ds:text-foreground\">\n {fmt(result.periodRange.start)} –{' '}\n {fmt(result.periodRange.end)}\n </span>\n </div>\n ) : null}\n\n <div className=\"ds:flex ds:flex-col ds:items-start ds:gap-[var(--spacing-2xs)]\">\n <span className=\"type-label ds:text-muted-foreground\">\n {t('cycleCalculator.upcomingPeriods')}\n </span>\n <ul className=\"ds:flex ds:flex-wrap ds:gap-x-[var(--spacing-md)] ds:gap-y-[var(--spacing-2xs)]\">\n {result.upcomingPeriods.map((d) => (\n <li\n key={d.getTime()}\n className=\"type-body ds:text-foreground\"\n >\n {fmt(d)}\n </li>\n ))}\n </ul>\n </div>\n\n {insertVariant === 'copy' || onInsert ? (\n <InsertButton\n onInsert={onInsert}\n variant={insertVariant}\n onCopy={onCopy}\n onError={onError}\n card={{\n title: t('insert.title.cycle'),\n icon: 'heart',\n highlight: `${fmt(result.fertileWindow.start)} – ${fmt(\n result.fertileWindow.end,\n )}`,\n // Chip reuses the on-screen fertile-window badge's accent\n // token so the inserted PNG chip matches the screen.\n highlightToken: HIGHLIGHT_TOKEN,\n brand: insertBrand,\n fields: [\n {\n // Ovulation is a predicted date → calendar glyph (the\n // on-screen badge uses a Check tick, which ICON_GEOMETRY\n // does not carry, so the calendar reads the date meaning).\n icon: 'calendar',\n label: t('cycleCalculator.ovulation'),\n value: fmt(result.ovulation),\n },\n {\n // Fertile window → heart glyph, matching the on-screen\n // fertile-window badge's Heart icon.\n icon: 'heart',\n label: t('cycleCalculator.fertileWindow'),\n value: `${fmt(result.fertileWindow.start)} – ${fmt(\n result.fertileWindow.end,\n )}`,\n },\n {\n // Next period → droplets glyph, matching the on-screen\n // next-period badge's Droplet icon.\n icon: 'droplets',\n label: t('cycleCalculator.nextPeriod'),\n value: fmt(result.nextPeriod),\n },\n ],\n }}\n />\n ) : null}\n </Card.Body>\n </Card>\n ) : (\n <p className=\"type-body ds:text-muted-foreground\">\n {t('cycleCalculator.empty')}\n </p>\n )}\n </div>\n );\n },\n);\n\nCycleCalculator.displayName = 'CycleCalculator';\n"],"names":["__iconNode","Droplet","createLucideIcon","isoDate","cycleCalculatorAgent","handle","args","DEFAULT_CYCLE_LENGTH","LUTEAL_PHASE_DAYS","FERTILE_DAYS_AFTER","predictCycle","input","occurrences","cycle","lastPeriodStart","ovulation","addDays","fertileWindow","nextPeriod","upcomingPeriods","_","i","periodRange","rootVariants","cva","HIGHLIGHT_TOKEN","toIsoDate","d","format","fromIsoDate","iso","parseISO","CYCLE_LENGTH_RANGE","PERIOD_LENGTH_RANGE","inRange","n","min","max","CycleCalculator","forwardRef","defaultCycleLength","onResultChange","onInsert","insertVariant","onCopy","onError","insertBrand","id","width","className","ref","t","i18n","useTranslation","lastPeriod","setLastPeriod","useState","cycleLength","setCycleLength","periodLength","setPeriodLength","result","useMemo","dateFormatter","useEffect","today","liveRef","useRef","agentHandle","parsed","isAfter","days","useAgentRegistration","fmt","jsxs","jsx","FormField","DatePicker","NumberInput","Card","Badge","Check","Heart","InsertButton"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -7,7 +7,7 @@ import { R as C } from "./radio-TWf9Q-mp.js";
|
|
|
7
7
|
import { R as z } from "./radio-group-BmIqhIT2.js";
|
|
8
8
|
import { F as w } from "./form-field-D1oqYisL.js";
|
|
9
9
|
import { D as T } from "./date-picker-Bp64zk2p.js";
|
|
10
|
-
import { N as Y } from "./number-input-
|
|
10
|
+
import { N as Y } from "./number-input-CM1q9zvH.js";
|
|
11
11
|
import { C as U } from "./card-DPmk26CL.js";
|
|
12
12
|
import { B as W } from "./badge-CIt-UFEx.js";
|
|
13
13
|
import { I as ce } from "./insert-result-98J1QEp7.js";
|
|
@@ -568,4 +568,4 @@ Ae.displayName = "DueDateCalculator";
|
|
|
568
568
|
export {
|
|
569
569
|
Ae as D
|
|
570
570
|
};
|
|
571
|
-
//# sourceMappingURL=due-date-calculator-
|
|
571
|
+
//# sourceMappingURL=due-date-calculator-le1z3KpW.js.map
|