Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions packages/remix/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,13 @@
the shared `TextFieldStyler` callable constructs a single-line
`RemixTextField`. Pass a `TextFieldStyler` to `RemixTextArea.style` instead.
- **FIX**: Top-align multiline TextField hints and expose label, hint, helper,
error, and interactive accessory semantics once without narrowing the
existing composite tap target.
error, and interactive accessory semantics once. The composite gesture tap
target is unchanged, but the field's semantic bounds now cover the editable
area rather than the full container box; restoring full-box assistive-tech
bounds needs an upstream naked_ui hook and is tracked there.
- **FIX**: Clear TextField hovered styling when the field is disabled while a
pointer is over it. The hover region unmounts without an exit event, so the
state previously leaked across a disable/re-enable cycle.
- **FEAT**: Add an optional styled `RemixCheckbox.label` inside the checkbox's
pointer, focus, and single semantics target, with a 48-by-48 default minimum
target and an explicit `Size.zero` compact opt-out. Mix now generates the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,13 @@ class _RemixTextFieldBodyState extends State<_RemixTextFieldBody> {
_activePressSources.clear();
_styleController.update(.pressed, false);
}
// Deliberate: the hover MouseRegion is unmounted while disabled and an
// unmounted MouseRegion never fires onExit, so the hovered flag must be
// cleared here. A pointer still over the field re-acquires it on re-enable
// because MouseTracker dispatches enter events to newly mounted regions.
if (!widget.config.enabled) {
_styleController.update(.hovered, false);
}
}

void _updatePressSource(_RemixTextFieldPressSource source, bool pressed) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,53 @@ void main() {
expect(cursorColor(), Colors.blue);
});

testWidgets('disabling while hovered clears hovered styling', (
tester,
) async {
var enabled = true;
late StateSetter rebuild;

await tester.pumpRemixApp(
StatefulBuilder(
builder: (context, setState) {
rebuild = setState;
return RemixTextField(
label: 'Hover target',
enabled: enabled,
style: TextFieldStyler(
cursorColor: Colors.blue,
).onHovered(TextFieldStyler(cursorColor: Colors.red)),
);
},
),
);
await tester.pump();

Color? cursorColor() => tester
.widget<NakedTextField>(find.byType(NakedTextField))
.cursorColor;
final mouse = await tester.createGesture(kind: PointerDeviceKind.mouse);
addTearDown(mouse.removePointer);
await mouse.addPointer(location: Offset.zero);

await mouse.moveTo(tester.getCenter(find.text('Hover target')));
await tester.pump();
expect(cursorColor(), Colors.red);

rebuild(() => enabled = false);
await tester.pump();
await mouse.moveTo(const Offset(700, 500));
await tester.pump();

rebuild(() => enabled = true);
await tester.pump();
expect(cursorColor(), Colors.blue);

await mouse.moveTo(tester.getCenter(find.text('Hover target')));
await tester.pump();
expect(cursorColor(), Colors.red);
});

testWidgets('fallback press down, up, and cancel drive pressed styling', (
tester,
) async {
Expand Down
Loading