Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement adding an action to a UITextField #3

Merged
merged 2 commits into from
Jan 27, 2025
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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
# Change Log
All notable changes to this project will be documented in this file.

#### 1.x Releases
- `1.1.x` Releases - [1.1.0](#110)
- `1.0.x` Releases - [1.0.0](#100)

## [1.1.0](https://github.com/space-code/flare/releases/tag/1.1.0)
Released on 2025-01-27.

#### Added
- Implement adding an action to a `UITextField`.
- Added in Pull Request [#3](https://github.com/space-code/flex-ui/pull/3).

## [1.0.0](https://github.com/space-code/flex-ui/releases/tag/1.0.0)
Released on 2025-01-07.

Expand Down
38 changes: 4 additions & 34 deletions Sources/FlexUI/Classes/Extensions/FlexUI+UIButton.swift
Original file line number Diff line number Diff line change
@@ -1,41 +1,11 @@
//
// flex-ui
// Copyright © 2024 Space Code. All rights reserved.
// Copyright © 2025 Space Code. All rights reserved.
//

import UIKit

// MARK: - ButtonCommand

/// A private class that wraps a closure to be executed as an action for a `UIButton`.
/// This class allows associating arbitrary closure actions with buttons, and is used internally
/// to manage custom button actions in the `FlexUI` extension.
private final class ButtonCommand {
// MARK: Properties

/// The closure that will be executed when the button action is triggered.
let block: () -> Void

// MARK: Initialization

/// Initializes a new instance of `ButtonCommand` with the provided closure.
///
/// - Parameter block: The closure to be executed when the button is tapped.
init(block: @escaping () -> Void) {
self.block = block
}

// MARK: Actions

/// The action method that is triggered when the associated button's event occurs.
/// It executes the stored closure.
@objc
func action() {
block()
}
}

@MainActor private let kMapTable = NSMapTable<AnyObject, ButtonCommand>.weakToStrongObjects()
@MainActor private let kMapTable = NSMapTable<AnyObject, Command>.weakToStrongObjects()

/// An extension to `FlexUI` that adds helper methods for configuring `UIButton` properties.
/// These methods allow for fluent configuration of button properties such as title, image, alignment, and actions.
Expand Down Expand Up @@ -251,7 +221,7 @@ public extension FlexUI where Component: UIButton {
return self
}

let buttonCommand = ButtonCommand(block: command)
let buttonCommand = Command(block: command)
component.removeTarget(nil, action: nil, for: event)
component.addTarget(buttonCommand, action: #selector(buttonCommand.action), for: event)
kMapTable.setObject(buttonCommand, forKey: component)
Expand All @@ -271,7 +241,7 @@ public extension FlexUI where Component: UIButton {
return self
}

let buttonCommand = ButtonCommand { [weak component] in
let buttonCommand = Command { [weak component] in
if let component = component {
command(component)
}
Expand Down
53 changes: 52 additions & 1 deletion Sources/FlexUI/Classes/Extensions/FlexUI+UITextField.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//
// flex-ui
// Copyright © 2024 Space Code. All rights reserved.
// Copyright © 2025 Space Code. All rights reserved.
//

import UIKit

@MainActor private let kMapTable = NSMapTable<AnyObject, Command>.weakToStrongObjects()

public extension FlexUI where Component: UITextField {
/// Sets the font of the text field.
///
Expand Down Expand Up @@ -140,4 +142,53 @@ public extension FlexUI where Component: UITextField {
component.adjustsFontSizeToFitWidth = true
return self
}

/// Adds a command to be executed when a specified event occurs on the UIControl component.
/// The method is annotated with `@discardableResult` to allow the return value to be ignored,
/// and `@MainActor` to ensure it runs on the main thread.
///
/// - Parameters:
/// - command: A closure to be executed when the event occurs. Can be `nil`, in which case no action is added.
/// - event: The `UIControl.Event` that triggers the command.
/// - Returns: The instance of `Self` to allow method chaining.
@discardableResult
@MainActor
func add(command: (() -> Void)?, event: UIControl.Event) -> Self {
guard let command = command else {
return self
}

let buttonCommand = Command(block: command)
component.removeTarget(nil, action: nil, for: event)
component.addTarget(buttonCommand, action: #selector(buttonCommand.action), for: event)
kMapTable.setObject(buttonCommand, forKey: component)
return self
}

/// Adds a command to be executed when a specified event occurs on the `UITextField` component.
/// The method is annotated with `@discardableResult` to allow the return value to be ignored,
/// and `@MainActor` to ensure it runs on the main thread.
///
/// - Parameters:
/// - command: A closure that receives the `UITextField` as a parameter when the event occurs. Can be `nil`.
/// - event: The `UIControl.Event` that triggers the command.
/// - Returns: The instance of `Self` to allow method chaining.
@discardableResult
@MainActor
func add(command: ((UITextField) -> Void)?, event: UIControl.Event) -> Self {
guard let command = command else {
return self
}

let buttonCommand = Command { [weak component] in
if let component = component {
command(component)
}
}

component.removeTarget(nil, action: nil, for: event)
component.addTarget(buttonCommand, action: #selector(buttonCommand.action), for: event)
kMapTable.setObject(buttonCommand, forKey: component)
return self
}
}
34 changes: 34 additions & 0 deletions Sources/FlexUI/Classes/Model/Command.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// flex-ui
// Copyright © 2025 Space Code. All rights reserved.
//

import Foundation

/// A private class that wraps a closure to be executed as an action for a `UIControl`.
/// This class allows associating arbitrary closure actions with buttons, and is used internally
/// to manage custom button actions in the `FlexUI` extension.
final class Command {
// MARK: Properties

/// The closure that will be executed when the button action is triggered.
let block: () -> Void

// MARK: Initialization

/// Initializes a new instance of `Command` with the provided closure.
///
/// - Parameter block: The closure to be executed when the button is tapped.
init(block: @escaping () -> Void) {
self.block = block
}

// MARK: Actions

/// The action method that is triggered when the associated button's event occurs.
/// It executes the stored closure.
@objc
func action() {
block()
}
}
Loading