@alfadocs/ui-kit 1.2.0 → 1.3.0

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.
Files changed (62) hide show
  1. package/dist/_chunks/{actions-cell-renderer-ClGCSQnA.js → actions-cell-renderer-Ceah0ywE.js} +2 -2
  2. package/dist/_chunks/anamnesis-i18n-DGRdwc0i.js +8720 -0
  3. package/dist/_chunks/arrow-up-BYvcvTkB.js +26 -0
  4. package/dist/_chunks/{editable-currency-cell-renderer-Dus_sBvX.js → editable-currency-cell-renderer-Uhzkd0ZP.js} +68 -88
  5. package/dist/_chunks/{exceljs.min-DUJ-5CGx.js → exceljs.min-D2MHbJsF.js} +10 -9
  6. package/dist/_chunks/{face-scheme-Cou2efl7.js → face-scheme-C00IvkUA.js} +237 -243
  7. package/dist/_chunks/{file-manager-CNSLiuLo.js → file-manager-lNjcSXoD.js} +174 -186
  8. package/dist/_chunks/minus-BQDHq1c1.js +12 -0
  9. package/dist/_chunks/notebook-pen-CO7HoM-W.js +25 -0
  10. package/dist/_chunks/{notes-panel-CCz0J140.js → notes-panel-DPsgB4Mv.js} +73 -92
  11. package/dist/_chunks/{patient-table-DXk0wW8Q.js → patient-table-C7QHFC63.js} +2 -2
  12. package/dist/_chunks/share-2-B49jcW2I.js +18 -0
  13. package/dist/_chunks/{sparkline-DJtZBe7O.js → sparkline-BTY4B5tv.js} +153 -145
  14. package/dist/agent-catalog.json +1 -1
  15. package/dist/components/data-table/index.js +2 -2
  16. package/dist/components/face-scheme/index.js +1 -1
  17. package/dist/components/file-manager/index.js +1 -1
  18. package/dist/components/index.d.ts +1 -0
  19. package/dist/components/notes-panel/index.d.ts +1 -1
  20. package/dist/components/notes-panel/index.js +1 -1
  21. package/dist/components/patient-table/index.js +1 -1
  22. package/dist/components/sparkline/index.js +1 -1
  23. package/dist/components/sparkline/sparkline.d.ts +5 -4
  24. package/dist/index.js +132 -109
  25. package/dist/patterns/_shared/target-tile.d.ts +31 -0
  26. package/dist/patterns/anamnesis/anamnesis-catalogue.d.ts +23 -0
  27. package/dist/patterns/anamnesis/anamnesis-compare-panel.d.ts +82 -0
  28. package/dist/patterns/anamnesis/anamnesis-compile-blocks.d.ts +46 -0
  29. package/dist/patterns/anamnesis/anamnesis-compile.d.ts +48 -0
  30. package/dist/patterns/anamnesis/anamnesis-config-editor.d.ts +26 -0
  31. package/dist/patterns/anamnesis/anamnesis-config.d.ts +62 -0
  32. package/dist/patterns/anamnesis/anamnesis-derive.d.ts +194 -0
  33. package/dist/patterns/anamnesis/anamnesis-digest.d.ts +84 -0
  34. package/dist/patterns/anamnesis/anamnesis-disclosure.d.ts +19 -0
  35. package/dist/patterns/anamnesis/anamnesis-event-bar.d.ts +12 -0
  36. package/dist/patterns/anamnesis/anamnesis-events.d.ts +60 -0
  37. package/dist/patterns/anamnesis/anamnesis-evolution-grid.d.ts +48 -0
  38. package/dist/patterns/anamnesis/anamnesis-evolution.d.ts +37 -0
  39. package/dist/patterns/anamnesis/anamnesis-export-download.d.ts +10 -0
  40. package/dist/patterns/anamnesis/anamnesis-export-menu.d.ts +23 -0
  41. package/dist/patterns/anamnesis/anamnesis-export-pdf.d.ts +36 -0
  42. package/dist/patterns/anamnesis/anamnesis-export.d.ts +143 -0
  43. package/dist/patterns/anamnesis/anamnesis-field.d.ts +14 -0
  44. package/dist/patterns/anamnesis/anamnesis-format.d.ts +67 -0
  45. package/dist/patterns/anamnesis/anamnesis-i18n.d.ts +6 -0
  46. package/dist/patterns/anamnesis/anamnesis-indicators.d.ts +53 -0
  47. package/dist/patterns/anamnesis/anamnesis-intake.d.ts +16 -0
  48. package/dist/patterns/anamnesis/anamnesis-matrix.d.ts +91 -0
  49. package/dist/patterns/anamnesis/anamnesis-notes.d.ts +19 -0
  50. package/dist/patterns/anamnesis/anamnesis-readonly.d.ts +17 -0
  51. package/dist/patterns/anamnesis/anamnesis-summary.d.ts +35 -0
  52. package/dist/patterns/anamnesis/anamnesis-target-editor.d.ts +18 -0
  53. package/dist/patterns/anamnesis/anamnesis-target-strip.d.ts +14 -0
  54. package/dist/patterns/anamnesis/anamnesis-targets.d.ts +58 -0
  55. package/dist/patterns/anamnesis/anamnesis-types.d.ts +336 -0
  56. package/dist/patterns/anamnesis/anamnesis-visit-note.d.ts +35 -0
  57. package/dist/patterns/anamnesis/anamnesis-window.d.ts +37 -0
  58. package/dist/patterns/anamnesis/anamnesis.d.ts +48 -0
  59. package/dist/patterns/anamnesis/index.d.ts +8 -0
  60. package/dist/patterns/anamnesis/index.js +26 -0
  61. package/dist/tokens.css +1 -1
  62. package/package.json +5 -1
@@ -0,0 +1,31 @@
1
+ import type { ReactNode } from 'react';
2
+ /** Where the patient stands against one target. */
3
+ export type TargetStatus = 'onTarget' | 'approaching' | 'offTarget';
4
+ /** Traffic light → semantic Badge variant. green / amber / red map to the
5
+ * kit's success / warning / error tokens (each carries its own -foreground
6
+ * pairing, so the chip stays legible in all four themes). */
7
+ export declare const TARGET_STATUS_VARIANT: Record<TargetStatus, 'success' | 'warning' | 'error'>;
8
+ export interface TargetTileProps {
9
+ /** `outlined` (default) for hosts already inside a Card; `elevated`
10
+ * mirrors the kit Card's elevated recipe for tiles that read as cards. */
11
+ variant?: 'outlined' | 'elevated';
12
+ /** Metric name, e.g. "Target weight". Also the group's accessible name. */
13
+ label: string;
14
+ /** The TARGET, formatted with its unit — the tile's headline figure. */
15
+ target: string;
16
+ /** The patient's current value, already phrased ("Now 74.5 kg"). */
17
+ now: string;
18
+ /** Omit (or `null`) when no target is set — the tile then shows no chip. */
19
+ status?: TargetStatus | null;
20
+ /** Translated status text. Required whenever `status` is set: the traffic
21
+ * light is colour PLUS text, never colour alone (WCAG 1.4.1). */
22
+ statusLabel?: string;
23
+ /** Trailing affordance on the status row — e.g. an edit control. */
24
+ action?: ReactNode;
25
+ /** Extra body under the `now` line — e.g. a banded gauge for the current
26
+ * value. Kept adjacent to `now` so it reads as an elaboration of the
27
+ * measured figure, never of the headline target. */
28
+ children?: ReactNode;
29
+ }
30
+ export declare function TargetTile({ variant, label, target, now, status, statusLabel, action, children, }: TargetTileProps): import("react/jsx-runtime").JSX.Element;
31
+ //# sourceMappingURL=target-tile.d.ts.map
@@ -0,0 +1,23 @@
1
+ import type { IntakeSectionDef, LabParameterDefinition, NumericParameterDef, PathologyCode } from './anamnesis-types';
2
+ export declare const ANTHRO_PARAMETERS: NumericParameterDef[];
3
+ export declare const LAB_PARAMETERS: LabParameterDefinition[];
4
+ export declare const DIETARY_PARAMETERS: NumericParameterDef[];
5
+ /** Every numeric parameter, in evolution-grid row order (anthropometrics,
6
+ * dietary intake, then labs). Callers can slice this to build a smaller grid.
7
+ * Intake sits beside the anthropometrics it explains, and above the bloods
8
+ * that are only drawn once or twice a year. */
9
+ export declare const ALL_NUMERIC_PARAMETERS: NumericParameterDef[];
10
+ /** Fast lookup by key. */
11
+ export declare const PARAMETER_BY_KEY: Record<string, NumericParameterDef>;
12
+ export declare const PATHOLOGY_TAXONOMY: PathologyCode[];
13
+ export declare const PATHOLOGY_BY_CODE: Record<string, PathologyCode>;
14
+ /** i18next uses '.' as its key separator, so a pathology code like `E66.0`
15
+ * must be sanitised before it can be used as an i18n key segment. */
16
+ export declare const pathologyLabelKey: (code: string) => string;
17
+ /** Only the leaf/assignable codes (a parent family with sub-codes is a
18
+ * heading, not itself assignable). Parents without sub-codes stay assignable. */
19
+ export declare const ASSIGNABLE_PATHOLOGY_CODES: string[];
20
+ export declare const INTAKE_SECTIONS: IntakeSectionDef[];
21
+ /** Flat list of every intake field key (in registry order). */
22
+ export declare const INTAKE_FIELD_KEYS: string[];
23
+ //# sourceMappingURL=anamnesis-catalogue.d.ts.map
@@ -0,0 +1,82 @@
1
+ import type { TFunction } from 'i18next';
2
+ import type { SparklineAnnotation } from '../../components/sparkline';
3
+ import { type DeltaInfo, type SpanDiff } from './anamnesis-derive';
4
+ import type { NumericParameterDef, PathologyCode, Visit } from './anamnesis-types';
5
+ import type { VisitColumn } from './anamnesis-window';
6
+ /** The one grammar every category speaks. */
7
+ export type CompareChangeKind = 'added' | 'removed' | 'changed';
8
+ /** One line of the compare table. Every field is already display-ready, so
9
+ * the renderer below never reaches back into the domain model. */
10
+ export interface CompareRow {
11
+ /** Stable row id — `<category>:<subject>`. */
12
+ id: string;
13
+ /** Owning category's id (see `COMPARE_CATEGORIES`). */
14
+ categoryId: string;
15
+ /** What changed, in the clinician's words. */
16
+ item: string;
17
+ /** Second line under `item` — the unit and reference range, where there is
18
+ * one. Numeric rows only; the grid puts the same thing in the same place. */
19
+ meta?: string;
20
+ change: CompareChangeKind;
21
+ /** Translated change word — what the Change cell says when there is no
22
+ * number to say it with. */
23
+ changeLabel: string;
24
+ /** One display string per compared visit, in the diff's (record) order. */
25
+ values: string[];
26
+ /** Numeric rows only: the FULL-RECORD series, so the sparkline here is the
27
+ * same line as the grid's — not a shorter one drawn from the picked visits,
28
+ * which would move every event annotation. */
29
+ series?: (number | null)[];
30
+ /** Numeric rows only: the net first→last change, direction-aware. */
31
+ delta?: DeltaInfo | null;
32
+ /** Numeric rows only: needed to colour the delta by valence. */
33
+ def?: NumericParameterDef;
34
+ }
35
+ export interface CompareRowContext {
36
+ t: TFunction;
37
+ pathologies: Record<string, PathologyCode>;
38
+ /** Full-record sparkline series by parameter key. */
39
+ seriesByKey: ReadonlyMap<string, (number | null)[]>;
40
+ }
41
+ export interface CompareCategoryDef {
42
+ /** Stable id; also the i18n leaf under `anamnesis.compare.category.*`. */
43
+ id: string;
44
+ /** Pull this category's rows out of one span diff. */
45
+ rows: (diff: SpanDiff, ctx: CompareRowContext) => CompareRow[];
46
+ }
47
+ /** One entry per `SpanDiff` array, in reading order. A future symptom or
48
+ * event diff is ADDED here — the grammar, the columns and the renderer below
49
+ * stay untouched. Adding a category is data, never a rewrite. */
50
+ export declare const COMPARE_CATEGORIES: readonly CompareCategoryDef[];
51
+ /** Every difference across the compared visits as one flat, ordered list.
52
+ * Category order is the registry's order; within a category, the diff's own
53
+ * order. Nothing is sorted here — the record's order is the reading order. */
54
+ export declare function buildCompareRows(diff: SpanDiff, ctx: CompareRowContext): CompareRow[];
55
+ export interface AnamnesisComparePanelProps {
56
+ /** The record's visits, in record order — the picker's options. */
57
+ visits: Visit[];
58
+ /** The compared columns, resolved in RECORD order (never tick order). */
59
+ columns: readonly VisitColumn[];
60
+ /** Currently compared visit ids. */
61
+ selectedIds: readonly string[];
62
+ onSelectionChange: (ids: string[]) => void;
63
+ /** The computed diff, or `null` when fewer than two visits are compared. */
64
+ diff: SpanDiff | null;
65
+ /** Full-record sparkline series by parameter key. */
66
+ seriesByKey: ReadonlyMap<string, (number | null)[]>;
67
+ pathologies: Record<string, PathologyCode>;
68
+ /** The event lines drawn on the grid, so they are drawn here too. */
69
+ annotations?: readonly SparklineAnnotation[];
70
+ /** Make those lines pointer-selectable, exactly as they are on the grid.
71
+ * The event bar above the grid stays the keyboard route for both. */
72
+ onSelectAnnotation?: (eventId: string) => void;
73
+ t: TFunction;
74
+ /** Exit compare mode from inside the panel. The toggle that opened it is a
75
+ * full grid above, so without this the only way out is off-screen. */
76
+ onClose?: () => void;
77
+ }
78
+ /** Slot 4's contents: a header carrying the way out, the visit picker, then
79
+ * one matrix of differences. The enclosing `Collapsible` lives in
80
+ * `anamnesis-evolution.tsx`. */
81
+ export declare function AnamnesisComparePanel({ visits, columns, selectedIds, onSelectionChange, diff, seriesByKey, pathologies, annotations, onSelectAnnotation, t, onClose, }: AnamnesisComparePanelProps): import("react/jsx-runtime").JSX.Element;
82
+ //# sourceMappingURL=anamnesis-compare-panel.d.ts.map
@@ -0,0 +1,46 @@
1
+ import type { NumericParameterDef, Visit } from './anamnesis-types';
2
+ /** Open on arrival: the blocks a clinician records at — or must recall at —
3
+ * EVERY consultation. Visit details and anthropometrics are recorded each
4
+ * time; an unanswered required question is this visit's to-do list; the
5
+ * pathology list and the current therapy are the "what does this patient carry
6
+ * / already take" memory aids, and proposing a supplement without seeing the
7
+ * current medication is exactly the recall failure this surface prevents.
8
+ * The questionnaire itself is read on the Summary tab, not here. */
9
+ export declare const EVERY_VISIT_BLOCKS: readonly ["visitMeta", "intakeGaps", "anthropometrics", "pathologies", "therapy", "proposal"];
10
+ /** Folded on arrival at a FOLLOW-UP: reference or occasional. Oncological
11
+ * history is blank for most patients; bloods are drawn a few times a year;
12
+ * fasting cycles and the annual programme are yearly. Each keeps a fill
13
+ * summary in its header, so folding hides the detail and never the existence
14
+ * of a record. A first visit opens all of them — see `compileBlockDensity`. */
15
+ export declare const OCCASIONAL_BLOCKS: readonly ["oncological", "labs", "fmd", "annual"];
16
+ export type EveryVisitBlockId = (typeof EVERY_VISIT_BLOCKS)[number];
17
+ export type OccasionalBlockId = (typeof OCCASIONAL_BLOCKS)[number];
18
+ /** One titled block of the compile form whose arrival state this module
19
+ * decides. Adding an id to this union without listing it in one of the two
20
+ * arrays above is a type error. It does NOT catch a `<Block>` rendered in the
21
+ * JSX with no id at all — that block simply keeps the shell's own default. */
22
+ export type CompileBlockId = EveryVisitBlockId | OccasionalBlockId;
23
+ export interface CompileBlockDensity {
24
+ /** Open on arrival. */
25
+ open: boolean;
26
+ /** How much this block already holds, for the header summary. `null` on the
27
+ * always-open blocks, where a count beside visible content is noise. */
28
+ fill: number | null;
29
+ /** Of that fill, how many values sit outside their reference range. Named in
30
+ * the header so a folded block can never hide a flagged result. */
31
+ flagged: number;
32
+ }
33
+ /** How each compile block opens for the visit being recorded.
34
+ *
35
+ * A FIRST visit opens everything: there is no history to fold away, and an
36
+ * empty block on a first consultation means "to be filled", not "nothing to
37
+ * see". A follow-up folds the occasional blocks behind their fill summary.
38
+ *
39
+ * `labDefs` is the practice's live lab vocabulary — the same list the Blood
40
+ * tests block renders. Pass it, or the lab fill and flag counts describe a
41
+ * different set of values from the one the opened block shows.
42
+ *
43
+ * Safe on a record with no visit — everything falls back to the arrival
44
+ * default with no fill. */
45
+ export declare function compileBlockDensity(visit: Visit | undefined, labDefs?: readonly NumericParameterDef[]): Record<CompileBlockId, CompileBlockDensity>;
46
+ //# sourceMappingURL=anamnesis-compile-blocks.d.ts.map
@@ -0,0 +1,48 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { TFunction } from 'i18next';
3
+ import { type PracticeAnamnesisConfig } from './anamnesis-config';
4
+ import type { DisclosureAudience } from './anamnesis-disclosure';
5
+ import type { AnamnesisExportTab } from './anamnesis-export';
6
+ import type { AnamnesisRecord, OpenAnamnesisNote } from './anamnesis-types';
7
+ /** The three Diagnosis views. Also the three export tabs — one vocabulary. */
8
+ export type AnamnesisCompileView = AnamnesisExportTab;
9
+ export interface AnamnesisCompileProps {
10
+ record: AnamnesisRecord;
11
+ t: TFunction;
12
+ /** Mount flush inside a host section tab (drops the full-page chrome + the
13
+ * patient-name page heading — the host shows the patient banner). */
14
+ embedded?: boolean;
15
+ /** The practice's configured vocabulary. Omitted = the kit-seeded default. */
16
+ config?: PracticeAnamnesisConfig;
17
+ /** A per-patient target was set or cleared (`null` clears it). The surface
18
+ * applies it to its own working record either way; this is the seam a
19
+ * platform host persists through — and the one place a shared target could
20
+ * be reconciled with the care plan, which no story can do. */
21
+ onTargetChange?: (parameterKey: string, target: number | null) => void;
22
+ /** Host status chips rendered at the surface header's end — the slot a
23
+ * platform host uses to fold its OWN record state (signature status,
24
+ * expiry, save feedback, a renew affordance) into the section instead of
25
+ * bolting a second bar above it. Content is host-owned and already
26
+ * translated. The surface itself claims no save state. */
27
+ statusSlot?: ReactNode;
28
+ /** Omit the nutrition-targets strip above the record card — for hosts
29
+ * that present the record without the goals (the isolated single-section
30
+ * demo). Default false: the strip renders. Target editors inside the
31
+ * record blocks are unaffected. */
32
+ hideTargetStrip?: boolean;
33
+ /** The host's side panel, forwarded to the Evolution view. Omitted = the
34
+ * evolution surface reads notes in place. */
35
+ onOpenNote?: OpenAnamnesisNote;
36
+ /** Mount on this view instead of Summary. Demo/story hook only — Chromatic
37
+ * skips play functions, so a click-selected tab is never snapshotted. */
38
+ defaultView?: AnamnesisCompileView;
39
+ /** Mount with the export menu open. Demo/story hook only — Chromatic skips
40
+ * play functions, so a click-opened menu is never snapshotted. */
41
+ defaultExportMenuOpen?: boolean;
42
+ /** Mount with the share preview open. Demo/story hook, same reason. */
43
+ defaultShareOpen?: boolean;
44
+ /** Mount the export control on this audience. Demo/story hook. */
45
+ defaultExportAudience?: DisclosureAudience;
46
+ }
47
+ export declare function AnamnesisCompile({ record: initial, t, embedded, config, onTargetChange, hideTargetStrip, statusSlot, onOpenNote, defaultView, defaultExportMenuOpen, defaultShareOpen, defaultExportAudience, }: AnamnesisCompileProps): import("react/jsx-runtime").JSX.Element;
48
+ //# sourceMappingURL=anamnesis-compile.d.ts.map
@@ -0,0 +1,26 @@
1
+ import type { TFunction } from 'i18next';
2
+ import { type PracticeAnamnesisConfig } from './anamnesis-config';
3
+ export interface AnamnesisConfigEditorProps {
4
+ /** The practice's vocabulary — materialised (every list present). Build the
5
+ * initial value with `seededConfigDraft()`, never from the module constants
6
+ * directly: the editor patches lists immutably, but a shared array identity
7
+ * with the kit seed would leak one accidental in-place edit into every
8
+ * other mount in the session. */
9
+ config: Required<PracticeAnamnesisConfig>;
10
+ onConfigChange: (next: Required<PracticeAnamnesisConfig>) => void;
11
+ t: TFunction;
12
+ /** Override the cascade / test marker (defaults to `anamnesis-config-editor`). */
13
+ dataComponent?: string;
14
+ }
15
+ /** A per-entry deep-enough clone of the kit seed: sections own their `fields`
16
+ * arrays and parameters their `referenceRange` objects, so no array or object
17
+ * identity is shared with the module constants. */
18
+ export declare function seededConfigDraft(): Required<PracticeAnamnesisConfig>;
19
+ /** Derive an immutable camelCase key from a practice label — the practice
20
+ * never types identifiers, and a labelled entry can never render as a raw
21
+ * key. Uniquified with a numeric suffix on collision. Practice-derived keys
22
+ * are practice-LOCAL: they do not join any shared cross-practice vocabulary
23
+ * (the curated-library question — decision 0.3 — is still open). */
24
+ export declare function keyFromLabel(label: string, taken: ReadonlySet<string>): string;
25
+ export declare function AnamnesisConfigEditor({ config, onConfigChange, t, dataComponent, }: AnamnesisConfigEditorProps): import("react/jsx-runtime").JSX.Element;
26
+ //# sourceMappingURL=anamnesis-config-editor.d.ts.map
@@ -0,0 +1,62 @@
1
+ import type { IntakeFieldDef, IntakeSectionDef, NumericParameterDef, ParameterGroup, PathologyCode } from './anamnesis-types';
2
+ /** The only keys the derivation engine cannot lose. `bmi` is computed from
3
+ * `weight` + `height`; every other key in the kit is read generically. */
4
+ export declare const LOCKED_PARAMETER_KEYS: ReadonlySet<string>;
5
+ /** Whether a numeric parameter is locked against archiving / deletion. */
6
+ export declare function isParameterLocked(key: string): boolean;
7
+ /** Parameters a plan sets a per-patient GOAL for. Not every number is one: a
8
+ * height is a fact about the patient, and a blood test carries a population
9
+ * reference range rather than a target. The four the nutrition plan is written
10
+ * in — weight, BMI, daily energy, protein — plus waist, which practices have
11
+ * long set a goal for. */
12
+ export declare const TARGETABLE_PARAMETER_KEYS: ReadonlySet<string>;
13
+ /** Whether a per-patient target can be set for this parameter. */
14
+ export declare function isParameterTargetable(key: string): boolean;
15
+ /** A practice's anamnesis vocabulary. Every list is optional: an omitted list
16
+ * falls back to the kit-seeded catalogue, so `undefined` is a fully working
17
+ * configuration and every existing mount keeps rendering unchanged. */
18
+ export interface PracticeAnamnesisConfig {
19
+ /** Numeric parameters (anthropometrics + labs), in the practice's order. */
20
+ parameters?: readonly NumericParameterDef[];
21
+ /** The intake questionnaire — the practice's own form, transcribed. */
22
+ intakeSections?: readonly IntakeSectionDef[];
23
+ /** The coded pathology taxonomy. */
24
+ pathologies?: readonly PathologyCode[];
25
+ }
26
+ /** What the kit ships when a practice has configured nothing. Seeded, not
27
+ * empty — an empty vocabulary renders an empty record. */
28
+ export declare const SEEDED_ANAMNESIS_CONFIG: Required<PracticeAnamnesisConfig>;
29
+ /** Fill every omitted list from the seed. */
30
+ export declare function resolveConfig(config?: PracticeAnamnesisConfig): Required<PracticeAnamnesisConfig>;
31
+ /** CAPTURE surfaces: live parameters only. A locked parameter is never
32
+ * dropped, whatever the config says — archiving `weight` would silently break
33
+ * BMI everywhere. */
34
+ export declare function configuredParameters(config?: PracticeAnamnesisConfig, group?: ParameterGroup): NumericParameterDef[];
35
+ /** HISTORY surfaces: every parameter, archived ones included, so a value
36
+ * recorded under an archived parameter still renders. */
37
+ export declare function allParametersIncludingArchived(config?: PracticeAnamnesisConfig, group?: ParameterGroup): NumericParameterDef[];
38
+ /** Lookup over every parameter, archived included — callers resolving a key
39
+ * read from a record must never miss an archived one. */
40
+ export declare function parameterLookup(config?: PracticeAnamnesisConfig): Record<string, NumericParameterDef>;
41
+ /** CAPTURE: the questionnaire as the patient sees it — archived sections and
42
+ * fields dropped, and a section left with no live field dropped with them. */
43
+ export declare function configuredSections(config?: PracticeAnamnesisConfig): IntakeSectionDef[];
44
+ /** HISTORY: every section and field ever configured, so answers recorded under
45
+ * a since-archived question still render in the record and the read-only view.
46
+ * Using `configuredSections` here would erase them from the screen. */
47
+ export declare function allSectionsIncludingArchived(config?: PracticeAnamnesisConfig): IntakeSectionDef[];
48
+ /** Flat field lookup across every section, archived included. */
49
+ export declare function intakeFieldLookup(config?: PracticeAnamnesisConfig): Record<string, IntakeFieldDef>;
50
+ /** CAPTURE: live codes, in configured order. */
51
+ export declare function configuredPathologies(config?: PracticeAnamnesisConfig): PathologyCode[];
52
+ /** HISTORY: every code, archived included. A code assigned last year must
53
+ * still render its label this year. */
54
+ export declare function allPathologiesIncludingArchived(config?: PracticeAnamnesisConfig): PathologyCode[];
55
+ /** Lookup by code over the FULL taxonomy. Without this, reading
56
+ * `entry.parentCode` off a practice-added code throws. */
57
+ export declare function pathologyLookup(config?: PracticeAnamnesisConfig): Record<string, PathologyCode>;
58
+ /** Assignable codes: a family that carries sub-codes is a heading, not itself
59
+ * assignable. Derived from the LIVE taxonomy so an archived code cannot be
60
+ * newly assigned, but stays resolvable for history. */
61
+ export declare function assignablePathologyCodes(config?: PracticeAnamnesisConfig): string[];
62
+ //# sourceMappingURL=anamnesis-config.d.ts.map
@@ -0,0 +1,194 @@
1
+ import type { AnamnesisRecord, MedicationEntry, NumericParameterDef, Visit } from './anamnesis-types';
2
+ /** Anthropometric parameter keys map to AnthropometricSet fields; `bmi` is
3
+ * computed. Kept as a lookup so the grid can treat anthropometrics + labs
4
+ * uniformly. */
5
+ export declare const ANTHRO_FIELD_BY_KEY: Record<string, keyof Visit['anthropometrics']>;
6
+ /** `Timestamp` options for the record's calendar dates (visit date, date of
7
+ * birth, cycle start). Every one of them is a date-only ISO string, which
8
+ * `Date` parses as UTC midnight — rendered with the viewer's zone that shows a
9
+ * phantom time ("13 Apr 2026, 2:00" in CEST) and, west of UTC, the WRONG DAY.
10
+ * Dropping the time fields and pinning the zone to UTC makes the calendar date
11
+ * render as written, identically in every timezone (and so deterministically
12
+ * in Chromatic). */
13
+ export declare const CALENDAR_DATE_FORMAT: Intl.DateTimeFormatOptions;
14
+ /** BMI = kg / m². Thin `undefined`-tolerant wrapper over the kit's canonical
15
+ * BMI maths — the anthropometric set leaves unmeasured fields `undefined`,
16
+ * which `bmi-calculator/bmi` (a form-backed component) does not model. The
17
+ * formula itself lives there and is not restated here. */
18
+ export declare function computeBmi(weightKg: number | null | undefined, heightCm: number | null | undefined): number | null;
19
+ /** Whether a stored ISO string is a date `Date` can actually read. An archive
20
+ * holds blanks and typos; nothing downstream may throw or print "NaN" on one. */
21
+ export declare function isReadableDate(iso: string | null | undefined): boolean;
22
+ /** Whole-years age at a reference instant, or `null` when either date is
23
+ * unreadable OR the reference predates the birth — an unknown age is absent,
24
+ * never `NaN` and never negative. Reference is the record's
25
+ * own visit date (deterministic for stories / Chromatic), not the wall clock.
26
+ * Read in UTC because both inputs are date-only strings, which `Date` parses as
27
+ * UTC midnight: local getters return the previous day west of UTC. */
28
+ export declare function ageAt(dobIso: string, referenceIso: string): number | null;
29
+ /** Where a parameter's value actually lives on a `Visit`. */
30
+ export type ParameterStorage = 'computed' | 'anthropometric' | 'dietary' | 'lab';
31
+ /** Keys stored in `visit.dietaryIntake`. Explicit, like `ANTHRO_FIELD_BY_KEY`:
32
+ * the kit's two shipped intake parameters have a drawer of their own, and
33
+ * anything else a practice adds falls through to the open-ended one below. */
34
+ export declare const DIETARY_STORAGE_KEYS: ReadonlySet<string>;
35
+ /** Resolve a parameter's STORAGE HOME. Read and write branch on this, never on
36
+ * `def.group`: `AnthropometricSet` is a fixed shape, so a practice-added
37
+ * anthropometric has no field of its own and must round-trip through the
38
+ * open-ended `labs` array. Branching on `group` made it read null and store
39
+ * nothing. `bmi` keeps its explicit guard — `def.computed` is a bare boolean
40
+ * with no formula registry to dispatch on.
41
+ *
42
+ * `labs` stays the FALLBACK, so a key with no drawer of its own still stores
43
+ * and reads back. There is no such thing as a parameter with no storage home. */
44
+ export declare function parameterStorage(def: NumericParameterDef): ParameterStorage;
45
+ /** The raw numeric value of a parameter at a visit (BMI computed on the fly,
46
+ * the six shipped anthropometrics read from the set, everything else looked up
47
+ * in `labs` by key). Non-finite stored values read as absent. */
48
+ export declare function parameterValueAt(visit: Visit, def: NumericParameterDef): number | null;
49
+ /** Write a numeric value onto a visit at its storage home, returning a new
50
+ * visit. Computed parameters are never written. Pure — the surfaces call it
51
+ * through their own working-state setters. */
52
+ export declare function setNumericOnVisit(visit: Visit, def: NumericParameterDef, value: number | null): Visit;
53
+ /** Set or clear a per-patient target, returning a new record. `null` clears
54
+ * it. Pure — the surfaces call it through their own working-state setters,
55
+ * exactly as they call `setNumericOnVisit`. A non-finite target is not a goal
56
+ * and clears rather than storing "NaN". */
57
+ export declare function setTargetOnRecord(record: AnamnesisRecord, parameterKey: string, target: number | null): AnamnesisRecord;
58
+ export type RangeFlag = 'low' | 'high' | null;
59
+ /** Whether a value sits outside its reference range. */
60
+ export declare function outOfRange(value: number | null, range: NumericParameterDef['referenceRange']): RangeFlag;
61
+ export type DeltaDirection = 'up' | 'down' | 'flat';
62
+ export type DeltaValence = 'good' | 'bad' | 'neutral';
63
+ export interface DeltaInfo {
64
+ /** Signed change vs the previous visit (current − previous). */
65
+ abs: number;
66
+ direction: DeltaDirection;
67
+ valence: DeltaValence;
68
+ }
69
+ /** Direction-aware good/bad. Uses the parameter's `betterDirection` and, for
70
+ * `toRange`, the reference range — never the sign of the delta alone. */
71
+ export declare function deltaInfo(current: number | null, previous: number | null, def: NumericParameterDef): DeltaInfo | null;
72
+ export interface ParameterCell {
73
+ visitId: string;
74
+ value: number | null;
75
+ outOfRange: RangeFlag;
76
+ /** Change vs the immediately preceding visit; null for the first column. */
77
+ delta: DeltaInfo | null;
78
+ }
79
+ export interface ParameterRow {
80
+ def: NumericParameterDef;
81
+ /** One cell per record visit, aligned to `record.visits` order. */
82
+ cells: ParameterCell[];
83
+ /** ONE ENTRY PER RECORD VISIT, in visit order — the sparkline series. A
84
+ * `null` is a visit where this parameter was not measured, and it holds its
85
+ * place: dropping it would compress a four-times-measured lab across the
86
+ * same width as a thirteen-times-measured weight, and an event annotation
87
+ * would then land on a different date in each row. */
88
+ series: (number | null)[];
89
+ /** Per-patient target for this parameter, when one is configured. */
90
+ target: number | null;
91
+ }
92
+ /** Build the transposed grid: one row per parameter definition, one cell per
93
+ * visit, with derived deltas / out-of-range flags / sparkline series. */
94
+ export declare function buildParameterRows(record: AnamnesisRecord, defs: NumericParameterDef[]): ParameterRow[];
95
+ export interface NumericChange {
96
+ def: NumericParameterDef;
97
+ from: number | null;
98
+ to: number | null;
99
+ delta: DeltaInfo | null;
100
+ }
101
+ export interface PathologyChange {
102
+ code: string;
103
+ change: 'added' | 'removed';
104
+ }
105
+ export interface MedicationChange {
106
+ entry: MedicationEntry;
107
+ change: 'added' | 'removed' | 'changed';
108
+ previous?: MedicationEntry;
109
+ }
110
+ export type TextField = 'nutritionalProposal' | 'clinicalNotes';
111
+ /** The free-text fields a visit carries, in diff order. */
112
+ export declare const TEXT_FIELDS: readonly TextField[];
113
+ export interface TextChange {
114
+ field: TextField;
115
+ from?: string;
116
+ to?: string;
117
+ }
118
+ export interface VisitDiff {
119
+ from: Visit;
120
+ to: Visit;
121
+ numeric: NumericChange[];
122
+ pathologies: PathologyChange[];
123
+ medications: MedicationChange[];
124
+ texts: TextChange[];
125
+ }
126
+ /** Everything that changed between two visits — numeric parameters plus the
127
+ * non-numeric fields (pathologies added/removed, medications added/removed/
128
+ * changed, free-text notes edited). Only entries that actually differ are
129
+ * returned, so compare mode can mark exactly the changed cells. */
130
+ export declare function compareVisits(from: Visit, to: Visit, defs: NumericParameterDef[]): VisitDiff;
131
+ export interface NumericSpanChange {
132
+ def: NumericParameterDef;
133
+ /** One entry per compared visit, rounded to the parameter's precision. */
134
+ values: (number | null)[];
135
+ /** Net change, first compared visit → last. Null when either end is absent. */
136
+ delta: DeltaInfo | null;
137
+ }
138
+ export interface PathologySpanChange {
139
+ code: string;
140
+ /** Whether the code was assigned at each compared visit. */
141
+ present: boolean[];
142
+ }
143
+ export interface MedicationSpanChange {
144
+ id: string;
145
+ /** The entry at each compared visit; `undefined` where it was not carried. */
146
+ entries: (MedicationEntry | undefined)[];
147
+ }
148
+ export interface TextSpanChange {
149
+ field: TextField;
150
+ /** The field's text at each compared visit, trimmed; '' where absent. */
151
+ values: string[];
152
+ }
153
+ export interface SpanDiff {
154
+ /** The compared visits, in the order given (record order). Never below two. */
155
+ visits: Visit[];
156
+ numeric: NumericSpanChange[];
157
+ pathologies: PathologySpanChange[];
158
+ medications: MedicationSpanChange[];
159
+ texts: TextSpanChange[];
160
+ }
161
+ /** Everything that is not constant across two or more visits. `null` below
162
+ * two visits — there is no span to read, and an empty diff would claim there
163
+ * was nothing to report. */
164
+ export declare function compareVisitSpan(visits: readonly Visit[], defs: NumericParameterDef[]): SpanDiff | null;
165
+ /** The newest visit — the editable one in compile mode, and the record's one
166
+ * reference instant for anything dated against "now": the patient's age, the
167
+ * header's visit date. Every surface must read it from here. Intake used to
168
+ * date itself to `visits[0]` while compile and read-only used the last visit,
169
+ * which printed two different ages for the same patient. */
170
+ export declare function latestVisit(record: AnamnesisRecord): Visit | undefined;
171
+ /** The one string every absent value renders as. Never a bare hyphen, never a
172
+ * blank, never "NaN". */
173
+ export declare const ABSENT_VALUE = "\u2014";
174
+ /** Format a numeric value to its parameter precision, or an em dash when
175
+ * absent. `0` formats as a value; a non-finite number is absent, because
176
+ * `NaN.toFixed(1)` is the string "NaN" and that must never reach a cell.
177
+ * Callers append the unit separately. */
178
+ export declare function formatValue(value: number | null, precision?: number): string;
179
+ /** Localised medium date (e.g. "12 May 2025") from an ISO date string.
180
+ * @deprecated Pins neither timezone nor locale. Use `visitDateLabel`
181
+ * (anamnesis-format.ts) for anything date-only; it is the reason this has no
182
+ * callers left. */
183
+ export declare function formatDateMedium(iso: string): string;
184
+ /** Localised calendar date from a date-only ISO string, pinned to UTC through
185
+ * `CALENDAR_DATE_FORMAT`. Prefer `visitDateLabel` (anamnesis-format.ts), which
186
+ * resolves `locale` from the surface's `t` — omitting it falls back to the
187
+ * BROWSER locale, which disagrees with `<Timestamp>` on the same screen.
188
+ * An unreadable date renders the em dash: `Intl` THROWS on one, which would
189
+ * take down the whole evolution surface rather than blank one label. */
190
+ export declare function formatCalendarDate(iso: string, locale?: string): string;
191
+ /** Signed, precision-formatted delta string (e.g. "+2.4", "−1.0"). Uses a
192
+ * real minus sign for the negative case. */
193
+ export declare function formatDelta(abs: number, precision?: number): string;
194
+ //# sourceMappingURL=anamnesis-derive.d.ts.map
@@ -0,0 +1,84 @@
1
+ import type { RefObject } from 'react';
2
+ import type { TFunction } from 'i18next';
3
+ import { type AlertAnnounce } from '../../components/alert';
4
+ import type { IntakeAnswer, IntakeSectionDef, PatientSex } from './anamnesis-types';
5
+ /** How one digest group is built. Phase 3 adds a group by adding an entry
6
+ * here — the renderer switches on `kind` and never on a group id. */
7
+ export type DigestGroupKind = 'prose' | 'facts' | 'flags';
8
+ export type DigestGroupDef = {
9
+ id: string;
10
+ kind: 'prose';
11
+ fieldKeys: readonly string[];
12
+ } | {
13
+ id: string;
14
+ kind: 'facts';
15
+ fieldKeys: readonly string[];
16
+ } | {
17
+ id: string;
18
+ kind: 'flags';
19
+ };
20
+ /** Reading order for a clinician with the patient in the room: why they came,
21
+ * what they already carry, what they report, what they do every day. */
22
+ export declare const DIGEST_GROUPS: readonly DigestGroupDef[];
23
+ /** Reads one answer by field key. Both surfaces hold their answers in a
24
+ * different shape (a working map vs `Sourced<IntakeAnswer>`), so the digest
25
+ * takes a reader rather than either shape. */
26
+ export type AnswerReader = (key: string) => IntakeAnswer | undefined;
27
+ export interface DigestItem {
28
+ key: string;
29
+ label: string;
30
+ /** Already display-ready. Absent numerics are an em dash, never "NaN". */
31
+ value: string;
32
+ }
33
+ export interface DigestGroup {
34
+ id: string;
35
+ kind: DigestGroupKind;
36
+ items: DigestItem[];
37
+ }
38
+ export interface IntakeDigest {
39
+ /** Only groups that have something to say. */
40
+ groups: DigestGroup[];
41
+ answered: number;
42
+ total: number;
43
+ }
44
+ export interface MissingAnswer {
45
+ key: string;
46
+ sectionKey: string;
47
+ label: string;
48
+ }
49
+ /** The whole digest. Pure apart from `t`; safe on an absent questionnaire, a
50
+ * half-answered one, and a practice that archived half the form. */
51
+ export declare function buildIntakeDigest(sections: readonly IntakeSectionDef[], read: AnswerReader, sex: PatientSex, t: TFunction): IntakeDigest;
52
+ /** Mandatory questions the patient has not answered, in questionnaire order.
53
+ * "Not sure" counts as unanswered — provisional, and flagged in the `.mdx`. */
54
+ export declare function missingMandatoryAnswers(sections: readonly IntakeSectionDef[], read: AnswerReader, sex: PatientSex, t: TFunction): MissingAnswer[];
55
+ /** Jump-to-field seam. The caller opens whatever disclosures hide the target
56
+ * (on compile that is BOTH the section block and the answer review), then asks
57
+ * for the jump; this waits for the reveal to mount before moving focus. */
58
+ export declare function useFieldJump(): {
59
+ containerRef: RefObject<HTMLDivElement | null>;
60
+ requestJump: (key: string) => void;
61
+ };
62
+ export interface AnamnesisMissingAnswersProps {
63
+ missing: readonly MissingAnswer[];
64
+ t: TFunction;
65
+ /** Reveals the first missing answer and moves focus to it. */
66
+ onJump: (missing: MissingAnswer) => void;
67
+ /** How loudly this is announced. Pass `'off'` where the list RECOMPUTES as
68
+ * the user types — a live region re-announces its whole content on every
69
+ * change, so a per-keystroke summary is noise, not help. Default `'polite'`
70
+ * suits a list fixed at mount. */
71
+ announce?: AlertAnnounce;
72
+ /** Label for the jump action. Override where the jump LEAVES the surface —
73
+ * a button that changes tab has to say so before it moves focus. */
74
+ jumpKey?: string;
75
+ }
76
+ /** Guidance, not an interruption. Tint and urgency are independent in the kit,
77
+ * so the `info` tint here is a visual choice, separate from `announce`. */
78
+ export declare function AnamnesisMissingAnswers({ missing, t, onJump, announce, jumpKey, }: AnamnesisMissingAnswersProps): import("react/jsx-runtime").JSX.Element | null;
79
+ export interface AnamnesisDigestProps {
80
+ digest: IntakeDigest;
81
+ t: TFunction;
82
+ }
83
+ export declare function AnamnesisDigest({ digest, t }: AnamnesisDigestProps): import("react/jsx-runtime").JSX.Element;
84
+ //# sourceMappingURL=anamnesis-digest.d.ts.map
@@ -0,0 +1,19 @@
1
+ /** Who a concept may be disclosed to. `clinician` is implicit on every row. */
2
+ export type DisclosureAudience = 'clinician' | 'patient' | 'external';
3
+ export interface DisclosureRule {
4
+ /** Stable concept id — never a UI label, never a data-model field path. */
5
+ id: string;
6
+ /** Where the concept is captured or rendered. */
7
+ surface: 'intake' | 'compile' | 'evolution' | 'readOnly' | 'export';
8
+ /** Audiences allowed to see it. Always includes 'clinician'. */
9
+ audiences: readonly DisclosureAudience[];
10
+ /** One English sentence, for the customer sign-off walkthrough. */
11
+ rationale: string;
12
+ /** 'provisional' = our judgement, not the customer's. */
13
+ status: 'provisional' | 'signedOff';
14
+ }
15
+ export declare const DISCLOSURE_RULES: readonly DisclosureRule[];
16
+ /** The one resolver. Never inline this logic. An unknown id is NOT disclosed —
17
+ * a concept with no row is a concept nobody has thought about yet. */
18
+ export declare function disclosedTo(id: string, audience: DisclosureAudience): boolean;
19
+ //# sourceMappingURL=anamnesis-disclosure.d.ts.map
@@ -0,0 +1,12 @@
1
+ import type { TFunction } from 'i18next';
2
+ import { type EventMark } from './anamnesis-events';
3
+ export interface AnamnesisEventBarProps {
4
+ /** Events that HAVE a position on the plot, in the order they happened.
5
+ * One with no place on it never reaches here — see `eventMarks`. */
6
+ marks: readonly EventMark[];
7
+ activeIds: ReadonlySet<string>;
8
+ onToggle: (eventId: string) => void;
9
+ t: TFunction;
10
+ }
11
+ export declare function AnamnesisEventBar({ marks, activeIds, onToggle, t, }: AnamnesisEventBarProps): import("react/jsx-runtime").JSX.Element | null;
12
+ //# sourceMappingURL=anamnesis-event-bar.d.ts.map