Skip to content
This repository was archived by the owner on Feb 10, 2026. It is now read-only.
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
41 changes: 39 additions & 2 deletions example/lib/src/storybook/stories/primitives/radio.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class _RadioStoryState extends State<RadioStory> {
Widget build(BuildContext context) {
final activeColorKnob = context.knobs.nullable.options(
label: "activeColor",
description: "MoonColors variants for selected MoonRadio.",
description: "MoonColors variants for selected MoonRadio background.",
enabled: false,
initial: 0,
// piccolo
Expand All @@ -37,7 +37,7 @@ class _RadioStoryState extends State<RadioStory> {

final inactiveColorKnob = context.knobs.nullable.options(
label: "inactiveColor",
description: "MoonColors variants for unselected MoonRadio.",
description: "MoonColors variants for unselected MoonRadio background.",
enabled: false,
initial: 0,
// piccolo
Expand All @@ -46,6 +46,40 @@ class _RadioStoryState extends State<RadioStory> {

final inactiveColor = colorTable(context)[inactiveColorKnob ?? 40];

final activeBorderColorKnob = context.knobs.nullable.options(
label: "activeBorderColor",
description: "MoonColors variants for selected MoonRadio border.",
enabled: false,
initial: 0,
// piccolo
options: colorOptions,
);

final activeBorderColor = colorTable(context)[activeBorderColorKnob ?? 40];

final inactiveBorderColorKnob = context.knobs.nullable.options(
label: "inactiveBorderColor",
description: "MoonColors variants for unselected MoonRadio border.",
enabled: false,
initial: 0,
// piccolo
options: colorOptions,
);

final inactiveBorderColor =
colorTable(context)[inactiveBorderColorKnob ?? 40];

final indicatorColorKnob = context.knobs.nullable.options(
label: "indicatorColor",
description: "MoonColors variants for selected MoonRadio indicator.",
enabled: false,
initial: 0,
// piccolo
options: colorOptions,
);

final indicatorColor = colorTable(context)[indicatorColorKnob ?? 40];

final isToggleableKnob = context.knobs.boolean(
label: "toggleable",
description: "Whether selected MoonRadio can be unselected.",
Expand All @@ -72,6 +106,9 @@ class _RadioStoryState extends State<RadioStory> {
groupValue: valueCustom,
activeColor: activeColor,
inactiveColor: inactiveColor,
activeBorderColor: activeBorderColor,
inactiveBorderColor: inactiveBorderColor,
indicatorColor: indicatorColor,
toggleable: isToggleableKnob,
onChanged: isDisabledKnob
? null
Expand Down
50 changes: 43 additions & 7 deletions lib/src/widgets/radio/radio.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,21 @@ class MoonRadio<T> extends StatefulWidget {
/// unselected.
final bool toggleable;

/// The color of the active (selected) radio button.
/// The background color of the active (selected) radio button.
final Color? activeColor;

/// The background color of the inactive (unselected) radio button.
final Color? inactiveColor;

/// The border color of the active (selected) radio button.
final Color? activeBorderColor;

/// The border color of the inactive (unselected) radio button.
final Color? inactiveBorderColor;

/// The indicator color of the active (selected) radio button.
final Color? indicatorColor;

/// The size of the radio button tap target.
///
/// Defaults to 40.
Expand Down Expand Up @@ -80,6 +89,9 @@ class MoonRadio<T> extends StatefulWidget {
this.toggleable = false,
this.activeColor,
this.inactiveColor,
this.activeBorderColor,
this.inactiveBorderColor,
this.indicatorColor,
this.tapAreaSizeValue = 40,
this.focusNode,
this.semanticLabel,
Expand Down Expand Up @@ -111,8 +123,8 @@ class _RadioState<T> extends State<MoonRadio<T>> {

@override
Widget build(BuildContext context) {
const double sizeValue = 16;
const double dotSizeValue = (sizeValue - 1) / 2;
const double sizeValue = 20;
const double dotSizeValue = 8;

final MoonFocusEffect focusEffect =
MoonEffectsTheme(tokens: MoonTokens.light).controlFocusEffect;
Expand All @@ -121,7 +133,23 @@ class _RadioState<T> extends State<MoonRadio<T>> {
widget.activeColor ?? MoonColors.light.piccolo;

final Color effectiveInactiveColor =
widget.inactiveColor ?? MoonColors.light.trunks;
widget.inactiveColor ?? const Color.fromRGBO(252, 252, 253, 1);

final Color effectiveActiveBorderColor =
widget.activeBorderColor ?? effectiveActiveColor;

final Color effectiveInactiveBorderColor =
widget.inactiveBorderColor ?? const Color.fromRGBO(205, 206, 214, 1);

final Color effectiveIndicatorColor =
widget.indicatorColor ?? const Color.fromRGBO(252, 252, 253, 1);

const Color hoverColor = Color.fromRGBO(28, 32, 36, 0.08);

final effectiveHoverColor = Color.alphaBlend(
hoverColor,
_selected ? effectiveActiveColor : effectiveInactiveColor,
);

final Color effectiveFocusEffectColor = focusEffect.effectColor;

Expand All @@ -138,18 +166,26 @@ class _RadioState<T> extends State<MoonRadio<T>> {
$box.chain
..width(_selected ? dotSizeValue : 0)
..height(_selected ? dotSizeValue : 0)
..color(effectiveActiveColor)
..color(_selected ? effectiveIndicatorColor : effectiveInactiveColor)
..shape.circle(),
).animate(duration: effectiveFocusEffectDuration);

final Style baseStyle = Style(
$box.chain
..height(sizeValue)
..width(sizeValue)
..border
.color(_selected ? effectiveActiveColor : effectiveInactiveColor)
..color(_selected ? effectiveActiveColor : effectiveInactiveColor)
..border(
width: 2,
color: _selected
? effectiveActiveBorderColor
: effectiveInactiveBorderColor,
)
..alignment.center()
..shape.circle(),
$on.hover(
$box.color(effectiveHoverColor),
),
).animate(duration: effectiveFocusEffectDuration);

final Style effectsStyle = Style(
Expand Down