Skip to content

healthdatasafe/hds-forms-js

Repository files navigation

hds-forms

React component library for rendering forms from HDS item definitions. Converts HDS ItemDefs to form fields using Tailwind CSS styling, and handles bidirectional data conversion between form values and Pryv events.

Components

<HDSFormField>

Renders a single form field based on an HDS item data definition.

import { HDSFormField } from 'hds-forms';

<HDSFormField
  itemData={itemDef.data}
  value={value}
  onChange={(v) => setValue(v)}
/>

Supported field types: checkbox, date, text, number, select, composite, datasource-search.

Date / time / duration companions

When an item declares a dateTime or duration block, <HDSFormField> renders the corresponding companion input next to the value field — the companions write to the surrounding Pryv event's event.time / event.duration (Pryv-native), not to the payload schema. Companions can be exposed individually:

import { EventTimeInput, EventDurationInput } from 'hds-forms';

<EventTimeInput value={time} onChange={setTime} mandatory={false} />
<EventDurationInput value={duration} onChange={setDuration} maxSeconds={315360000} />

EventDurationInput has four modes — No (point-in-time), Ongoing (open-ended), Length (numeric + unit), End time (computed) — and respects mandatory / allowNull / maxSeconds from the item definition.

<HDSFormSection>

Renders a full form section (multiple fields + submit button). Resolves item keys via getHDSModel().

import { HDSFormSection } from 'hds-forms';

// Permanent section (default) — one-time profile data
<HDSFormSection
  section={{ type: 'permanent', itemKeys: ['bloodType', 'allergies'] }}
  onSubmit={(formData) => console.log(formData)}
/>

// Recurring section — repeated entries with date picker
<HDSFormSection
  section={{ type: 'recurring', label: { en: 'Daily tracking' }, itemKeys: ['temperature', 'notes'] }}
  onSubmit={(formData) => console.log(formData)}
  entries={previousEntries}
  onEditEntry={(index) => handleEdit(index)}
  onDeleteEntry={(index) => handleDelete(index)}
/>

Recurring sections render a date picker (defaults to today), an "Add entry" button, and a list of previously submitted entries with edit/delete actions.

Custom fields (Plan 45)

Sections accept optional customFieldKeys: string[] + customFields: CustomFieldDeclaration[]. Each custom-field key is rendered alongside canonical items via the existing <HDSFormField>. Form values for custom fields live under __cf::{templateId}::{key} so they can't collide with canonical itemKeys.

<HDSFormSection
  section={{
    type: 'recurring',
    itemKeys: ['fertility-cycles-start'],
    customFieldKeys: ['dcom'],
    customFields: appTemplate.customFields // from hds-lib's loadTemplate()
  }}
  onSubmit={...}
/>

For the submit / prefill round-trip, use buildCustomFieldEntries(customFieldKeys, customFields) to produce { key, itemDef }[] entries that plug straight into formDataToActions() and prefillFromEvents() alongside canonical entries. See hds-lib's CUSTOM-FIELDS-AND-SYSTEM.md for the full design reference.

Item context (Plan 46 — D3 mechanic)

Sections can pin an item to a descendant stream via itemCustomizations[itemKey].context:

<HDSFormSection
  section={{
    type: 'recurring',
    itemKeys: ['procedure-coded'],
    itemCustomizations: {
      'procedure-coded': { context: 'procedure-fertility' }
    }
  }}
  onSubmit={...}
/>

The resulting event uses the descendant streamId (procedure-fertility) instead of the item's default parent (procedure). forEvent() walks back up to resolve the original itemDef. Cross-subtree contexts are rejected. See data-model documentation/TREATMENT-PROCEDURE.md for the design rationale.

<DatasetSearch>

Renders a typeahead search field bound to a remote dataset endpoint (e.g. datasets-service's /medication, /treatment, /procedure). On selection, populates the host item's payload (drug / regimen / procedure) and any companion fields (intake.{doseValue, doseUnit, route}, procedure findings[], free-text notes). Companion fields render inline.

<EntryList>

Displays a compact table of recurring entries. Used internally by HDSFormSection but also exported for custom layouts.

Schema Utilities

import { schemaFor, jsonFormForItemDef } from 'hds-forms';

// Generate JSON Schema from item data
const schema = schemaFor(itemDef.data);

// Full conversion pipeline: schema + event data converter
const { schema, eventDataForFormData } = jsonFormForItemDef(itemDef);
const eventData = eventDataForFormData(formValues);

Event Data Conversion

import { prefillFromEvents, formDataToEventBatch } from 'hds-forms';

// Pre-fill form from existing Pryv events
const values = prefillFromEvents(itemDefs, events);

// Convert form submission to Pryv event batch
const batch = formDataToEventBatch(itemDefs, formData, timestamp);

Test App

An interactive test application is included in src-test-app/. It provides a UI to exercise all components and field types with the real HDS model.

npm run test-app:setup   # install test app dependencies (one-time)
npm run test-app         # launch dev server
npm run build:app        # build test app into dist/ for gh-pages

Prerequisites

  • Node.js >= 20
  • npm
  • hds-lib (HDS model must be initialized before using components)

Setup

npm run setup

Development

npm run dev        # library watch mode
npm run build      # library build (outputs to js/)
npm run test       # run unit tests
npm run test:watch # run tests in watch mode
npm run lint       # check linting
npm run typecheck  # check types

About

Forms abstraction for HDS app

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages