@petrarca/sonnet-core 0.7.0 → 0.9.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.
@@ -0,0 +1,582 @@
1
+ /**
2
+ * $ref Resolution -- resolves JSON Schema references.
3
+ *
4
+ * Walks the schema tree and replaces `{ "$ref": ... }` nodes with the
5
+ * corresponding sub-schema. By default it resolves local, in-document refs:
6
+ * `#/$defs/name` (Draft 2020-12) or `#/definitions/name` (Draft 7).
7
+ *
8
+ * A caller may inject a `RefResolver` to resolve ANY ref string (e.g. a schema
9
+ * registry id like `sdf_...`, or a canonical URI). The injected resolver is
10
+ * tried first, then the core types (coreTypes.ts), then the in-document
11
+ * `$defs`/`definitions` lookup, so every ref style works together. The resolver is synchronous: consumers that
12
+ * fetch schemas asynchronously (e.g. from a registry over HTTP) pre-load them
13
+ * into a map and pass a `(ref) => map[ref]` lookup. This keeps the toolkit pure
14
+ * (no HTTP, no async).
15
+ *
16
+ * Keywords beside the `$ref` apply with the target, as in 2020-12: they are
17
+ * merged on top of it -- a custom title -- and `properties` key by key,
18
+ * `required` as both lists, so a node narrows a property of the target (a
19
+ * quantity's units) without restating the rest. Refs that no resolver can
20
+ * satisfy are left as-is.
21
+ */
22
+
23
+ /** Resolve a `$ref` string to its target sub-schema, or undefined if unknown. */
24
+ type RefResolver = (ref: string) => JsonSchemaProperty | undefined;
25
+ /**
26
+ * Resolve `$ref` pointers in a JSON Schema document.
27
+ *
28
+ * By default resolves the core types and in-document `#/$defs` /
29
+ * `#/definitions` refs. Pass a `resolve` to also resolve registry/URI refs; it
30
+ * is tried first, the core types and the in-document lookup after it. The original schema is never mutated;
31
+ * a document with no refs to resolve is returned unchanged.
32
+ */
33
+ declare function resolveRefs(schema: JsonSchema, resolve?: RefResolver): JsonSchema;
34
+
35
+ /**
36
+ * Core types -- value types with one definition each, shared by every schema
37
+ * that uses them: a property is one by `$ref` to the type's id, and narrows it
38
+ * beside the `$ref` (a quantity's units). The ids are identifiers, never
39
+ * fetched: the definitions ship here and resolve without a server, before an
40
+ * injected resolver's and the in-document ones.
41
+ *
42
+ * The first is a quantity, aligned with FHIR's `Quantity` and openEHR's
43
+ * `DV_QUANTITY`: a number and a unit code -- UCUM unless `system` says
44
+ * otherwise -- and, optionally, a comparator. The unit's label is not stored:
45
+ * the question's units give it. See docs/design/core-types.md.
46
+ */
47
+
48
+ /**
49
+ * A value type: a value with one definition that schemas use by `$ref` to its
50
+ * id. Sonnet contributes the core types; an application contributes its own,
51
+ * with an id of its own. See docs/design/value-types.md (workspace).
52
+ */
53
+ interface ValueType {
54
+ /** The `$ref` id -- whose type it is is part of it. */
55
+ id: string;
56
+ /** What it is called where an author sees it. */
57
+ label: string;
58
+ /** What the `$ref` resolves to: its shape, validation and widget hint. */
59
+ definition: JsonSchemaProperty;
60
+ }
61
+ /** Where the core types' ids live. */
62
+ declare const CORE_TYPES_BASE = "https://schemas.petrarca-labs.com/core/";
63
+ /** The id of the quantity type, version 1. */
64
+ declare const QUANTITY_TYPE_ID = "https://schemas.petrarca-labs.com/core/quantity/v1";
65
+ /** UCUM, the unit system a quantity's unit is in when it names none. */
66
+ declare const UCUM_SYSTEM = "http://unitsofmeasure.org";
67
+ /** How a quantity's value relates to the actual one: "less than 5". */
68
+ type QuantityComparator = "<" | "<=" | ">=" | ">";
69
+ /** A quantity: a number and a unit code (UCUM unless `system` says otherwise). */
70
+ interface Quantity {
71
+ value: number;
72
+ unit: string;
73
+ system?: string;
74
+ comparator?: QuantityComparator;
75
+ }
76
+ /** The quantity type: a number and a unit code. */
77
+ declare const QUANTITY_TYPE: ValueType;
78
+ /** The id of the coded value type, version 1. */
79
+ declare const CODING_TYPE_ID = "https://schemas.petrarca-labs.com/core/coding/v1";
80
+ /**
81
+ * A coded value: a code from a code list, its code system, optionally the
82
+ * list's version and the label shown -- FHIR's `Coding`, a SKOS concept, a
83
+ * schema.org `DefinedTerm`. The label is stored: it records what was shown.
84
+ * A service may carry a field of its own on a coding (an internal key).
85
+ */
86
+ interface Coding {
87
+ system: string;
88
+ code: string;
89
+ version?: string;
90
+ display?: string;
91
+ }
92
+ /** A coding's identity -- its system and code, `system|code`: what tells codings apart, never their label. */
93
+ declare function codingKey(c: Pick<Coding, "code"> & {
94
+ system?: string;
95
+ }): string;
96
+ /** The coded value type: a code from a code list, searched through a terminology service. */
97
+ declare const CODING_TYPE: ValueType;
98
+ /** The id of the codeable concept type, version 1. */
99
+ declare const CODEABLE_CONCEPT_TYPE_ID = "https://schemas.petrarca-labs.com/core/codeable-concept/v1";
100
+ /** How a coding relates to a concept's first coding -- openEHR's `=` `>` `<`, SKOS's exact / broad / narrow match. */
101
+ type CodingMatch = "equivalent" | "broader" | "narrower";
102
+ /** One coding of a codeable concept: a coding, whether a person picked it, how it relates to the first, why it is there. */
103
+ interface ConceptCoding extends Coding {
104
+ /** Picked by a person -- FHIR's meaning; a coding a service mapped is not. */
105
+ userSelected?: boolean;
106
+ /** How it relates to the concept's first coding; none: nobody said. */
107
+ match?: CodingMatch;
108
+ /** Why it is there -- billing, a registry. */
109
+ purpose?: Coding;
110
+ }
111
+ /**
112
+ * A codeable concept: one concept, coded where it can be -- in as many code
113
+ * systems as it needs -- or given by its text alone. FHIR's `CodeableConcept`,
114
+ * openEHR's `DV_CODED_TEXT` with its mappings, ISO 21090's `CD`. See
115
+ * docs/design/codeable-concepts.md (workspace).
116
+ */
117
+ interface CodeableConcept {
118
+ codings?: ConceptCoding[];
119
+ /** What the person saw or said -- or the answer, when no code fits. */
120
+ text?: string;
121
+ }
122
+ /** The codeable concept type: one concept in several code systems, or its text alone. */
123
+ declare const CODEABLE_CONCEPT_TYPE: ValueType;
124
+ /** The core types: the value types sonnet contributes. */
125
+ declare const CORE_VALUE_TYPES: readonly ValueType[];
126
+ /** A resolver for value types' `$ref`s -- an application's, handed to the form renderer. */
127
+ declare function valueTypeResolver(types: readonly ValueType[]): RefResolver;
128
+ /** The definition of a core type, by its id; undefined for another ref. */
129
+ declare function coreType(ref: string): JsonSchemaProperty | undefined;
130
+ /** The core type a property is, by its `$ref`; undefined when it is none. */
131
+ declare function coreTypeOf(prop: JsonSchemaProperty): string | undefined;
132
+
133
+ /**
134
+ * Bindings -- a field's binding to a code list: `x-binding`, declared by
135
+ * sonnet-core beside the `x-ui-*` vocabulary. Which list (a value set or a
136
+ * code system, by an identifier the terminology service resolves), optionally
137
+ * its version, and how strictly: `required` -- only the list's codes -- or
138
+ * `extensible` -- another code, or a text of one's own, when none fits. A
139
+ * codeable concept's binding names more lists, `additional`: where its other
140
+ * codings come from. See docs/design/coded-values.md and
141
+ * docs/design/codeable-concepts.md (workspace).
142
+ */
143
+
144
+ /** How strictly a field takes its list. */
145
+ type BindingStrength = "required" | "extensible";
146
+ /** One more list of a codeable concept: where another of its codings comes from (FHIR R5 `binding.additional`). */
147
+ interface AdditionalBinding {
148
+ valueSet?: string;
149
+ system?: string;
150
+ version?: string;
151
+ /** What the list is called where an author or a person sees it (FHIR R5 `shortDoco`). */
152
+ title?: string;
153
+ /** A value must have a coding of this list, picked or mapped. */
154
+ required?: boolean;
155
+ /** Why its coding is there -- billing, a registry: the purpose of the coding it gives. */
156
+ purpose?: Coding;
157
+ }
158
+ /** A field's binding to a code list -- a codeable concept's, to more lists. */
159
+ interface Binding {
160
+ valueSet?: string;
161
+ system?: string;
162
+ version?: string;
163
+ /** What the first list is called where it is shown beside others -- a codeable concept's. */
164
+ title?: string;
165
+ strength: BindingStrength;
166
+ /** A codeable concept's further lists, after the first. */
167
+ additional?: AdditionalBinding[];
168
+ }
169
+ /** The binding a property declares; undefined when it has none, or not one of this shape. */
170
+ declare function bindingOf(prop: JsonSchemaProperty): Binding | undefined;
171
+ /** The lists of a binding in their order: the first, then the additional ones. */
172
+ declare function bindingLists(binding: Binding): AdditionalBinding[];
173
+ /**
174
+ * A code as a condition names it: `code`, of the code system the binding names,
175
+ * or FHIR's token `system|code` when of another. Read here.
176
+ */
177
+ declare function parseCodeToken(token: string, bound: string | undefined): {
178
+ system?: string;
179
+ code: string;
180
+ };
181
+ /** A code as a condition names it: its code alone when of the bound code system, else `system|code`. */
182
+ declare function codeToken(coding: {
183
+ system?: string;
184
+ code: string;
185
+ }, bound: string | undefined): string;
186
+
187
+ /**
188
+ * Generic JSON Schema type definitions.
189
+ *
190
+ * These types follow Draft 2020-12 and include x-ui-* extension points
191
+ * for form/widget integration. They are domain-agnostic -- no
192
+ * application-specific entity concepts live here.
193
+ */
194
+ /**
195
+ * A declarative presentation rule (JSONForms-style) attached to a field.
196
+ *
197
+ * The rule lives on the field it controls (the target). Its `condition` points
198
+ * at another field's value via a JSON Pointer (RFC 6901) into the form DATA
199
+ * (rooted at the whole form), and validates that value against `condition.schema`.
200
+ * When the condition holds, `effect` is applied to the target:
201
+ * - "show" -- render only when the condition holds
202
+ * - "hide" -- render only when the condition does NOT hold
203
+ * - "enable" -- interactive only when the condition holds
204
+ * - "disable"-- non-interactive when the condition holds
205
+ *
206
+ * Example: show `pregnancy_status` when `gender` equals "female":
207
+ * ```json
208
+ * { "effect": "show",
209
+ * "condition": { "scope": "/gender", "schema": { "const": "female" } } }
210
+ * ```
211
+ * Unlike if/then/else, the target field stays declared at its own position, so
212
+ * layout placement is stable.
213
+ */
214
+ interface UIRuleCondition {
215
+ /** JSON Pointer (RFC 6901) into the form data, e.g. "/gender" or "/patient/gender". */
216
+ scope: string;
217
+ /** Schema the value at `scope` is validated against (e.g. { const: "female" }). */
218
+ schema: JsonSchemaProperty;
219
+ }
220
+ type UIRuleEffect = "show" | "hide" | "enable" | "disable";
221
+ interface UIRule {
222
+ effect: UIRuleEffect;
223
+ condition: UIRuleCondition;
224
+ }
225
+ /**
226
+ * A named validator reference carried by `x-ui-validate`. The bare-string form
227
+ * is the no-config common case (`"ibanValid"`); the object form supplies
228
+ * per-reference config and, for async form validators, the inputs that trigger
229
+ * a re-run (`dependsOn`). See the custom-validation design in sonnet-forms.
230
+ */
231
+ interface UIValidateRef {
232
+ /** Registered validator name, resolved against the ValidatorRegistry. */
233
+ name: string;
234
+ /** Per-reference config, passed to the validator as `ctx.args`. */
235
+ args?: Record<string, unknown>;
236
+ /**
237
+ * For an async FORM validator: the field names whose values trigger a re-run.
238
+ * The engine keys/debounces the async result on these values. Ignored for
239
+ * sync validators and for field validators.
240
+ */
241
+ dependsOn?: string[];
242
+ }
243
+ /**
244
+ * The value of `x-ui-validate`: one validator or a list. On a property it
245
+ * selects field validators (`(value, ctx) => ...`); on the root object it
246
+ * selects form validators (`(data, ctx) => FieldError[]`). A bare string is
247
+ * shorthand for `{ name }`.
248
+ */
249
+ type UIValidate = string | UIValidateRef | Array<string | UIValidateRef>;
250
+ /**
251
+ * JSON Schema property definition following Draft 2020-12 specification.
252
+ * Supports basic types, validation constraints, conditionals, and custom extensions.
253
+ */
254
+ type JsonSchemaProperty = {
255
+ type?: "string" | "number" | "integer" | "boolean" | "array" | "object" | "null";
256
+ title?: string;
257
+ description?: string;
258
+ default?: any;
259
+ /** The value is shown, not entered (Draft 2020-12 meta-data vocabulary). */
260
+ readOnly?: boolean;
261
+ const?: any;
262
+ enum?: any[];
263
+ pattern?: string;
264
+ format?: string;
265
+ minLength?: number;
266
+ maxLength?: number;
267
+ minimum?: number;
268
+ maximum?: number;
269
+ exclusiveMinimum?: number;
270
+ exclusiveMaximum?: number;
271
+ /** The earliest / latest value of a formatted string -- a date, a time, a datetime (ajv-formats). */
272
+ formatMinimum?: string;
273
+ formatMaximum?: string;
274
+ items?: JsonSchemaProperty;
275
+ /** An array with at least one item matching it. */
276
+ contains?: JsonSchemaProperty;
277
+ minItems?: number;
278
+ maxItems?: number;
279
+ uniqueItems?: boolean;
280
+ properties?: Record<string, JsonSchemaProperty>;
281
+ required?: string[];
282
+ additionalProperties?: boolean | JsonSchemaProperty;
283
+ $ref?: string;
284
+ "x-binding"?: Binding;
285
+ $defs?: Record<string, JsonSchemaProperty>;
286
+ definitions?: Record<string, JsonSchemaProperty>;
287
+ allOf?: JsonSchemaProperty[];
288
+ anyOf?: JsonSchemaProperty[];
289
+ oneOf?: JsonSchemaProperty[];
290
+ not?: JsonSchemaProperty;
291
+ /**
292
+ * Discriminator for a `oneOf` union (OpenAPI convention). `propertyName` is
293
+ * the shared property whose `const` value tags the active branch. When
294
+ * absent, the discriminator is auto-detected as the property that is const
295
+ * in every branch.
296
+ */
297
+ discriminator?: {
298
+ propertyName: string;
299
+ };
300
+ if?: JsonSchemaProperty;
301
+ then?: JsonSchemaProperty;
302
+ else?: JsonSchemaProperty;
303
+ "x-ui-order"?: string[];
304
+ "x-ui-rule"?: UIRule;
305
+ "x-ui-widget"?: string;
306
+ "x-ui-options"?: Record<string, any>;
307
+ "x-ui-layout"?: UILayoutConfig;
308
+ "x-ui-title"?: string;
309
+ "x-ui-placeholder"?: string;
310
+ "x-ui-description"?: string;
311
+ "x-ui-validate"?: UIValidate;
312
+ "x-ui-column"?: {
313
+ /**
314
+ * Display order (ascending). Properties without an order are appended
315
+ * after the ordered ones, keeping their schema declaration order.
316
+ */
317
+ order?: number;
318
+ /** Exclude this column from the table entirely. */
319
+ hidden?: boolean;
320
+ /** Fixed column width in pixels. */
321
+ width?: number;
322
+ /** Minimum column width in pixels. */
323
+ minWidth?: number;
324
+ /**
325
+ * The data source can order by this column. EntityTable makes its header a
326
+ * sort control when the table is given sorting state -- the order itself is
327
+ * the consumer's query, never a sort of the rows on the page.
328
+ */
329
+ sortable?: boolean;
330
+ };
331
+ /** Cell renderer name. Inferred from type+format when absent. */
332
+ "x-ui-cell"?: string;
333
+ /** Cell renderer configuration options (colors, href template, etc.). */
334
+ "x-ui-cell-options"?: Record<string, unknown>;
335
+ };
336
+ /**
337
+ * JSON Schema following Draft 2020-12 specification.
338
+ *
339
+ * This is the generic base type. Domain-specific consumers extend it
340
+ * with their own x-* extension keys via intersection types in their
341
+ * own type files.
342
+ */
343
+ type JsonSchema = {
344
+ $schema?: string;
345
+ title: string;
346
+ description?: string;
347
+ type: "object";
348
+ properties: Record<string, JsonSchemaProperty>;
349
+ required?: string[];
350
+ additionalProperties?: boolean | JsonSchemaProperty;
351
+ allOf?: JsonSchemaProperty[];
352
+ anyOf?: JsonSchemaProperty[];
353
+ oneOf?: JsonSchemaProperty[];
354
+ not?: JsonSchemaProperty;
355
+ if?: JsonSchemaProperty;
356
+ then?: JsonSchemaProperty;
357
+ else?: JsonSchemaProperty;
358
+ $defs?: Record<string, JsonSchemaProperty>;
359
+ definitions?: Record<string, JsonSchemaProperty>;
360
+ "x-ui-order"?: string[];
361
+ "x-ui-validate"?: UIValidate;
362
+ [key: `x-${string}`]: unknown;
363
+ };
364
+ /**
365
+ * WidthToken -- the shared semantic sizing vocabulary used across the form
366
+ * layout system: per-field slot width (x-ui-width) and per-column width
367
+ * (UILayoutRowConfig.widths). "full" fills available space; sm/md/lg are
368
+ * fixed inline sizes. Raw CSS remains available as an advanced escape hatch.
369
+ */
370
+ type WidthToken = "sm" | "md" | "lg" | "full";
371
+ /**
372
+ * The fixed rem values for each non-full WidthToken. This is the single source
373
+ * of truth for token sizing used by:
374
+ * - the CSS grid track map in JsonSchemaFormRenderer (sm -> "8rem" track)
375
+ * - the Tailwind class map in FormFieldRenderer (sm -> w-32 = 8rem)
376
+ * Consumers that need px can multiply by 16.
377
+ */
378
+ declare const WIDTH_TOKEN_REMS: Record<WidthToken, string>;
379
+ /**
380
+ * UISchema - User Interface Schema configuration.
381
+ *
382
+ * Defines how form fields should be rendered and behave in the UI.
383
+ * Separate from JSON Schema (which defines data structure) and focuses
384
+ * on presentation, widgets, and user interaction.
385
+ */
386
+ interface UISchema {
387
+ /** Widget name (string) or direct component reference */
388
+ "x-ui-widget"?: string | object;
389
+ "x-ui-options"?: UISchemaOptions;
390
+ "x-ui-globalOptions"?: UISchemaOptions;
391
+ "x-ui-order"?: string[];
392
+ /** Declarative show/hide or enable/disable rule (see UIRule). */
393
+ "x-ui-rule"?: UIRule;
394
+ /** Custom validators by name (override of the schema-level x-ui-validate). */
395
+ "x-ui-validate"?: UIValidate;
396
+ "x-ui-title"?: string | false;
397
+ "x-ui-description"?: string;
398
+ "x-ui-placeholder"?: string;
399
+ /** Semantic field-slot width (default "full"). */
400
+ "x-ui-width"?: WidthToken;
401
+ /** Column override -- merged over schema-level x-ui-column, UI schema wins. */
402
+ "x-ui-column"?: JsonSchemaProperty["x-ui-column"] & {
403
+ label?: string;
404
+ };
405
+ /** Cell renderer override. */
406
+ "x-ui-cell"?: string;
407
+ /** Cell renderer options override -- shallow-merged over schema-level x-ui-cell-options. */
408
+ "x-ui-cell-options"?: Record<string, unknown>;
409
+ /** Per-field UISchema for nested sub-forms (ObjectWidget / ArrayWidget) */
410
+ "x-ui-fields"?: {
411
+ [fieldName: string]: UISchema;
412
+ };
413
+ /** Layout config forwarded to the active template (ObjectWidget / ArrayWidget) */
414
+ "x-ui-layout"?: UILayoutConfig;
415
+ /** Extension keys not yet enumerated above */
416
+ [key: `x-ui-${string}`]: unknown;
417
+ }
418
+ /**
419
+ * UILayoutRowConfig -- one horizontal row in a multi-column object form layout.
420
+ *
421
+ * `fields` lists the field names to place in this row, left to right.
422
+ * Column sizing (grid mode) is resolved in this precedence:
423
+ * 1. `columns` -- raw CSS grid-template-columns (advanced escape hatch).
424
+ * 2. `widths` -- per-cell semantic tokens (the designer-friendly path).
425
+ * 3. default -- equal 1fr per field.
426
+ * `gap` overrides the parent layout gap for this row only.
427
+ *
428
+ * `group` renders the row inside a titled fieldset (presentation-only grouping
429
+ * over flat schema fields -- the data shape is unchanged).
430
+ *
431
+ * Examples:
432
+ * { fields: ["first_name", "last_name"], widths: ["md", "full"] }
433
+ * { fields: ["npi", "specialty", "email"], columns: "20% 1fr 1fr" }
434
+ * { group: "Contact", fields: ["email", "phone"] }
435
+ */
436
+ interface UILayoutRowConfig {
437
+ fields: string[];
438
+ columns?: string;
439
+ /**
440
+ * Per-cell semantic widths, aligned to `fields` by index. Translated to grid
441
+ * tracks: sm/md/lg -> fixed rem tracks, full -> 1fr. Ignored when `columns`
442
+ * is set (raw CSS wins) or in "flow" mode. Missing/short entries default to
443
+ * "full".
444
+ */
445
+ widths?: WidthToken[];
446
+ gap?: number;
447
+ /**
448
+ * Optional title. When set, the row renders inside a <fieldset> with a
449
+ * <legend>, grouping its fields visually without nesting them in the schema.
450
+ */
451
+ group?: string;
452
+ /**
453
+ * How this row arranges its fields:
454
+ * - "grid" (default): CSS grid using `columns`/`widths` (equal 1fr per field
455
+ * when neither is set).
456
+ * - "flow": flex row, fields at their natural width, left-to-right, wrapping.
457
+ * Use for compact toolbars / tight field groups. `columns`/`widths` are
458
+ * ignored.
459
+ */
460
+ arrange?: "grid" | "flow";
461
+ }
462
+ /**
463
+ * One named group of a grouped form layout. A group holds rows of fields under
464
+ * a label; the data stays flat (grouping is presentation only, like `group` on
465
+ * a single row). How groups are shown -- tabs, wizard steps, stacked sections
466
+ * -- is chosen by {@link UILayoutConfig.variant}, not by this structure.
467
+ *
468
+ * A group may carry an `x-ui-rule`-style {@link UIRule} to appear conditionally
469
+ * (e.g. show an "Address" group only when "provide address" is checked). The
470
+ * rule is evaluated against the form data exactly as a field-level rule is.
471
+ */
472
+ interface UILayoutGroupConfig {
473
+ /** Label shown on the group's trigger or heading. */
474
+ label: string;
475
+ /** Rows of fields in this group (same shape as UILayoutConfig.rows). */
476
+ rows: UILayoutRowConfig[];
477
+ /**
478
+ * Optional show/hide rule for the whole group: a hidden group disappears
479
+ * along with its fields. Narrowed to the visibility effects -- a disabled
480
+ * group has no meaning, and permitting the effect would let it be authored
481
+ * and then silently ignored.
482
+ */
483
+ rule?: UIRule & {
484
+ effect: "show" | "hide";
485
+ };
486
+ }
487
+ /**
488
+ * UILayoutConfig -- layout configuration for ObjectWidget and ArrayWidget.
489
+ *
490
+ * Configures the built-in default templates. Has no effect when a custom
491
+ * template is registered for the field.
492
+ */
493
+ interface UILayoutConfig {
494
+ direction?: "vertical" | "horizontal";
495
+ rows?: UILayoutRowConfig[];
496
+ groups?: UILayoutGroupConfig[];
497
+ variant?: "tabs" | "stepper" | "sections" | (string & {});
498
+ columns?: string;
499
+ gap?: number;
500
+ labels?: boolean;
501
+ compact?: boolean;
502
+ labelPlacement?: "top" | "start";
503
+ }
504
+ /**
505
+ * ValueChange -- a single scalar or nested-object field that changed value.
506
+ *
507
+ * `path` is a dot-separated field path: "name", "address.city".
508
+ */
509
+ type ValueChange = {
510
+ type: "value";
511
+ path: string;
512
+ from: unknown;
513
+ to: unknown;
514
+ };
515
+ /**
516
+ * ArrayItemChange -- one item-level change within an array field.
517
+ *
518
+ * Items are identified by their form-internal `_fid` (never the server ID).
519
+ * A single item can appear as both "moved" and "modified" if it was
520
+ * repositioned and its values also changed -- these are emitted as two
521
+ * separate entries with the same `fid`.
522
+ */
523
+ type ArrayItemChange = {
524
+ type: "added";
525
+ fid: string;
526
+ index: number;
527
+ item: unknown;
528
+ } | {
529
+ type: "removed";
530
+ fid: string;
531
+ index: number;
532
+ item: unknown;
533
+ } | {
534
+ type: "moved";
535
+ fid: string;
536
+ from: number;
537
+ to: number;
538
+ } | {
539
+ type: "modified";
540
+ fid: string;
541
+ index: number;
542
+ changes: ValueChange[];
543
+ };
544
+ /**
545
+ * FieldDiff -- the diff for one top-level form field.
546
+ */
547
+ type FieldDiff = ValueChange | {
548
+ type: "array";
549
+ field: string;
550
+ changes: ArrayItemChange[];
551
+ };
552
+ /**
553
+ * FormDiff -- structured diff produced by diffFormData().
554
+ *
555
+ * One entry per changed top-level field. Fields whose value is deeply
556
+ * equal between original and updated are omitted.
557
+ */
558
+ type FormDiff = FieldDiff[];
559
+ /**
560
+ * UISchemaOptions - Widget configuration options.
561
+ */
562
+ interface UISchemaOptions {
563
+ label?: string | false;
564
+ disabled?: boolean;
565
+ readonly?: boolean;
566
+ compact?: boolean;
567
+ enumNames?: Record<string | number, string>;
568
+ inputType?: string;
569
+ rows?: number;
570
+ searchable?: boolean;
571
+ clearable?: boolean;
572
+ /** Allow the user to type and submit a value not in the enum list (combobox / open-choice). */
573
+ creatable?: boolean;
574
+ /** Label placement: "top" (default, above) or "start" (inline, RTL-safe). */
575
+ labelPlacement?: "top" | "start";
576
+ /** Semantic field-slot width (default "full"). */
577
+ width?: WidthToken;
578
+ [key: string]: any;
579
+ }
580
+
581
+ export { bindingLists as G, bindingOf as H, codeToken as I, codingKey as K, coreType as L, coreTypeOf as M, parseCodeToken as N, resolveRefs as O, valueTypeResolver as P, QUANTITY_TYPE as Q, WIDTH_TOKEN_REMS as W, CODEABLE_CONCEPT_TYPE as e, CODEABLE_CONCEPT_TYPE_ID as f, CODING_TYPE as g, CODING_TYPE_ID as h, CORE_TYPES_BASE as i, CORE_VALUE_TYPES as j, QUANTITY_TYPE_ID as n, UCUM_SYSTEM as q };
582
+ export type { AdditionalBinding as A, Binding as B, ConceptCoding as C, ValueType as D, WidthToken as E, FormDiff as F, JsonSchemaProperty as J, RefResolver as R, UIRule as U, ValueChange as V, JsonSchema as a, CodeableConcept as b, ArrayItemChange as c, BindingStrength as d, Coding as k, CodingMatch as l, FieldDiff as m, Quantity as o, QuantityComparator as p, UILayoutConfig as r, UILayoutGroupConfig as s, UILayoutRowConfig as t, UIRuleCondition as u, UIRuleEffect as v, UISchema as w, UISchemaOptions as x, UIValidate as y, UIValidateRef as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@petrarca/sonnet-core",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Shared utilities, schema tools, and hooks for the Petrarca Sonnet component library",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {
@@ -30,26 +30,34 @@
30
30
  "import": "./dist/entityOptions/index.js",
31
31
  "types": "./dist/entityOptions/index.d.ts"
32
32
  },
33
+ "./terminology": {
34
+ "types": "./dist/terminology/index.d.ts",
35
+ "import": "./dist/terminology/index.js"
36
+ },
33
37
  "./config": {
34
38
  "import": "./dist/config/index.js",
35
39
  "types": "./dist/config/index.d.ts"
40
+ },
41
+ "./logger": {
42
+ "import": "./dist/logger/index.js",
43
+ "types": "./dist/logger/index.d.ts"
36
44
  }
37
45
  },
38
46
  "files": [
39
47
  "dist"
40
48
  ],
41
49
  "dependencies": {
42
- "ajv": "^8.17.1",
50
+ "ajv": "^8.20.0",
43
51
  "ajv-formats": "^3.0.1",
44
52
  "class-variance-authority": "^0.7.1",
45
53
  "clsx": "^2.1.1",
46
- "nanoid": "^5.1.6",
54
+ "nanoid": "^5.1.16",
47
55
  "tailwind-merge": "3.3.1",
48
- "zod": "^4.3.6"
56
+ "zod": "^4.6.7"
49
57
  },
50
58
  "peerDependencies": {
51
- "react": ">=19",
52
- "@tanstack/react-query": ">=5"
59
+ "@tanstack/react-query": ">=5",
60
+ "react": ">=19"
53
61
  },
54
62
  "peerDependenciesMeta": {
55
63
  "@tanstack/react-query": {
@@ -57,16 +65,16 @@
57
65
  }
58
66
  },
59
67
  "devDependencies": {
60
- "@types/react": "^19.0.0",
61
- "tsup": "^8.4.0",
62
- "typescript": "^5.9.2"
68
+ "@types/react": "^19.3.0",
69
+ "tsup": "^9.0.0",
70
+ "typescript": "^5.9.3"
63
71
  },
64
72
  "scripts": {
65
73
  "build": "tsup",
66
74
  "dev": "tsup --watch",
67
75
  "typecheck": "tsc --noEmit",
68
76
  "lint": "tsc --noEmit",
69
- "test": "vitest run",
77
+ "test": "vitest run --config ../../vitest.config.ts",
70
78
  "clean": "rm -rf dist *.tsbuildinfo"
71
79
  }
72
80
  }