Skip to content
Open
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## [2.3.0]
### ✨ New ✨
- `MacosTextField.selectionColor` sets the color of the selection highlight.

### 🔄 Updated 🔄
- The default selection highlight of `MacosTextField` is an opaque tint of the accent color, close to the one macOS paints behind selected text, instead of the accent at 20% opacity, which was hard to read in the dark appearance.

## [2.2.3]
### 🛠 Fixed 🛠
- Fixed sidebar background painting when wallpaper tinting is disabled: the macOS sidebar now stays transparent unless a decoration color is provided (previously showed a black strip). Addresses #587.
Expand Down
41 changes: 38 additions & 3 deletions lib/src/fields/text_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ class MacosTextField extends StatefulWidget {
this.cursorHeight,
this.cursorRadius = const Radius.circular(2.0),
this.cursorColor,
this.selectionColor,
this.selectionHeightStyle = ui.BoxHeightStyle.tight,
this.selectionWidthStyle = ui.BoxWidthStyle.tight,
this.keyboardAppearance,
Expand Down Expand Up @@ -407,6 +408,7 @@ class MacosTextField extends StatefulWidget {
this.cursorHeight,
this.cursorRadius = const Radius.circular(2.0),
this.cursorColor,
this.selectionColor,
this.selectionHeightStyle = ui.BoxHeightStyle.tight,
this.selectionWidthStyle = ui.BoxWidthStyle.tight,
this.keyboardAppearance,
Expand Down Expand Up @@ -684,6 +686,13 @@ class MacosTextField extends StatefulWidget {
/// and [CupertinoColors.activeOrange] in the dark theme.
final Color? cursorColor;

/// The color of the selection highlight.
///
/// Defaults to an opaque tint of the accent color, close to the one macOS
/// paints behind selected text (`NSColor.selectedTextBackgroundColor`) in the
/// light and in the dark appearance.
final Color? selectionColor;

/// Controls how tall the selection highlight boxes are computed to be.
///
/// See [ui.BoxHeightStyle] for details on available styles.
Expand Down Expand Up @@ -867,6 +876,13 @@ class MacosTextField extends StatefulWidget {
defaultValue: null,
),
);
properties.add(
createCupertinoColorProperty(
'selectionColor',
selectionColor,
defaultValue: null,
),
);
properties.add(
FlagProperty(
'selectionEnabled',
Expand Down Expand Up @@ -1186,6 +1202,18 @@ class _MacosTextFieldState extends State<MacosTextField>
);
}

/// An opaque selection color derived from [accent], like the one macOS
/// paints behind selected text: a light tint of the accent over white in the
/// light appearance, a muted one over gray in the dark appearance. With the
/// blue accent they come out as `#B3D7FF` and about `#3F638B`, the system's
/// own values.
static Color _defaultSelectionColor(Color accent, Brightness brightness) {
final base = brightness.isDark
? const Color(0xFF5A5A5A)
: const Color(0xFFFFFFFF);
return Color.lerp(base, accent.withValues(alpha: 1), 0.3)!;
}

Color? _resolveAccentColor(BuildContext context, AccentColor? accentColor) {
if (accentColor == null) {
return null;
Expand Down Expand Up @@ -1442,9 +1470,16 @@ class _MacosTextFieldState extends State<MacosTextField>
color: focusedDecoration.color ?? const Color(0x00000000),
);

final Color selectionColor = MacosTheme.of(
context,
).primaryColor.withValues(alpha: 0.2);
final Color selectionColor =
MacosDynamicColor.maybeResolve(widget.selectionColor, context) ??
_defaultSelectionColor(
_resolveAccentColor(
context,
AccentColorListener.instance.currentAccentColor,
) ??
themeData.primaryColor,
themeData.brightness,
);

final Widget paddedEditable = Padding(
padding: widget.padding,
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: macos_ui
description: Flutter widgets and themes implementing the current macOS design language.
version: 2.2.3
version: 2.3.0
homepage: "https://macosui.dev"
repository: "https://github.com/GroovinChip/macos_ui"

Expand Down
63 changes: 63 additions & 0 deletions test/fields/text_field_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,67 @@ void main() {
await tester.enterText(textField, input);
expect(controller.text, input);
});
Widget field(TextEditingController controller, {Brightness? brightness}) {
return MacosApp(
theme: MacosThemeData(brightness: brightness ?? Brightness.light),
home: MacosWindow(
child: MacosScaffold(
children: [
ContentArea(
builder: (context, _) {
return Center(
child: SizedBox(
width: 400,
child: MacosTextField(controller: controller),
),
);
},
),
],
),
),
);
}

testWidgets('The default selection color is opaque in both appearances', (
tester,
) async {
final controller = TextEditingController(text: 'Hello');
await tester.pumpWidget(field(controller));
await tester.pump(const Duration(milliseconds: 1));
final light = tester
.widget<EditableText>(find.byType(EditableText))
.selectionColor!;

await tester.pumpWidget(field(controller, brightness: Brightness.dark));
await tester.pump(const Duration(milliseconds: 1));
final dark = tester
.widget<EditableText>(find.byType(EditableText))
.selectionColor!;

expect(light.a, 1.0);
expect(dark.a, 1.0);
expect(dark.computeLuminance(), lessThan(light.computeLuminance()));
});

testWidgets('selectionColor overrides the default', (tester) async {
await tester.pumpWidget(
MacosApp(
home: MacosWindow(
child: MacosScaffold(
children: [
ContentArea(
builder: (context, _) => const Center(
child: MacosTextField(selectionColor: Color(0xFF123456)),
),
),
],
),
),
),
);
await tester.pump(const Duration(milliseconds: 1));
final editable = tester.widget<EditableText>(find.byType(EditableText));
expect(editable.selectionColor, const Color(0xFF123456));
});
}