extended-dynamic-forms 0.3.13 → 0.4.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 (43) hide show
  1. package/README.md +580 -25
  2. package/dist/WizardForm.d.ts +17 -2
  3. package/dist/components/FieldFeedbackContext.d.ts +4 -0
  4. package/dist/components/FieldStyleContext.d.ts +7 -0
  5. package/dist/components/SchemaSelectionContext.d.ts +20 -0
  6. package/dist/components/URLBlurValidationContext.d.ts +38 -0
  7. package/dist/components/fields/TextChangeScope.d.ts +28 -0
  8. package/dist/components/fields/TextEmptyArrayField.d.ts +3 -0
  9. package/dist/conditionals/v2/createConditionalEngineHook.d.ts +3 -1
  10. package/dist/conditionals/v2/index.d.ts +2 -1
  11. package/dist/conditionals/v2/types.d.ts +13 -0
  12. package/dist/conditionals/v2/utils/stepRules.d.ts +35 -0
  13. package/dist/events/FormEventContext.d.ts +3 -0
  14. package/dist/index.es.js +41796 -32825
  15. package/dist/index.umd.js +1618 -1606
  16. package/dist/layouts/wizard/WizardLayout.d.ts +1 -0
  17. package/dist/style.css +1 -1
  18. package/dist/utils/normalizeUrlValue.d.ts +3 -0
  19. package/dist/utils/urlValue.d.ts +12 -0
  20. package/dist/widgets/base/URLParts.d.ts +5 -0
  21. package/dist/widgets/base/URLPreviewLink.d.ts +5 -0
  22. package/dist/widgets/base/inputStyles.d.ts +4 -0
  23. package/dist/widgets/base/inputTypography.d.ts +3 -0
  24. package/dist/widgets/base/numberInputStyles.d.ts +4 -0
  25. package/dist/widgets/base/telephoneAddons.d.ts +3 -0
  26. package/dist/widgets/base/types.d.ts +15 -1
  27. package/dist/widgets/base/useInputChrome.d.ts +5 -0
  28. package/dist/widgets/base/utils.d.ts +9 -1
  29. package/dist/widgets/choice/ChoiceWidget.types.d.ts +2 -0
  30. package/dist/widgets/choice/dropdownValidation.d.ts +8 -0
  31. package/dist/widgets/choice/inlineChoiceValidation.d.ts +5 -0
  32. package/dist/widgets/choice/presenters/InlineChoiceGroup.d.ts +888 -0
  33. package/dist/widgets/date/DateTimeWidget.d.ts +2 -21
  34. package/dist/widgets/date/calendarConstraints.d.ts +5 -0
  35. package/dist/widgets/date/dateRangeValue.d.ts +20 -0
  36. package/dist/widgets/date/dateTimeValue.d.ts +15 -0
  37. package/dist/widgets/file/FileUploadWidget.d.ts +3 -32
  38. package/dist/widgets/index.d.ts +6 -6
  39. package/dist/widgets/input/TelephoneWidget.d.ts +1 -1
  40. package/dist/widgets/input/emailValidation.d.ts +7 -0
  41. package/dist/widgets/input/telephoneMask.d.ts +7 -0
  42. package/dist/widgets/input/telephoneOptions.d.ts +14 -0
  43. package/package.json +9 -3
package/README.md CHANGED
@@ -7,12 +7,11 @@ Conditional logic is configured with pure JSON via `x-edf:rules` in your `schema
7
7
  ## Project Status
8
8
 
9
9
  **Important Notes:**
10
- - Requires RJSF source in sibling directory for development
11
- - Cannot be installed from npm due to local file dependencies
10
+ - Source development uses the pinned RJSF packages in `yarn.lock`; no sibling checkout is needed.
11
+ - Source package version is `0.4.0`; a checkout or local tarball is not proof of registry publication.
12
12
  - JSON logic conditions don't work with vanilla JavaScript builds
13
13
  - Array drag-and-drop is not implemented
14
- - Automated coverage is provided by logic and snapshot suites; component/UI tests
15
- are intentionally omitted
14
+ - Automated coverage includes logic/snapshot suites and real jsdom wizard component regressions.
16
15
  - JSON Patch implementation supports add/remove/replace only (not move/copy/test)
17
16
 
18
17
  ## Overview
@@ -33,35 +32,290 @@ All custom widgets built on Ant Design components forward their props via `ui:op
33
32
  - JSON-only flags: `disablePastDates`, `disableFutureDates`, `disableWeekends` (builds `disabledDate` internally)
34
33
  - Range support: set `ui:options.range: true` to render AntD `RangePicker` (see examples below)
35
34
 
35
+ ### Text Input clear (BUGS-S0-R020, 0.4.0)
36
+
37
+ This correction, including fixes added after the earlier !6 artifact, is part of
38
+ 0.4.0 release preparation. Publication and Formstudio adoption remain separate gates.
39
+
40
+ Clearing the built-in `text` / `TextWidget` now emits `undefined` by default.
41
+ Object properties, including properties inside array items, are omitted when
42
+ serialized as JSON. Undefined-valued own properties may still exist in callbacks.
43
+ Required fields and invalid nonempty formats remain invalid; clearing an optional
44
+ formatted Text Input no longer creates an invalid empty string.
45
+
46
+ Defined `emptyValue` options remain explicit overrides, including `""`, `null`
47
+ and other sentinels. They must satisfy the consumer's schema: an explicit empty
48
+ string still fails an email format. Wizard blank-string normalization is retained
49
+ unless a positive string `minLength`, a valid explicit `maxLength` (including
50
+ zero), or an explicit string `pattern` (including the empty regex) constrains
51
+ that property. See [Wizard explicit string minimums](#wizard-explicit-string-minimums),
52
+ [Wizard supplied pattern strings](#wizard-supplied-pattern-strings), and
53
+ [Wizard explicit string maximums](#wizard-explicit-string-maximums).
54
+ An unconstrained widget's legacy empty string is not a promise of a
55
+ final Wizard empty-string submission.
56
+
57
+ Stored/default answers are not rewritten on load. Array positions and row
58
+ identity are preserved; this is not a primitive-array deletion or compaction
59
+ policy. The array-item integration forwards built-in TextWidget property clears
60
+ as leaf paths, so batched sibling updates use current form state rather than a
61
+ render-time object snapshot. It delegates host `ArraySchemaField`/`SchemaField`
62
+ components and retains array row keys. Consumer-supplied fields/widgets remain
63
+ authoritative; an overridden `ArrayField` owns its child-change policy.
64
+ Password, Textarea and other widget empty defaults are unchanged.
65
+ Traversal uses RJSF's effective schema-type resolver after reference resolution,
66
+ including supported nullable array/object containers. Untouched explicit nulls
67
+ are preserved; this is not global null normalization.
68
+ Field authority is resolved before TextWidget eligibility at the leaf and each
69
+ ancestor: normalized UI/global field options take precedence, then registered
70
+ schema `$id`, then the type's registry field. Unknown UI field names fall through
71
+ as in RJSF. A custom field selected by schema ID retains the same ordinary array
72
+ handling as that field selected by `ui:field`; it does not inherit TextWidget's
73
+ omission policy.
74
+ Host item/schema renderers that replace TextWidget retain ordinary array
75
+ undefined-to-null handling. Delegating renderers retain omission for the actual
76
+ TextWidget they render, including public relative-path changes and batched host
77
+ controls. The adapter checks committed field-scoped rendering and the public
78
+ callback's target path, not widget IDs or schema metadata alone; replacement,
79
+ unmount and row moves withdraw obsolete rendering authority.
80
+
81
+ ### 0.4.0 adoption and migration
82
+
83
+ `0.4.0` intentionally changes the Date, Time, DateTime and calendar Date Range
84
+ serialization contracts described below. Treat this pre-1.0 minor release as a
85
+ contract boundary, not a transparent patch to `0.3.13`. Consumers using `^0.3.x`
86
+ do not receive `0.4.x` automatically.
87
+
88
+ External/native integrators must explicitly adopt `0.4.x`, update their dependency
89
+ lockfile, and check callback handlers, schema validation and submission storage
90
+ against the relevant contract. Date/Time schemas without their respective
91
+ `format` retain their documented native formatted-output exception. Calendar
92
+ ranges use ISO dates even with plain string items; explicit `showTime` / `withTime`
93
+ ranges retain their time-bearing contract. DateTime uses the UTC-instant contract
94
+ for both Ant Design and native inputs, not a configurable floating-time mode.
95
+
96
+ Do not automatically rewrite persisted or in-progress responses during an
97
+ upgrade. Restore supported values without load-time change callbacks; legacy
98
+ values that fail the applicable schema/instant contract require respondent
99
+ re-entry rather than a guessed timezone or bulk normalization. Pending invalid
100
+ edit callbacks are not accepted submissions. Existing non-production Formstudio
101
+ forms need no migration infrastructure; this does not authorize changing external
102
+ stored data.
103
+
104
+ Formstudio adoption is a separate step **after published registry proof** of the
105
+ new SDK. Pair the reviewed producer changes with the exact released dependency
106
+ and lockfile, then verify the resolved package in the consumer. Local packed
107
+ integration alone does not establish publication, authenticated hosted/managed
108
+ behavior or deployed adoption. Never replace registry `0.3.13` with these bytes.
109
+
110
+ Release preparation covers the declared ESM and browser UMD bundles, CSS and
111
+ ESNext/Bundler declarations. The existing CommonJS/NodeNext packaging limitations
112
+ and the separate vanilla build's missing entry are not repaired by this release.
113
+
114
+ Only the browser UMD output resolves `process.env.NODE_ENV` to production at build
115
+ time; script-tag hosts do not need a Node `process` shim. ESM retains its
116
+ environment checks so consumers control development diagnostics and production
117
+ behavior. The normal UMD peer globals remain required: `React`, `ReactDOM`,
118
+ `React.jsxRuntime`, `antd` and `dayjs`.
119
+
120
+ ### Single Date Picker values (ON-41, 0.4.0)
121
+
122
+ For `ui:widget: "date"` with a scalar `schema.format: "date"`, selection emits
123
+ `YYYY-MM-DD` to form data and field-change events. `ui:options.format` controls
124
+ display only: `DD/MM/YYYY` displays `23/10/2026` but submits `2026-10-23`.
125
+ The value is a calendar day, not a UTC timestamp; no timezone conversion is used.
126
+ Clearing still emits the configured `emptyValue`.
127
+
128
+ This intentionally corrects the previous, schema-invalid formatted output in
129
+ `0.4.0`; it does not replace published `0.3.13`.
130
+ Native string schemas without `format: "date"` retain their formatted output.
131
+ Existing ISO dates and legacy values matching the configured string format are
132
+ readable, including day-first dates. Loading does not rewrite stored answers:
133
+ a legacy non-ISO answer still fails a date schema until the respondent selects
134
+ a valid date. Impossible ISO dates are not rolled into a different calendar day.
135
+ Consumers upgrading date-schema forms must expect canonical values in callbacks
136
+ and submissions; do not rewrite saved/in-progress responses as an upgrade side effect.
137
+
138
+ This change covers the single Date Picker only, not Time, DateTime or Date Range.
139
+
140
+ ### Time Picker values (BUGS-S0-R272, 0.4.0)
141
+
142
+ For `ui:widget: "time"` with `schema.format: "time"`, selection emits
143
+ `HH:mm:ss` wall-clock values to form data, callbacks and submissions.
144
+ `ui:options.format` controls display: `hh:mm A` displays `02:35 PM` while
145
+ the value is `14:35:00`. No `Z`, offset or timezone conversion is added.
146
+ Clearing retains the configured `emptyValue`.
147
+
148
+ Canonical values and legacy strings matching the configured format are parsed
149
+ strictly. Invalid values are not displayed as `Invalid Date` or rolled into a
150
+ different time. Reading does not call `onChange` or rewrite saved answers:
151
+ schema-invalid legacy values still require reselection before valid submission.
152
+ The readonly native input shows the same clock time.
153
+
154
+ Native string schemas without `format: "time"` retain configured-format output
155
+ and prefer that format when reading ambiguous values. This approved time-schema
156
+ contract correction requires explicit `0.4.x` consumer adoption; do not replace
157
+ registry `0.3.13` or migrate saved/in-progress responses implicitly.
158
+ It does not change DateTime or Date Range behavior.
159
+
160
+ ### DateTime values (BUGS-S0-R273, 0.4.0)
161
+
162
+ DateTime (`datetime`, `datetime-local`, `DateTimeWidget`, or the default
163
+ `format: "date-time"` widget) captures and displays the respondent's **browser-local
164
+ wall clock**. Every newly accepted selection emits a UTC ISO timestamp with `Z`,
165
+ for example `2024-11-03T05:30:00.000Z`. `ui:options.format` controls presentation
166
+ only. Ant Design, native `useNativeInput`, readonly display, plain forms and
167
+ wizard validation share this instant contract. There is no form timezone setting.
168
+
169
+ The widget rejects a nonexistent local time during a daylight-saving gap. For a
170
+ repeated local time it requires an explicit **First occurrence** or **Second
171
+ occurrence**, labelled with the corresponding UTC offset, before accepting an
172
+ instant. A restored UTC/offset-bearing instant already identifies its occurrence;
173
+ loading it does not call `onChange`, normalize storage or ask the respondent to
174
+ choose again. Different browser timezones may display different calendar dates
175
+ for the same instant.
176
+
177
+ Valid restored fractional seconds may exceed three digits (for example `.1230Z`
178
+ or `.123456789Z`). The original string is preserved on load and unchanged
179
+ submission; millisecond-resolution controls do not rewrite stored precision.
180
+ New respondent edits emit the standard ISO millisecond precision shown above.
181
+
182
+ Invalid or zone-less saved strings require re-entry; their timezone is never
183
+ guessed. Pending/invalid edits invalidate the previous form value and block submit
184
+ and wizard progression, even on optional fields. During such an edit, change
185
+ callbacks can contain the non-instant `Invalid date-time` marker and validation
186
+ errors; do not persist it as an accepted answer. Only a valid, completed selection
187
+ emits an instant. Clearing emits `undefined` (omitted in JSON), regardless of old
188
+ DateTime `emptyValue` options; required clear remains invalid. Other widgets'
189
+ empty sentinels and Date/Time/Range semantics are unchanged.
190
+ Wizard `onLiveChange` publishes the same deletion-aware flat snapshot used
191
+ internally: clearing removes the answer while retaining sibling and other-step
192
+ data. Validation also covers positional tuple entries and additional items using
193
+ their corresponding schema references and item UI schema, including explicit
194
+ native DateTime widgets whose string schema has no `format`.
195
+ The supported `ui:field` aliases obey the same contract and forward widget errors.
196
+ For `oneOf`/`anyOf`, validation follows RJSF's active schema and corresponding
197
+ branch UI, retaining explicit choices when branches match equally. Inactive text
198
+ branches are not treated as DateTime. Wizard final submission validates every
199
+ visible step with its own UI and retained branch choice, including earlier steps
200
+ newly revealed by a final-step answer.
201
+ Returning to a wizard step restores its actual rendered selector and nested/ref
202
+ branch UI, not only a validation hint. Navigation preserves answers and emits no
203
+ answer-change callback merely to restore a choice. Choices are scoped by step and
204
+ nested branch; authored discriminators still determine matching when data differs.
205
+ In arrays, choices follow RJSF's stable row identities through removal and both
206
+ reorder directions, including equal-valued and nested rows. Removed-row choices
207
+ are retired; added rows use normal matching/defaults. Answer/error paths remain
208
+ positional, with no IDs added to responses. Registry and per-field
209
+ `ArrayFieldTemplate` / `ArrayFieldItemTemplate` overrides retain their rendering
210
+ and public row actions; identity tracking neither replays nor replaces callbacks.
211
+
212
+ `disablePastDates`, `disableFutureDates`, `disableWeekends` and explicit date bounds
213
+ compare browser-local calendar labels, not the UTC instant of a picker container.
214
+ Picker selection, typed/native input and restored-answer validation agree.
215
+ An explicit `disabledDate` callback takes precedence over convenience flags;
216
+ bounds still apply. Callback calendar/clock fields are preserved, using a
217
+ fixed-offset carrier for a skipped local date or clock rather than shifting it.
218
+
219
+ This is the approved **clean DateTime cutover**, not an opt-in or floating-time
220
+ mode. Existing non-production Formstudio forms need no migration infrastructure.
221
+ External consumers must explicitly adopt `0.4.x` and account for the changed
222
+ DateTime callbacks/submissions; never replace published `0.3.13` with these
223
+ contents or rewrite external stored answers on load.
224
+
225
+ ### Calendar Date Range values (BUGS-S0-R274, 0.4.0)
226
+
227
+ `ui:widget: "date"` with `ui:options.range: true` reuses Ant Design's
228
+ `RangePicker`, including RJSF array dispatch. Calendar endpoints are always
229
+ `[YYYY-MM-DD, YYYY-MM-DD]`, even for native SDK schemas whose items are plain
230
+ strings. `format` controls display/input only. Dates are calendar days, not
231
+ instants: there is no UTC conversion or timezone shifting. Readonly mode displays
232
+ both endpoints using native date inputs.
233
+
234
+ Impossible dates, reversed pairs and incomplete pairs are rejected in plain forms
235
+ and wizard progression. Invalid typed drafts invalidate the answer rather than
236
+ submitting a previous valid pair; do not persist change callbacks as accepted
237
+ submissions without validation. Typed/restored dates also obey picker constraints.
238
+ Loading valid ISO data does not rewrite it or emit a change callback.
239
+ Character-by-character endpoint edits retain their text and caret through parent
240
+ updates while each partial draft still reaches change callbacks and validation.
241
+ A genuine external answer replacement replaces the draft without replaying it.
242
+ Explicit Clear discards both endpoint texts, including a partial draft entered
243
+ into an already-empty range, and emits `[]` without replaying the discarded draft.
244
+ Fresh typing starts from blank inputs; optional `[]` remains valid and required
245
+ `[]` remains invalid.
246
+ The same guards apply to the registered `date` / `DateWidget` field aliases
247
+ (`ui:field` takes precedence over `ui:widget`) and the actually selected referenced
248
+ `oneOf` / `anyOf` branch. Inactive text branches remain text, including through
249
+ Wizard Back/final validation and stable array-row changes.
250
+
251
+ Past/future restrictions compare calendar-day keys with the respondent's **local
252
+ today**, not UTC-midnight containers with local-midnight instants. Picker cells,
253
+ typed/restored validation and wizard progression use the same internal calendar
254
+ constraint adapter as DateTime. Native min/max bounds retain their displayed
255
+ calendar days; an explicit `disabledDate` callback still takes precedence over
256
+ JSON flags, independently of those bounds. Its date and `info.from` preserve
257
+ calendar and clock fields in local mode where representable; a locally skipped
258
+ day or clock uses a separate fixed-offset carrier without mutating the picker's
259
+ input. Range-only options and explicit with-time behavior remain unchanged.
260
+ This does not repair the separate pre-existing full-form UI-option normalization
261
+ of native Dayjs instances.
262
+
263
+ Calendar clear emits `[]`: optional answers may submit it; required answers may
264
+ not. An optional array schema must permit zero or two items (for example,
265
+ `minItems: 0`, `maxItems: 2`, `not: { minItems: 1, maxItems: 1 }`).
266
+ Explicit `allowEmpty: [true, false]` preserves `["", "YYYY-MM-DD"]`; only the
267
+ allowed endpoint may be empty, and populated endpoints remain ISO. Native schema
268
+ constraints still apply: `items.format: "date"` does not permit `""`; use matching
269
+ tuple item schemas if an empty endpoint is intentional.
270
+
271
+ Explicit `showTime` / `withTime` ranges remain outside this calendar cutover:
272
+ they retain their existing formatted string pair and time information. No UTC
273
+ DateTime policy is applied to them. Single Date, Time and DateTime are unchanged.
274
+
275
+ This explicitly approved non-production cutover supersedes the old configured
276
+ string calendar output; it is not a migration or compatibility mode. External
277
+ native consumers must explicitly adopt `0.4.x` with this contract. Do not replace
278
+ published `0.3.13`. Formstudio's reviewed producer change must be paired with
279
+ the new SDK only after registry publication is proved; an older installed package
280
+ or a local packed fixture is not proof of released consumer adoption.
281
+
36
282
  ## Installation
37
283
 
38
- **Note:** This library currently requires local development setup and cannot be installed via npm due to local file dependencies.
284
+ For this source checkout, use the maintained Yarn lockfile. The older npm lockfile
285
+ still contains local RJSF references and is not a reproducible install for this tree.
39
286
 
40
287
  ```bash
41
- # Clone RJSF as sibling directory (required)
42
- cd ..
43
- git clone https://github.com/rjsf-team/react-jsonschema-form.git
44
-
45
- # Setup Extended Dynamic Forms
46
- cd extended-dynamic-forms
47
- npm install
48
- npm run dev
288
+ yarn install --frozen-lockfile
289
+ npm run build
49
290
  ```
50
291
 
51
- **Important:** The library is currently designed for internal use or as part of a monorepo setup. Standalone npm package distribution is not yet supported.
292
+ For local consumer verification, run `npm pack --ignore-scripts` after building and
293
+ install the resulting `extended-dynamic-forms-0.4.0.tgz` in an isolated consumer.
294
+ The root version fields in the legacy npm lockfile match `0.4.0`; its stale
295
+ dependency graph is deliberately unchanged and must not be used for this install.
296
+ Package preparation does not authorize publication. See the adoption boundary
297
+ above and the existing packaging limitations below.
52
298
 
53
299
  ## Testing
54
300
 
55
- The project uses Vitest with **Node** environment to cover pure logic and serialized
56
- outputs. Component or DOM-level tests are intentionally excluded.
301
+ Vitest defaults to the **Node** environment for logic and serialized-output tests.
302
+ `tests/integration/WizardForm.regression.test.tsx` opts into **jsdom** and mounts
303
+ the real wizard, renderer, widgets, validator and Ant Design components.
57
304
 
58
- - Run the full suite: `npm test`
59
- - Logic-only focus: `npm test -- tests/logic`
60
- - Snapshot updates: `npm test -- tests/snapshots -- -u`
305
+ - Full suite: `npm test -- --run`
306
+ - Wizard and step-rule regressions: `npm test -- --run tests/integration/WizardForm.regression.test.tsx tests/logic/conditionals/stepRules.test.ts`
307
+ - Date selection, display/value round-trip and plain/wizard validation: `npm test -- --run tests/integration/DatePicker.regression.test.tsx`
308
+ - Time selection, canonical/native values, strict parsing and required plain/wizard submission: `npm test -- --run tests/integration/TimePicker.regression.test.tsx`
309
+ - Logic-only focus: `npm test -- --run tests/logic`
310
+ - Real Chromium Text status/color and host-CSS regressions: `npm run test:browser`. This opt-in suite builds and packs the current SDK, builds an isolated public consumer and asserts rendered colors, token/neutral transitions, authored plain/addon-affix backgrounds and submission behavior; it is separate from the default Node/jsdom suite.
61
311
 
62
- After pulling dependencies or updating `package.json`, run `npm install` (or
63
- `yarn install`) so the lockfile reflects removed packages such as
64
- `@testing-library/*` and `jsdom`.
312
+ The browser suite needs Chromium/Chrome (`CHROME_BIN` overrides discovery), `npm` and `tar`.
313
+ It creates a fresh profile and consumer under `TMPDIR` and closes/removes only its own runtime.
314
+ Set `EDF_BROWSER_ARTIFACT_DIR` to retain genuine PNG, DOM/raw observations and package/resource identities outside the temporary runtime.
315
+
316
+ The plain-form array comparisons use `noHtml5Validate` so JSON Schema, rather
317
+ than native HTML `required` attributes on array-item inputs, determines whether
318
+ empty strings are valid.
65
319
 
66
320
  ## Core Architecture
67
321
 
@@ -163,6 +417,108 @@ Note on wizard detection:
163
417
  - With a single `STEP_…` property, the form renders as a single-page form (no progress/navigation UI).
164
418
  - To display steps UI, define at least two step objects (e.g., `STEP_PERSONAL`, `STEP_REVIEW`).
165
419
 
420
+ ### Completion and array-value guarantees
421
+
422
+ - The final visible step can submit without a following step. Submission
423
+ validates every visible step snapshot against its step schema before calling
424
+ `onSubmit`; a newly revealed invalid earlier step is activated for completion.
425
+ - A trailing step skipped by `x-edf:stepRules` does not disable completion.
426
+ Hidden steps are excluded from structured `formData` unless
427
+ `includeHiddenStepsInSubmit` is enabled; `flatFormData` retains its existing
428
+ all-step value context.
429
+ - A root skip rule on a single-page form renders the no-visible-steps state,
430
+ not inputs with a submit action that cannot complete.
431
+ - Public `WizardLayout`/`StepNavigation` omit hidden steps from navigation and
432
+ progress while retaining original step indices in `onStepChange`.
433
+ - Supplied step data is available on the first render. Empty-string and whitespace
434
+ array entries, nested arrays and array positions survive editing, step
435
+ navigation, `onLiveChange`, and both structured and flat submission data.
436
+ - Flat initial answers are assigned to their schema-owned step snapshots, so
437
+ untouched answers appear in structured submission as well as `flatFormData`.
438
+ Supplied flat values reach validation unchanged, including composed constraints.
439
+ Explicit nested `STEP_*` snapshots retain precedence; editing or clearing an
440
+ answer does not restore its initial value.
441
+ - For nested snapshots and respondent edits, blank-string normalization outside
442
+ arrays remains in place when no string `pattern`, positive `minLength`, or
443
+ valid explicit `maxLength` applies. Explicit constraints follow the contracts below.
444
+ Array contents are not compacted or normalized by the wizard.
445
+
446
+ ### Wizard explicit string minimums
447
+
448
+ 0.4.0 R139 correction: a string property with an explicit positive
449
+ `minLength` retains supplied empty and whitespace-only strings for validation.
450
+ An optional absent property remains optional, but an explicit `""` cannot bypass
451
+ the minimum by being removed from the step snapshot. This applies on initial
452
+ load, editing/clearing, Next, and final submission.
453
+
454
+ Length counts the original characters, not digits or trimmed text. Nonempty
455
+ Phone values and sibling callback data are not normalized by this correction.
456
+ Blank normalization without a pattern, positive minimum, or valid explicit maximum,
457
+ date empty defaults, and array positions remain unchanged.
458
+
459
+ This correction is included in 0.4.0, not registry `0.3.13`.
460
+ Publication and Formstudio adoption remain separate gates.
461
+
462
+ ### Wizard supplied pattern strings
463
+
464
+ 0.4.0 R138 correction: a string property with an explicit string `pattern`
465
+ retains every supplied string unchanged for AJV validation, including `""` and
466
+ whitespace-only strings. Nonmatching blanks block Next and final submission;
467
+ matching blanks remain intact in live changes and both structured and flat
468
+ submission data. This applies to restored values and editing/clearing, not only
469
+ Phone fields. Native `pattern: ""` is an explicit regex matching all strings;
470
+ an omitted pattern is distinct.
471
+
472
+ An actually absent optional property remains absent. This does not add
473
+ requiredness or a minimum, trim values, change widget clear defaults, or alter
474
+ the positive-minimum contract above. A widget emitting absence is not treated
475
+ as supplying an empty string.
476
+
477
+ This correction is included in 0.4.0, not registry `0.3.13`.
478
+ Publication and Formstudio adoption remain separate gates.
479
+
480
+ ### Wizard explicit string maximums
481
+
482
+ 0.4.0 R140 correction: a string property with a valid explicit nonnegative
483
+ integer `maxLength` retains supplied strings unchanged for AJV validation,
484
+ including empty and whitespace-only values. Eleven spaces under `maxLength: 10`
485
+ and one space under `maxLength: 0` block Next and final submission, just as in a
486
+ plain form. Permitted blanks and clears remain intact in live changes and both
487
+ structured and flat submission data, including after back navigation.
488
+
489
+ This deliberately changes required-plus-maximum blanks: JSON Schema `required`
490
+ checks presence, so a supplied matching `""` or whitespace value is present
491
+ rather than normalized to absence. Plain schema validation already accepts it.
492
+ A genuinely missing required property still rejects. Use a positive `minLength`
493
+ to reject empty strings, or an appropriate `pattern` to reject whitespace;
494
+ neither content rule is added implicitly. Native HTML validation is separate.
495
+
496
+ An absent optional property stays optional; an undefined value is not converted
497
+ to a supplied string. This does not trim values, count only digits, change widget
498
+ clear defaults, or change unconstrained/zero-minimum-only blank normalization.
499
+ Array positions remain unchanged.
500
+
501
+ This correction is included in 0.4.0, not registry `0.3.13`.
502
+ Publication and Formstudio adoption remain separate gates.
503
+
504
+ ### Wizard configuration errors
505
+
506
+ In multi-step mode, invalid schema configuration (for example, a malformed
507
+ `pattern`) blocks Next or Submit and shows the validator's root error by default.
508
+ This does not change pattern matching or remove the malformed constraint.
509
+ Ordinary answer-validation errors remain field-local by default.
510
+
511
+ An explicit `showErrorList={false}` opts out of the root error list without
512
+ allowing invalid progression; `showErrorList={true}` enables the list. Custom
513
+ `templates.ErrorListTemplate` renders this feedback as it does other RJSF errors.
514
+ Configuration feedback tracks schema-only edits on the same mounted Wizard,
515
+ including when answers do not change. Correcting the schema clears configuration
516
+ feedback and restores navigation without discarding current values or replaying
517
+ answer-change callbacks. Initial and final step guards use the current validation
518
+ result; the error list does not replace those guards.
519
+
520
+
521
+
166
522
  ### Step Layouts with LayoutGridField
167
523
 
168
524
  Wizard steps can define their own grid layout using a custom object field (e.g., `LayoutGridField`). Place the layout at the step key in `uiSchema` and pass your custom field via `fields` to `WizardForm`.
@@ -324,6 +680,41 @@ Common patterns for migrating from function-based conditions:
324
680
  - **TextareaWidget** - Multi-line text input
325
681
  - **PasswordWidget** - Password input with visibility toggle
326
682
 
683
+ With the SDK's default `FieldTemplate`, Text, Email, URL and Password
684
+ `ui:options.style` overrides the selected input's theme presentation.
685
+ For example: `{ "ui:widget": "text", "ui:options": { "style": { "color": "#b4141e", "fontSize": 18 } } }`.
686
+ Updating or removing this style does not change answers; styles stay scoped to
687
+ that field, including nested fields. `ui:style` and `ui:options.formItem.style`
688
+ remain container styling. A custom widget's explicit `options.style` takes
689
+ precedence, and a host replacing `FieldTemplate` retains control of its styling.
690
+ With addons, the complete style still reaches Ant Design's outer `Input.style`
691
+ surface. Only explicit control presentation is additionally applied to the
692
+ editable control: text color/font/spacing/alignment/decoration/caret, background
693
+ paint, padding, and border color/style/width/radius (including physical/logical
694
+ padding and border sides). Inputs with icons, prefix/suffix, clear or count use
695
+ the affix control so inner padding is not applied twice.
696
+ Other properties retain native outer ownership rather than being copied onto a
697
+ second surface: sizing, margins, positioning/insets, transforms, layout/alignment
698
+ and compositional effects are not duplicated. No properties are removed from
699
+ the original `Input.style`; this rule also applies to explicit host
700
+ `options.style`. Without addons, native control styling is unchanged.
701
+
702
+ `PasswordWidget` uses the same field-scoped style and control-presentation rules,
703
+ including its masked and revealed states. The default template supplies a style
704
+ only for the matching field ID when the widget has no explicit `options.style`.
705
+ An explicit host style wins as a complete object, including `{}`; parent/object
706
+ styles do not become a nested password's control style. The password eye, clear,
707
+ count, prefix and addons retain their native Ant Design behavior. Numeric zero
708
+ values and the original style declaration order are preserved when presentation
709
+ properties are mirrored onto the control. Style changes do not replace answers
710
+ or synthesize change/submission callbacks.
711
+ Recovered field typography also reaches the editable input inside an affix
712
+ wrapper, so its own theme font does not override the author's font. Host
713
+ semantic input properties remain unless the field overrides that property.
714
+ Email uses the same borderless status-background fallback as Text; explicit
715
+ backgrounds, disabled controls and host CSS retain their existing precedence.
716
+
717
+
327
718
  #### Specialized Input Widgets
328
719
  - **ColorWidget** - Color picker using HTML5 color input
329
720
  - **EmailWidget** - Email input with validation
@@ -331,6 +722,87 @@ Common patterns for migrating from function-based conditions:
331
722
  - **TelephoneWidget** - Phone number input
332
723
  - **NumberWidget** - Numeric input with increment/decrement controls
333
724
 
725
+ URLWidget honors an active `ui:options.type` on its existing native input
726
+ (for example, `text` or `url`), independently of `inputMode`. TextWidget
727
+ honors that override only on the existing URL route, identified by
728
+ `ui:options.inputType: 'url'`. Other TextWidget routes, including utility
729
+ Email/Phone and direct Text, retain their published native Text behavior.
730
+ Omitted, `undefined`, `null` and empty-string types preserve each route's
731
+ existing default: URL for URLWidget, Text for TextWidget. The `inputType`
732
+ marker alone never supplies a native type.
733
+
734
+ Changing HTML type can change native browser validity; it does not change
735
+ schema type, URI format, pattern, Required, answers or callbacks. Explicit
736
+ schema URL constraints still apply with HTML Text. Formstudio's URL author
737
+ choices remain Text/URL. URL acceptance uses HTTP/HTTPS by default, independently
738
+ of the HTML type and `validateUrl`. To allow extra schemes, set
739
+ `ui:options.allowedProtocols`, for example `['http://', 'https://', 'mailto']`.
740
+ Scheme names are case-insensitive and accept bare names, `:` or `://` suffixes.
741
+ An explicit list replaces the defaults, and `[]` rejects every nonempty URL.
742
+ `javascript:`, `data:` and `vbscript:` are always blocked, even when listed.
743
+ Optional empty answers still follow the schema's existing validation.
744
+ This applies to ExtendedForm submission, Wizard progression/final submission and
745
+ the TextWidget URL route. Raw answers are not migrated or rewritten.
746
+ After adopting this SDK change, existing forms with no protocol list reject
747
+ non-HTTP(S) answers. Authors must explicitly allow other safe schemes before
748
+ those answers are accepted. Link preview remains restricted to HTTP/HTTPS.
749
+
750
+ With the default `FieldTemplate`, ordinary `tel`/`telephone` fields recover
751
+ `ui:options.style` for that field's Phone control. Changing, clearing or restoring
752
+ the style leaves the current answer and sibling fields unchanged. A custom
753
+ widget's explicit native `options.style`, including `{}`, takes precedence;
754
+ recovery requires a matching field ID, so a host-replaced child template cannot
755
+ borrow an ancestor's style.
756
+
757
+ For recovered Phone styles with addons, control presentation (text, background,
758
+ padding and borders) also reaches the editable input or affix control through
759
+ Ant Design's supported semantic styles. Layout and effects retain native outer
760
+ `Input.style` ownership. Explicit native styles are not rewritten or mirrored.
761
+ Intentional outer `Form.Item` presentation remains separate; outer and control
762
+ borders/padding are not a single combined-border contract.
763
+
764
+ Recovered Phone typography also reaches the editable input inside an affix
765
+ wrapper, where Ant Design otherwise applies its own font rule. This includes
766
+ the existing Phone-via-Text route (`inputType: 'tel'`), without changing its
767
+ native Text input type or unrelated Text behavior. Host input semantic styles
768
+ remain unless the selected field overrides the same typography property.
769
+ Padding, borders and background remain on the visible control rather than
770
+ being duplicated onto its inner input. Explicit native `options.style` and
771
+ intentional outer styling retain their existing ownership.
772
+
773
+ Exact inside Before/After placement preserves distinct prefix/suffix content
774
+ and stable wrappers through clear; omitted/outside/unsupported markers retain
775
+ the native outside slot. These placement options do not enter phone answers.
776
+ Phone `ui:options.mask` uses `9` for a digit, `a` for an ASCII letter and `*`
777
+ for any character. Other characters are display literals. For example,
778
+ `+1 (999) 999-9999` displays `+1 (202) 555-0123` and emits `+12025550123`.
779
+ A national mask uses the configured country code. An international mask includes
780
+ its own calling-code digits. Explicit foreign numbers are preserved rather than
781
+ silently changed to a fixed mask country.
782
+
783
+ Letter slots are display-only (no phoneword conversion). They survive the current
784
+ edit but are absent from saved answers and cannot be reconstructed on reload.
785
+ Only `+` and digit content enter answers, events and validation. Masked answers
786
+ use E.164 syntax plus the existing configured phone constraints. Empty optional
787
+ answers retain existing empty-value behaviour. Display separators do not spend
788
+ the canonical length budget. Backspace/Delete cross inserted literals.
789
+
790
+ A non-empty mask with slots takes precedence over native formatter/parser
791
+ callbacks and international grouping. Clearing the mask restores those existing
792
+ paths. Invalid/non-string masks without slots are ignored. The default keyboard
793
+ hint remains `tel`. Loading a saved answer does not rewrite stored data.
794
+
795
+ Phone country entries accept an optional `pattern` in the same mask grammar.
796
+ Set `ui:options.useCountryMasks: true` to use the selected/detected country's
797
+ pattern as a fallback. False or unset keeps existing behaviour, including stored
798
+ country names/codes and answers. An explicit field `mask` always takes priority.
799
+ For example, `countries: [{ code: '+44', name: 'UK', pattern: '+44 99 9999 9999' }]`
800
+ formats `+442079460018` as `+44 20 7946 0018`. Countries also accept JSON text.
801
+ Missing/non-string patterns or patterns without slots keep the unmasked route.
802
+ No regex or exact-length validation is inferred from a country display pattern.
803
+ Existing canonical-phone feedback and explicit schema constraints still apply.
804
+ Disabling the opt-in restores the prior display path without migrating answers.
805
+
334
806
  #### Visual Input Widgets
335
807
  - **RangeWidget** / **SliderWidget** - Slider for numeric ranges
336
808
  - **RatingWidget** - Star rating component
@@ -381,7 +853,7 @@ Common patterns for migrating from function-based conditions:
381
853
  "schema": {
382
854
  "type": "array",
383
855
  "title": "Date Range",
384
- "items": { "type": "string" },
856
+ "items": { "type": "string", "format": "date" },
385
857
  "minItems": 2,
386
858
  "maxItems": 2
387
859
  },
@@ -456,6 +928,89 @@ Month range:
456
928
  }
457
929
  ```
458
930
 
931
+ #### Number grouping (BUGS-S0-R202, 0.4.0)
932
+
933
+ The default `number` / `updown` NumberWidget supports an explicitly configured
934
+ ordinary single-character `ui:options.groupSeparator`. For example:
935
+
936
+ ```json
937
+ {
938
+ "ui:widget": "updown",
939
+ "ui:options": {
940
+ "groupSeparator": "_",
941
+ "precision": 2,
942
+ "decimalSeparator": "."
943
+ }
944
+ }
945
+ ```
946
+
947
+ `1234567.89` displays as `1_234_567.89`; editing `7_654_321.25` emits the
948
+ number `7654321.25`, not formatted text. Grouping affects the integer part only.
949
+ Native precision, step-derived precision and decimal normalization delegate to
950
+ the declared public `@rc-component/mini-decimal` API used by Ant's numeric input;
951
+ EDF does not replace that arithmetic or rewrite restored answers on render.
952
+ Partial user typing is retained until native blur/step normalization.
953
+
954
+ Absent, undefined or empty-string group options retain inactive native behavior.
955
+ An active (truthy) native formatter or parser retains its existing path, as does
956
+ an explicitly provided input `type`. Empty formatter/parser strings are inactive,
957
+ matching native hooks; they do not disable literal grouping. This option neither
958
+ overrides active hooks nor executes serialized JavaScript. Multi-character
959
+ groups, numeric/sign/exponent/decimal-token ambiguity and broader locale or
960
+ StringMode policies are not established here; those inputs retain native behavior
961
+ rather than removing numeric characters. Custom fields/widgets remain host-owned.
962
+
963
+ This correction is included in 0.4.0 release preparation.
964
+ Publication and downstream adoption remain separate gates; do not republish
965
+ different contents under an existing published version.
966
+
967
+ #### Numeric controls and exact decimal values
968
+
969
+ Number, Currency and Percentage presentations use the same `number` / `updown`
970
+ widget. `ui:options.min` / `max` clamp input on blur; `step` controls increments.
971
+ Schema `minimum`, `maximum`, `multipleOf` and numeric draft-7
972
+ `exclusiveMinimum` / `exclusiveMaximum` independently validate submissions.
973
+ `controls`, `keyboard` and `changeOnWheel` independently enable their respective
974
+ input interactions; wheel changes require focus.
975
+
976
+ Native integrations can preserve exact decimal strings with a **string schema**
977
+ and `stringMode`, for example:
978
+
979
+ ```json
980
+ {
981
+ "schema": {
982
+ "type": "string",
983
+ "title": "Exact decimal",
984
+ "pattern": "^-?[0-9]+(?:\\.[0-9]+)?(?![\\s\\S])"
985
+ },
986
+ "uiSchema": {
987
+ "ui:widget": "updown",
988
+ "ui:options": { "stringMode": true }
989
+ }
990
+ }
991
+ ```
992
+
993
+ This preserves values such as `"9007199254740993.123456789123456789"` as strings
994
+ through editing and submission. It is not a numeric-schema migration:
995
+ RJSF's numeric field converts values to JavaScript numbers, which can lose
996
+ precision even with `stringMode`. JSON Schema numeric constraints do not validate
997
+ strings; hosts choosing string responses must supply decimal-aware validation.
998
+ Do not change existing numeric schemas or drop their constraints implicitly.
999
+
1000
+ Native callable `formatter` / `parser` hooks remain supported. JavaScript source
1001
+ text in JSON is not a callable hook, and EDF does not evaluate it. Formstudio's
1002
+ author-entered formatter/parser execution requires separate approval.
1003
+
1004
+ Formstudio String Mode exports this string schema for Number, Currency and
1005
+ Percentage. Fields without String Mode retain numeric schemas. Existing answers
1006
+ are not migrated. Clearing String Mode emits an absent value unless `emptyValue`
1007
+ is explicitly configured, so optional decimal fields remain submittable.
1008
+ Numeric schema bounds and multiples do not validate strings.
1009
+ UI min/max, step and explicitly configured precision still apply in the widget.
1010
+ String Mode preserves decimal precision, while the numeric input normalises
1011
+ spelling such as leading/trailing zeroes. The generated pattern accepts signed
1012
+ plain decimals and rejects exponent notation, grouping, affixes and whitespace.
1013
+
459
1014
  #### Rating Widget
460
1015
  ```json
461
1016
  {
@@ -712,8 +1267,8 @@ Run `npm run dev` to explore examples.
712
1267
 
713
1268
  ## Known Limitations
714
1269
 
715
- 1. **Dependencies**: Requires RJSF source in sibling directory
716
- 2. **Installation**: Cannot install from npm
1270
+ 1. **Dependency installation**: The legacy npm lockfile is stale; use `yarn.lock` for this checkout.
1271
+ 2. **CommonJS packaging**: `require` resolves to `.umd.js` inside a `"type": "module"` package; a Node consumer returned no named SDK exports. ESM imports work. This pre-existing packaging defect is not repaired by the wizard fixes.
717
1272
  3. **Vanilla JS**: JsonLogic not supported in standalone builds
718
1273
  4. **Arrays**: No drag-and-drop functionality
719
1274
  5. **JSON Patch**: Only supports add/remove/replace operations