@petrarca/sonnet-forms 0.5.0 → 0.6.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.
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React$1 from 'react';
3
3
  import React__default, { ComponentType, ReactNode } from 'react';
4
4
  import { Input, Textarea, badgeVariants } from '@petrarca/sonnet-ui';
5
- import { JsonSchemaProperty, UILayoutConfig, JsonSchema, UISchema, UISchemaOptions, FormDiff } from '@petrarca/sonnet-core/schema';
5
+ import { JsonSchemaProperty, UILayoutConfig, JsonSchema, UISchema, UISchemaOptions, FormDiff, RefResolver, FieldError } from '@petrarca/sonnet-core/schema';
6
6
  export { UISchema, UISchemaOptions } from '@petrarca/sonnet-core/schema';
7
7
  import { VariantProps } from 'class-variance-authority';
8
8
 
@@ -419,6 +419,33 @@ interface ObjectContainerTemplateProps {
419
419
  variant?: string;
420
420
  defaultOpen?: boolean;
421
421
  }
422
+ /**
423
+ * One group of fields in a grouped layout (a tab, a wizard step, a section).
424
+ * `content` is already laid out -- the template only decides how groups are
425
+ * presented and navigated.
426
+ */
427
+ interface FieldGroup {
428
+ /** Stable key for React and for the template's own selection state. */
429
+ key: string;
430
+ /** Label shown on the group's trigger, step header or section legend. */
431
+ label: string;
432
+ /** The group's rendered rows. */
433
+ content: React.ReactNode;
434
+ /** Validation errors owned by this group's fields (for a badge). */
435
+ errorCount: number;
436
+ }
437
+ /** Props passed to a GroupLayoutTemplate */
438
+ interface GroupLayoutTemplateProps {
439
+ /** The visible groups, in declaration order. Never empty. */
440
+ groups: FieldGroup[];
441
+ }
442
+ /**
443
+ * Presents a set of field groups: as tabs, as a wizard, as an accordion --
444
+ * whatever the registered template renders. Selected by
445
+ * `x-ui-layout.variant`, which maps to a TemplateRegistry key, so consumers
446
+ * can register their own presentation without changing the renderer.
447
+ */
448
+ type GroupLayoutTemplate = (props: GroupLayoutTemplateProps) => React.ReactElement;
422
449
  type ArrayItemTemplate = (props: ArrayItemTemplateProps) => React.ReactElement;
423
450
  type ArrayHeaderTemplate = (props: ArrayHeaderTemplateProps) => React.ReactElement | null;
424
451
  type ObjectContainerTemplate = (props: ObjectContainerTemplateProps) => React.ReactElement;
@@ -435,6 +462,10 @@ type TemplateRegistry = {
435
462
  HorizontalArrayItemTemplate?: ArrayItemTemplate;
436
463
  ArrayHeaderTemplate?: ArrayHeaderTemplate;
437
464
  ObjectContainerTemplate?: ObjectContainerTemplate;
465
+ /** Group presentations, selected by x-ui-layout.variant (default "tabs"). */
466
+ TabsGroupTemplate?: GroupLayoutTemplate;
467
+ StepperGroupTemplate?: GroupLayoutTemplate;
468
+ SectionsGroupTemplate?: GroupLayoutTemplate;
438
469
  [templateName: string]: unknown;
439
470
  };
440
471
 
@@ -839,6 +870,83 @@ declare function ArrayWidget({ propertySchema, value, onChange, registry, uiSche
839
870
 
840
871
  declare function QuantityWidget({ id, name, value, onChange, onBlur, propertySchema, required, disabled, readonly, rawErrors, label, description, placeholder, autofocus, options, }: WidgetProps): react_jsx_runtime.JSX.Element;
841
872
 
873
+ /**
874
+ * DateWidget - date field widget backed by the DateInput primitive.
875
+ *
876
+ * Renders a text input with calendar popover. Value is a partial ISO 8601 date
877
+ * string (`YYYY`, `YYYY-MM`, or `YYYY-MM-DD`). Auto-resolves from schema
878
+ * `format: "date"`, or `x-ui-widget: "date"`.
879
+ *
880
+ * x-ui-options:
881
+ * precision - "year" | "month" | "day" (default "day")
882
+ * locale - BCP-47 locale override (defaults to the app locale)
883
+ *
884
+ * The label/description chrome comes from FormFieldWrapper; the primitive owns
885
+ * the inline error message and invalid border.
886
+ */
887
+
888
+ declare function DateWidget({ id, value, onChange, onBlur, required, disabled, rawErrors, label, description, placeholder, options, }: WidgetProps): React.ReactElement;
889
+
890
+ /**
891
+ * TimeWidget - time-of-day field widget backed by the TimeInput primitive.
892
+ *
893
+ * Zone-free time value as a normalized ISO string (`HH:mm` or `HH:mm:ss`).
894
+ * Auto-resolves from schema `format: "time"`, or `x-ui-widget: "time"`.
895
+ *
896
+ * x-ui-options:
897
+ * granularity - "minute" | "second" (default "minute")
898
+ *
899
+ * The label/description chrome comes from FormFieldWrapper; the primitive owns
900
+ * the inline error message and invalid border.
901
+ */
902
+
903
+ declare function TimeWidget({ id, value, onChange, onBlur, required, disabled, rawErrors, label, description, placeholder, options, }: WidgetProps): React.ReactElement;
904
+
905
+ /**
906
+ * DateTimeWidget - date + time field widget backed by the DateTimeInput primitive.
907
+ *
908
+ * Plain wall-clock value as an ISO string (`YYYY-MM-DDTHH:mm[:ss]`), no
909
+ * timezone. Auto-resolves from schema `format: "date-time"`, or
910
+ * `x-ui-widget: "date-time"`.
911
+ *
912
+ * x-ui-options:
913
+ * granularity - "minute" | "second" (default "minute")
914
+ * timeZone - IANA id shown as a display-only hint (never applied)
915
+ * locale - BCP-47 locale override for the date part
916
+ *
917
+ * The label/description chrome comes from FormFieldWrapper; the primitive owns
918
+ * the inline error message and invalid border.
919
+ */
920
+
921
+ declare function DateTimeWidget({ id, value, onChange, onBlur, required, disabled, rawErrors, label, description, options, }: WidgetProps): React.ReactElement;
922
+
923
+ /**
924
+ * DisplayWidget - read-only text block, no data binding.
925
+ *
926
+ * Renders a property's title (and optional description) as static text --
927
+ * instructions, notes, disclaimers placed between fields. Collects no value.
928
+ * Auto-resolves from `type: "null"`, or `x-ui-widget: "display"`.
929
+ *
930
+ * Modeled as a value-less property so it participates in field ordering and
931
+ * layout (appears exactly where placed). It never contributes to form data.
932
+ */
933
+
934
+ declare function DisplayWidget({ label, description, }: WidgetProps): React.ReactElement | null;
935
+
936
+ /**
937
+ * OneOfWidget -- renders a discriminated union (oneOf).
938
+ *
939
+ * A branch selector (reusing the Select primitive) chooses one of the property's
940
+ * `oneOf` branches; the selected branch's object sub-schema is then rendered as
941
+ * a nested sub-form (same pattern as ObjectWidget). The active branch is tracked
942
+ * by the discriminator property (see the oneOf helpers in
943
+ * @petrarca/sonnet-core/schema).
944
+ *
945
+ * Auto-resolves when a property has `oneOf`, or via `x-ui-widget: "one-of"`.
946
+ */
947
+
948
+ declare function OneOfWidget({ propertySchema, value, onChange, registry, uiSchema, disabled, readonly, label, description, id, options, }: WidgetProps): React.ReactElement | null;
949
+
842
950
  /**
843
951
  * Widget Resolution Algorithm
844
952
  *
@@ -977,6 +1085,12 @@ type JsonSchemaFormRendererProps = {
977
1085
  * field validation still applies. Default false (edit semantics).
978
1086
  */
979
1087
  allowPristineSave?: boolean;
1088
+ /**
1089
+ * Optional resolver for non-local `$ref`s (schema-registry id / canonical
1090
+ * URI). Tried before the in-document `$defs` fallback. Synchronous -- the
1091
+ * caller pre-loads referenced schemas into a map and passes a lookup.
1092
+ */
1093
+ refResolver?: RefResolver;
980
1094
  /** Label for Save button (default: "Save") */
981
1095
  saveLabel?: string;
982
1096
  /** Label for Cancel button (default: "Cancel") */
@@ -1108,6 +1222,12 @@ interface UseFormEngineOptions {
1108
1222
  * Validation (required fields) still applies. Default false (edit semantics).
1109
1223
  */
1110
1224
  allowPristineSave?: boolean;
1225
+ /**
1226
+ * Optional resolver for non-local `$ref`s (e.g. a schema-registry id or
1227
+ * canonical URI). Tried before the in-document `$defs` fallback. Must be
1228
+ * synchronous -- pre-load referenced schemas into a map and pass a lookup.
1229
+ */
1230
+ refResolver?: RefResolver;
1111
1231
  }
1112
1232
  interface UseFormEngineResult {
1113
1233
  /** The current working form data (for controlled field values) */
@@ -1123,12 +1243,17 @@ interface UseFormEngineResult {
1123
1243
  orderedProperties: [string, JsonSchemaProperty][];
1124
1244
  hasChanges: boolean;
1125
1245
  isValid: boolean;
1246
+ /**
1247
+ * Current validation errors, each attributed to its field by JSON Pointer.
1248
+ * Lets the renderer surface problems for fields that are not on screen.
1249
+ */
1250
+ fieldErrors: FieldError[];
1126
1251
  handleFieldChange: (fieldName: string, value: any) => void;
1127
1252
  handleFieldBlur: (fieldName: string) => void;
1128
1253
  handleSave: () => void;
1129
1254
  handleCancel: () => void;
1130
1255
  }
1131
- declare function useFormEngine({ schema, data, uiSchema, onChange, onBlur, onValidationChange, onUpdate, onCancel, readOnly, showActions, deferChanges, deferStateUpdates, allowPristineSave, }: UseFormEngineOptions): UseFormEngineResult;
1256
+ declare function useFormEngine({ schema, data, uiSchema, onChange, onBlur, onValidationChange, onUpdate, onCancel, readOnly, showActions, deferChanges, deferStateUpdates, allowPristineSave, refResolver, }: UseFormEngineOptions): UseFormEngineResult;
1132
1257
 
1133
1258
  /**
1134
1259
  * useResolvedSchema - Schema resolution and property ordering
@@ -1190,6 +1315,63 @@ interface NestedFormContextValue {
1190
1315
 
1191
1316
  declare function useNestedFormContext(): NestedFormContextValue;
1192
1317
 
1318
+ /**
1319
+ * TabsGroupTemplate -- presents field groups as a tab bar (the default for
1320
+ * `x-ui-layout.tabs`).
1321
+ *
1322
+ * Selection is controlled and clamped to a group that still exists, so hiding
1323
+ * the group the user is on (via its rule) falls back to the first remaining one
1324
+ * instead of leaving an empty body.
1325
+ */
1326
+
1327
+ declare function TabsGroupTemplate({ groups, }: GroupLayoutTemplateProps): React__default.ReactElement;
1328
+
1329
+ /**
1330
+ * StepperGroupTemplate -- presents field groups as a wizard
1331
+ * (`x-ui-layout.variant: "stepper"`).
1332
+ *
1333
+ * Same group model as the tab presentation, different chrome: a numbered step
1334
+ * rail plus Back/Next. Steps stay directly clickable so the user is never
1335
+ * trapped; validation gating is deliberately not applied here, because a
1336
+ * group's errors are advisory (the badge) rather than a hard barrier.
1337
+ *
1338
+ * Selection is controlled and clamped to a group that still exists, so hiding
1339
+ * the step the user is on falls back to the first remaining one.
1340
+ */
1341
+
1342
+ declare function StepperGroupTemplate({ groups, }: GroupLayoutTemplateProps): React__default.ReactElement;
1343
+
1344
+ /**
1345
+ * SectionsGroupTemplate -- presents field groups as stacked titled sections
1346
+ * (`x-ui-layout.variant: "sections"`).
1347
+ *
1348
+ * Unlike tabs and stepper, every group is visible at once. This is the
1349
+ * multi-row counterpart to a row's `group` fieldset: a section holds as many
1350
+ * rows as it likes, whereas `row.group` wraps exactly one.
1351
+ *
1352
+ * No selection state, so nothing to clamp -- a group hidden by its rule simply
1353
+ * does not appear.
1354
+ */
1355
+
1356
+ declare function SectionsGroupTemplate({ groups, }: GroupLayoutTemplateProps): React__default.ReactElement;
1357
+
1358
+ /**
1359
+ * GroupErrorBadge -- marks a group's trigger (tab or step) as having
1360
+ * validation errors. Shared by the built-in group templates.
1361
+ *
1362
+ * Deliberately just the icon: a trigger sits in a dense strip alongside its
1363
+ * label and, in a stepper, a step number, so a second numeral reads as clutter
1364
+ * and competes with the step index. The exact count stays available as the
1365
+ * accessible name and the tooltip, and the form-level summary reports totals.
1366
+ *
1367
+ * The signal is a shape, not a colour, so it survives a colour-vision
1368
+ * deficiency or a greyscale print.
1369
+ */
1370
+
1371
+ declare function GroupErrorBadge({ count, }: {
1372
+ count: number;
1373
+ }): React__default.ReactElement | null;
1374
+
1193
1375
  /**
1194
1376
  * Default templates for structural layout rendering.
1195
1377
  *
@@ -1207,5 +1389,12 @@ declare function useNestedFormContext(): NestedFormContextValue;
1207
1389
  * schema property for per-field overrides.
1208
1390
  */
1209
1391
  declare const DEFAULT_TEMPLATES: TemplateRegistry;
1392
+ /**
1393
+ * The TemplateRegistry key for a group-layout variant. The variant name maps
1394
+ * directly to a template name, so a consumer can register
1395
+ * `WizardGroupTemplate` and select it with `variant: "wizard"` -- no library
1396
+ * change needed. Unknown variants fall back to the tab presentation.
1397
+ */
1398
+ declare function groupTemplateKey(variant: string | undefined): string;
1210
1399
 
1211
- export { type ArrayHeaderTemplate, type ArrayHeaderTemplateProps, type ArrayItemTemplate, type ArrayItemTemplateProps, ArrayWidget, CheckboxWidget, DEFAULT_TEMPLATES, DEFAULT_WIDGETS, DEFAULT_WIDGET_MAP, EntitySelectWidget, ExtraPropertiesCard, FormActions, FormCheckbox, FormFieldRenderer, FormFieldWrapper, type FormFieldWrapperProps, FormInput, FormMultiSelect, FormNumberInput, FormQuantityInput, FormSelect, FormTagsInput, FormTextarea, JsonEditorWidget, JsonSchemaFormRenderer, type JsonSchemaFormRendererProps, type NestedFormContextValue, type NestedRenderer, NumberWidget, type ObjectContainerTemplate, type ObjectContainerTemplateProps, ObjectWidget, type QuantityValue, QuantityWidget, type SelectOption, SelectWidget, TagsInputWidget, type TemplateRegistry, TextInputWidget, TextareaWidget, type UnitOption, type UnitPosition, type Widget, type WidgetDescriptor, type WidgetMap, type WidgetProps, type WidgetRegistry, firstError, getAriaDescribedBy, getDefaultWidgetForType, resolveWidget, useFormEngine, useNestedFormContext, useResolvedSchema };
1400
+ export { type ArrayHeaderTemplate, type ArrayHeaderTemplateProps, type ArrayItemTemplate, type ArrayItemTemplateProps, ArrayWidget, CheckboxWidget, DEFAULT_TEMPLATES, DEFAULT_WIDGETS, DEFAULT_WIDGET_MAP, DateTimeWidget, DateWidget, DisplayWidget, EntitySelectWidget, ExtraPropertiesCard, type FieldGroup, FormActions, FormCheckbox, FormFieldRenderer, FormFieldWrapper, type FormFieldWrapperProps, FormInput, FormMultiSelect, FormNumberInput, FormQuantityInput, FormSelect, FormTagsInput, FormTextarea, GroupErrorBadge, type GroupLayoutTemplate, type GroupLayoutTemplateProps, JsonEditorWidget, JsonSchemaFormRenderer, type JsonSchemaFormRendererProps, type NestedFormContextValue, type NestedRenderer, NumberWidget, type ObjectContainerTemplate, type ObjectContainerTemplateProps, ObjectWidget, OneOfWidget, type QuantityValue, QuantityWidget, SectionsGroupTemplate, type SelectOption, SelectWidget, StepperGroupTemplate, TabsGroupTemplate, TagsInputWidget, type TemplateRegistry, TextInputWidget, TextareaWidget, TimeWidget, type UnitOption, type UnitPosition, type Widget, type WidgetDescriptor, type WidgetMap, type WidgetProps, type WidgetRegistry, firstError, getAriaDescribedBy, getDefaultWidgetForType, groupTemplateKey, resolveWidget, useFormEngine, useNestedFormContext, useResolvedSchema };