@mittwald/flow-react-components 1.2.0-next.2 → 1.2.0-next.4

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/MIGRATION.md CHANGED
@@ -99,8 +99,16 @@ tracked the selection both go away.
99
99
  ```
100
100
 
101
101
  **Setting a value.** The selection feeds a form or a setting. Use a
102
- `RadioGroup`: each `Segment` becomes a `Radio`, everything else — `Label`,
103
- `FieldDescription`, `FieldError`, the React Hook Form binding — stays as it is.
102
+ `RadioGroup`: each `Segment` becomes a `RadioButton`, everything else — `Label`,
103
+ `FieldDescription`, `FieldError`, `value`/`defaultValue`/`onChange`, the React
104
+ Hook Form binding — stays as it is.
105
+
106
+ This direction is a rename, not a restructure. The types line up:
107
+ `SegmentedControlProps` and `RadioGroupProps` both extend
108
+ `Omit<Aria.RadioGroupProps, "children">`, and `SegmentProps` and
109
+ `RadioButtonProps` are the same type (`RadioButtonProps` is declared as
110
+ `RadioProps`, which is identical to `SegmentProps`). Only
111
+ `containerBreakpointSize` has no counterpart — see the note at the end.
104
112
 
105
113
  ```diff
106
114
  - <SegmentedControl defaultValue="debit">
@@ -108,15 +116,56 @@ tracked the selection both go away.
108
116
  <Label>Zahlungsart</Label>
109
117
  - <Segment value="debit">Lastschrift</Segment>
110
118
  - <Segment value="invoice">Rechnung</Segment>
111
- + <Radio value="debit">Lastschrift</Radio>
112
- + <Radio value="invoice">Rechnung</Radio>
119
+ + <RadioButton value="debit">Lastschrift</RadioButton>
120
+ + <RadioButton value="invoice">Rechnung</RadioButton>
113
121
  <FieldDescription>Jederzeit änderbar</FieldDescription>
114
122
  - </SegmentedControl>
115
123
  + </RadioGroup>
116
124
  ```
117
125
 
118
- There is no codemod. Both replacements change the structure, and picking the
119
- right one is a decision per usage, not a rename.
126
+ **Always `RadioButton`, not `Radio`.** A `RadioGroup` also accepts a plain
127
+ `Radio`, and it takes the same props, so both would compile — but `RadioButton`
128
+ is the replacement for a `Segment`. The appearance still changes: `RadioButton`
129
+ does not reproduce the segmented control's joined row, which came from
130
+ `Segment`'s own `flex: 1` and collapsed borders. See the
131
+ [RadioGroup docs](https://flow.mittwald.de/components/form-controls/radio-group).
132
+
133
+ #### Three things the Tabs direction changes
134
+
135
+ **The controlled-state props are named differently.** `SegmentedControl` takes
136
+ `value` / `defaultValue` / `onChange` (it is a radio group); `Tabs` takes
137
+ `selectedKey` / `defaultSelectedKey` / `onSelectionChange`. Nothing carries over
138
+ by name here, unlike the `RadioGroup` direction.
139
+
140
+ **The group `Label`.** `SegmentedControl` is a form field — it wraps
141
+ react-aria's `RadioGroup` — so a `<Label>` inside it is a field label. `Tabs`
142
+ has no equivalent slot, and a tab list labels itself through its tab titles. The
143
+ `Label` therefore cannot move into `Tabs`, but its text has somewhere to go:
144
+
145
+ - into the surrounding `Section`'s `Heading`, when the group wants a visible
146
+ title
147
+ - into `aria-label` on `Tabs`, when it does not — that names the tab list for
148
+ screen readers without showing the name
149
+ - nowhere, when the surrounding heading already names the group
150
+
151
+ A `Label` on its own is **not** a signal that the usage was a `RadioGroup` case
152
+ — plenty of content switchers were authored with one, because the component
153
+ required a field label.
154
+
155
+ **Panels that register form fields.** Moving the switched-in content into a
156
+ `Tab` does not change when it mounts. `Tab` renders its panel with
157
+ `shouldForceMount` and wraps `Content` and `Section` in
158
+ `<Activity isActive={…}>`, so every tab's subtree is mounted and keeps its state
159
+ — an inactive tab is hidden, not unmounted. React Hook Form fields inside a tab
160
+ stay registered across a tab switch, exactly as they did as siblings below a
161
+ `SegmentedControl`.
162
+
163
+ There is no codemod, and the reason is the choice rather than the edit. Which
164
+ replacement is right cannot be decided from the source: a value-setting usage
165
+ and a content switcher look alike at the call site, and only the surrounding
166
+ intention separates them. The `RadioGroup` direction would be mechanical **once
167
+ that decision is made** — if you have many usages that all go that way, a
168
+ find-and-replace of `SegmentedControl`/`Segment` gets you most of it.
120
169
 
121
170
  `SegmentedControl` and `Segment` (and the `flr-segmented-control` /
122
171
  `flr-segment` remote elements) keep working unchanged and will be removed in a
@@ -128,8 +177,18 @@ their own when the available width runs out, and a `RadioGroup` stacks its
128
177
  options anyway.
129
178
 
130
179
  **Apply:** Replace `SegmentedControl` with `Tabs` when the selection switches
131
- displayed content, or with `RadioGroup` when it sets a value. Pick per usage
132
- this is a structural change, not a rename.
180
+ displayed content, or with `RadioGroup` when it sets a value. Pick per usage.
181
+ The two directions cost very different amounts of work. Towards `RadioGroup` it
182
+ is a prop-compatible rename: `SegmentedControl` → `RadioGroup` and `Segment` →
183
+ `RadioButton` (always `RadioButton`, not `Radio`; it takes exactly `Segment`'s
184
+ props), with `value`/`defaultValue`/`onChange` and a `Label` child all carrying
185
+ over. Only `containerBreakpointSize` has no counterpart, and the joined row is
186
+ not reproduced. Towards `Tabs` it is structural: the state props are
187
+ `selectedKey`/`defaultSelectedKey` rather than `value`/`defaultValue`, there is
188
+ no `Label` slot (the group label moves to the surrounding `Heading`, or to
189
+ `aria-label` on `Tabs` when it should not be visible, or goes away), and the
190
+ switched panels move inside the tabs — where they stay mounted, so form fields
191
+ in them keep their registration.
133
192
 
134
193
  ---
135
194