@mittwald/flow-react-components 1.5.0-next.42 → 1.5.0-next.43
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/AGENTS.md
CHANGED
|
@@ -400,7 +400,76 @@ Four traps cost time in every new browser test:
|
|
|
400
400
|
`wrapperProps` go on the outer element, `controlProps` on what assistive
|
|
401
401
|
technology lands on (the input or the group), spread after `rest`: its
|
|
402
402
|
`aria-describedby` references the error only while one is rendered and already
|
|
403
|
-
contains the consumer's own ids.
|
|
403
|
+
contains the consumer's own ids. See
|
|
404
|
+
[Building a form field](#building-a-form-field).
|
|
405
|
+
|
|
406
|
+
## Building a form field
|
|
407
|
+
|
|
408
|
+
A form field is any component a user enters a value with — anything that calls
|
|
409
|
+
`useFieldComponent`. It supports the whole contract below, end to end: prop →
|
|
410
|
+
behavior → styling → `Label` state → test. Gaps in existing fields are tracked
|
|
411
|
+
in #3368.
|
|
412
|
+
|
|
413
|
+
| Aspect | Requirement |
|
|
414
|
+
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
415
|
+
| `isDisabled` | Control is not operable (`disabled` or `aria-disabled`), disabled styling via the `formControl` mixin, `Label` disabled. Every inner button too. |
|
|
416
|
+
| `isReadOnly` | Value cannot change, control still focusable and submitted. Native `readonly` / react-aria's `isReadOnly` where it exists, otherwise `aria-readonly` — never by disabling the control. Inner buttons that change the value off. |
|
|
417
|
+
| `isRequired` | `required` or `aria-required` on the control; `Label` drops its "optional" marker (`useFieldComponent` does that). |
|
|
418
|
+
| `isInvalid` | `aria-invalid` on the control, invalid styling, `FieldError` rendered and linked. |
|
|
419
|
+
| `validationBehavior` | `"native"` blocks form submission on a constraint violation, `"aria"` does not. react-hook-form's `Field` passes `"aria"`. |
|
|
420
|
+
| `Label` / `FieldDescription` | Children slots via `useFieldComponent`; `Label` names the control. `controlProps` (with `aria-describedby`) land on the **focusable control** (or the group of a grouped control), not on a wrapper `div`. |
|
|
421
|
+
| `name` / `form` | The value is in the `FormData` of the surrounding (or `form`-referenced) form. A custom control renders a hidden input. |
|
|
422
|
+
| `defaultValue` / `value` | Both work; `onChange` reports user changes with the field's own value type (a `number` field reports a `number`). |
|
|
423
|
+
| `ref` | Points at the focusable control — react-hook-form focuses it on a validation error. |
|
|
424
|
+
| `autoFocus`, `onFocus`/`onBlur` | Reach the focusable control. react-hook-form marks a field touched via `onBlur`. |
|
|
425
|
+
|
|
426
|
+
An exception needs a reason that holds for the field's nature (a `Slider` always
|
|
427
|
+
has a value, so it has no required state) — not "not implemented yet".
|
|
428
|
+
|
|
429
|
+
Checklist beyond the component itself:
|
|
430
|
+
|
|
431
|
+
- **Contract test.** Call `testFormFieldContract`
|
|
432
|
+
(`src/tests/formFieldContract/`) in the field's `*.browser.test.tsx`. The
|
|
433
|
+
adapter renders the field, names its control, two values (the first one
|
|
434
|
+
submits an entry, the two submit different entries), their `FormData` entries
|
|
435
|
+
and a user interaction that changes the value. The interaction passes `force`
|
|
436
|
+
on, so the test can also try it on a disabled or read-only field.
|
|
437
|
+
`getValueButtons` narrows the inner buttons a read-only field turns off; it
|
|
438
|
+
defaults to all. Justified exceptions go in `exceptions` with their reason. An
|
|
439
|
+
excepted aspect must fail on one of its own expectations — once it passes, or
|
|
440
|
+
fails on a lookup or a timeout instead, the run fails:
|
|
441
|
+
|
|
442
|
+
```tsx
|
|
443
|
+
testFormFieldContract("TextField", {
|
|
444
|
+
render: (props) => <TextField {...props} />,
|
|
445
|
+
getControl: (screen) => screen.getByRole("textbox"),
|
|
446
|
+
values: ["foo", "bar"],
|
|
447
|
+
toFormValue: (value) => value,
|
|
448
|
+
changeValue: async (screen, { force }) => {
|
|
449
|
+
await userEvent.fill(screen.getByRole("textbox"), "bar", { force });
|
|
450
|
+
},
|
|
451
|
+
});
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
It checks behavior and ARIA, not looks — the disabled, read-only and invalid
|
|
455
|
+
states also get scenarios in the field's visual test
|
|
456
|
+
(`packages/remote-react-components/src/tests/visual`).
|
|
457
|
+
|
|
458
|
+
- **react-hook-form.** Register the field in the props context of
|
|
459
|
+
`src/integrations/react-hook-form/components/Field/Field.tsx`. `Field` passes
|
|
460
|
+
`name`, `value` and `defaultValue` together, `onChange`, `onBlur`, `ref`,
|
|
461
|
+
`form`, `isRequired`, `isReadOnly`, `isInvalid` and `validationBehavior` —
|
|
462
|
+
spread the rest props through instead of destructuring a fixed list, or they
|
|
463
|
+
are dropped silently. A field whose value prop is not `value` gets it mapped
|
|
464
|
+
there (`selectedKey` for `ComboBox`, `isSelected` for `Checkbox`). `Field`
|
|
465
|
+
does not pass `isDisabled` yet (#3368).
|
|
466
|
+
- **Remote.** A field that mirrors its value with `useControlledHostValueProps`
|
|
467
|
+
passes the type's empty value (see the controlled-from-the-first-render
|
|
468
|
+
convention below). A text input among them also needs its `flr-*` tag in
|
|
469
|
+
`controlledComponentNames`
|
|
470
|
+
(`packages/remote-react-components/src/lib/createRemoteComponent.ts`), or it
|
|
471
|
+
drops characters under fast typing
|
|
472
|
+
([docs/remote-ui.md](https://github.com/mittwald/flow/blob/main/docs/remote-ui.md)).
|
|
404
473
|
|
|
405
474
|
## Public API surfaces
|
|
406
475
|
|