@mittwald/flow-react-components 1.5.25 → 1.5.27

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
@@ -426,75 +426,15 @@ Four traps cost time in every new browser test:
426
426
  technology lands on (the input or the group), spread after `rest`: its
427
427
  `aria-describedby` references the error only while one is rendered and already
428
428
  contains the consumer's own ids. See
429
- [Building a form field](#building-a-form-field).
429
+ [FORM_FIELDS.md](https://github.com/mittwald/flow/blob/main/packages/components/FORM_FIELDS.md).
430
430
 
431
431
  ## Building a form field
432
432
 
433
433
  A form field is any component a user enters a value with — anything that calls
434
- `useFieldComponent`. It supports the whole contract below, end to end: prop →
435
- behavior → styling → `Label` state → test. Gaps in existing fields are tracked
436
- in #3368.
437
-
438
- | Aspect | Requirement |
439
- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
440
- | `isDisabled` | Control is not operable (`disabled` or `aria-disabled`), disabled styling via the `formControl` mixin, `Label` disabled. Every inner button too. |
441
- | `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. |
442
- | `isRequired` | `required` or `aria-required` on the control; `Label` drops its "optional" marker (`useFieldComponent` does that). |
443
- | `isInvalid` | `aria-invalid` on the control, invalid styling, `FieldError` rendered and linked. |
444
- | `validationBehavior` | `"native"` blocks form submission on a constraint violation, `"aria"` does not. react-hook-form's `Field` passes `"aria"`. |
445
- | `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`. |
446
- | `name` / `form` | The value is in the `FormData` of the surrounding (or `form`-referenced) form. A custom control renders a hidden input. |
447
- | `defaultValue` / `value` | Both work; `onChange` reports user changes with the field's own value type (a `number` field reports a `number`). |
448
- | `ref` | Points at the focusable control — react-hook-form focuses it on a validation error. |
449
- | `autoFocus`, `onFocus`/`onBlur` | Reach the focusable control. react-hook-form marks a field touched via `onBlur`. |
450
-
451
- An exception needs a reason that holds for the field's nature (a `Slider` always
452
- has a value, so it has no required state) — not "not implemented yet".
453
-
454
- Checklist beyond the component itself:
455
-
456
- - **Contract test.** Call `testFormFieldContract`
457
- (`src/tests/formFieldContract/`) in the field's `*.browser.test.tsx`. The
458
- adapter renders the field, names its control, two values (the first one
459
- submits an entry, the two submit different entries), their `FormData` entries
460
- and a user interaction that changes the value. The interaction passes `force`
461
- on, so the test can also try it on a disabled or read-only field.
462
- `getValueButtons` narrows the inner buttons a read-only field turns off; it
463
- defaults to all. Justified exceptions go in `exceptions` with their reason. An
464
- excepted aspect must fail on one of its own expectations — once it passes, or
465
- fails on a lookup or a timeout instead, the run fails:
466
-
467
- ```tsx
468
- testFormFieldContract("TextField", {
469
- render: (props) => <TextField {...props} />,
470
- getControl: (screen) => screen.getByRole("textbox"),
471
- values: ["foo", "bar"],
472
- toFormValue: (value) => value,
473
- changeValue: async (screen, { force }) => {
474
- await userEvent.fill(screen.getByRole("textbox"), "bar", { force });
475
- },
476
- });
477
- ```
478
-
479
- It checks behavior and ARIA, not looks — the disabled, read-only and invalid
480
- states also get scenarios in the field's visual test
481
- (`packages/remote-react-components/src/tests/visual`).
482
-
483
- - **react-hook-form.** Register the field in the props context of
484
- `src/integrations/react-hook-form/components/Field/Field.tsx`. `Field` passes
485
- `name`, `value` and `defaultValue` together, `onChange`, `onBlur`, `ref`,
486
- `form`, `isRequired`, `isReadOnly`, `isInvalid` and `validationBehavior` —
487
- spread the rest props through instead of destructuring a fixed list, or they
488
- are dropped silently. A field whose value prop is not `value` gets it mapped
489
- there (`selectedKey` for `ComboBox`, `isSelected` for `Checkbox`). `Field`
490
- does not pass `isDisabled` yet (#3368).
491
- - **Remote.** A field that mirrors its value with `useControlledHostValueProps`
492
- passes the type's empty value (see the controlled-from-the-first-render
493
- convention below). A text input among them also needs its `flr-*` tag in
494
- `controlledComponentNames`
495
- (`packages/remote-react-components/src/lib/createRemoteComponent.ts`), or it
496
- drops characters under fast typing
497
- ([docs/remote-ui.md](https://github.com/mittwald/flow/blob/main/docs/remote-ui.md)).
434
+ `useFieldComponent`. Building or changing one → read
435
+ [FORM_FIELDS.md](https://github.com/mittwald/flow/blob/main/packages/components/FORM_FIELDS.md):
436
+ the contract it supports end to end, `testFormFieldContract`, and the
437
+ react-hook-form and remote wiring.
498
438
 
499
439
  ## Every remote binding reads this package
500
440
 
@@ -535,29 +475,12 @@ to make a rule stick.
535
475
 
536
476
  ## Public API surfaces
537
477
 
538
- | Export | Contents |
539
- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
540
- | `.` (default) | Everything listed **manually** in `src/components/public.ts` — new public components must be added there. |
541
- | `./internal` | Advanced internals (`flowComponent`, prop helper types, …). |
542
- | `./flr-universal` | Curated subset that works local _and_ remote. Adding to `public.ts` does **not** add here. |
543
- | `./tunnel` | `@mittwald/react-tunnel` re-exported (`src/index/tunnel.ts`) plus `getTunnelProviderId`, so a consumer's own tunnels share Flow's module instance instead of creating a second React context. |
544
- | `./nextjs`, `./react-hook-form`, `./mittwald-password-tools-js` | Integrations (`src/integrations/`): wrappers around third-party dependencies that not every consumer should pay for — they get their own export entry instead of entering the core surface. |
545
- | `./all.css`, `./all-layered.css` | Bundled stylesheet, plain and `@layer`-wrapped. |
546
- | `./component-index` | Generated consumer-facing index: every public component with its status and its own props (`dev/component-index/`). What the docs site's prop tables read, and the one prop dataset a consumer's agent should use. |
547
- | `./doc-properties` | `react-docgen-typescript` output in its raw `ComponentDoc[]` shape, filtered to the props a consumer can act on. Prefer `./component-index`. The unfiltered dump the generators above read is `.cache/doc-properties.json`, which is not published. |
548
-
549
- **Adding any new export entry?** Add the subpath to `keptSubpaths` in
550
- `packages/codemods/src/migrations/imports-to-package-root/transform.ts`. That
551
- codemod collapses subpath imports onto the package root with a catch-all `else`,
552
- so a subpath that is not listed gets flattened onto a root that does not export
553
- its names. The guard beside the transform fails the codemods unit tests when you
554
- forget.
555
-
556
- **Adding a new integration export entry?** Also register it in the component
557
- status registry so it is covered: add the entry to `STATUS_EXPORT_ENTRIES`
558
- (`dev/status-registry/exportEntries.ts`) — the `FlowExportEntry` union and the
559
- registry regenerate from it. A generation-time guard fails if an entry resolves
560
- to zero components.
478
+ Adding or changing an export entry (`.`, `./internal`, `./flr-universal`, an
479
+ integration, a stylesheet or data entry) → read
480
+ [EXPORTS.md](https://github.com/mittwald/flow/blob/main/packages/components/EXPORTS.md):
481
+ what each entry holds and the registries a new one has to join.
482
+
483
+ ## Prop JSDoc
561
484
 
562
485
  Prop JSDoc feeds the generated `doc-properties.json` and the docs site: write
563
486
  doc comments on public props, use `@default` for defaults and `@internal` for