diff --git a/Sources/TUIkit/Views/RadioButton.swift b/Sources/TUIkit/Views/RadioButton.swift index 01b4962..58e793c 100644 --- a/Sources/TUIkit/Views/RadioButton.swift +++ b/Sources/TUIkit/Views/RadioButton.swift @@ -203,42 +203,34 @@ extension RadioButtonGroupHandler { case .up: // Up/Down only work for vertical orientation guard orientation == .vertical else { return false } - if focusedIndex > 0 { - focusedIndex -= 1 - selection.wrappedValue = itemValues[focusedIndex] - return true - } - return false + // Wrap around: go to last item if at beginning + focusedIndex = focusedIndex > 0 ? focusedIndex - 1 : itemValues.count - 1 + selection.wrappedValue = itemValues[focusedIndex] + return true case .down: // Up/Down only work for vertical orientation guard orientation == .vertical else { return false } - if focusedIndex < itemValues.count - 1 { - focusedIndex += 1 - selection.wrappedValue = itemValues[focusedIndex] - return true - } - return false + // Wrap around: go to first item if at end + focusedIndex = focusedIndex < itemValues.count - 1 ? focusedIndex + 1 : 0 + selection.wrappedValue = itemValues[focusedIndex] + return true case .left: // Left/Right only work for horizontal orientation guard orientation == .horizontal else { return false } - if focusedIndex > 0 { - focusedIndex -= 1 - selection.wrappedValue = itemValues[focusedIndex] - return true - } - return false + // Wrap around: go to last item if at beginning + focusedIndex = focusedIndex > 0 ? focusedIndex - 1 : itemValues.count - 1 + selection.wrappedValue = itemValues[focusedIndex] + return true case .right: // Left/Right only work for horizontal orientation guard orientation == .horizontal else { return false } - if focusedIndex < itemValues.count - 1 { - focusedIndex += 1 - selection.wrappedValue = itemValues[focusedIndex] - return true - } - return false + // Wrap around: go to first item if at end + focusedIndex = focusedIndex < itemValues.count - 1 ? focusedIndex + 1 : 0 + selection.wrappedValue = itemValues[focusedIndex] + return true case .enter, .character(" "): // Select current focused item diff --git a/Tests/TUIkitTests/RadioButtonTests.swift b/Tests/TUIkitTests/RadioButtonTests.swift index 8e95c3b..a7b33b2 100644 --- a/Tests/TUIkitTests/RadioButtonTests.swift +++ b/Tests/TUIkitTests/RadioButtonTests.swift @@ -386,7 +386,7 @@ struct RadioButtonGroupHandlerTests { #expect(selection == AnyHashable("y")) } - @Test("Handler ignores boundary navigation") + @Test("Handler wraps navigation at boundaries") func boundaryNavigation() { var selection = AnyHashable("opt1") let binding = Binding( @@ -403,12 +403,13 @@ struct RadioButtonGroupHandlerTests { canBeFocused: true ) - // Try to go up from first item + // Try to go up from first item — should wrap to last let upEvent = KeyEvent(key: .up) let handled = handler.handleKeyEvent(upEvent) - #expect(handled == false) - #expect(handler.focusedIndex == 0) + #expect(handled == true) + #expect(handler.focusedIndex == 1) // Wrapped to last item + #expect(selection == AnyHashable("opt2")) } @Test("Handler respects canBeFocused property")