From ef59898e794541404e3fe99fb148781345c4aedf Mon Sep 17 00:00:00 2001
From: Nikita Vasilev <nv3212@gmail.com>
Date: Mon, 27 Jan 2025 17:11:25 +0100
Subject: [PATCH 1/2] Implement adding an action to a `UITextField`

---
 .../Classes/Extensions/FlexUI+UIButton.swift  | 38 ++-----------
 .../Extensions/FlexUI+UITextField.swift       | 53 ++++++++++++++++++-
 Sources/FlexUI/Classes/Model/Command.swift    | 34 ++++++++++++
 3 files changed, 90 insertions(+), 35 deletions(-)
 create mode 100644 Sources/FlexUI/Classes/Model/Command.swift

diff --git a/Sources/FlexUI/Classes/Extensions/FlexUI+UIButton.swift b/Sources/FlexUI/Classes/Extensions/FlexUI+UIButton.swift
index 71f11ae..a2013cf 100644
--- a/Sources/FlexUI/Classes/Extensions/FlexUI+UIButton.swift
+++ b/Sources/FlexUI/Classes/Extensions/FlexUI+UIButton.swift
@@ -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.
@@ -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)
@@ -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)
             }
diff --git a/Sources/FlexUI/Classes/Extensions/FlexUI+UITextField.swift b/Sources/FlexUI/Classes/Extensions/FlexUI+UITextField.swift
index acc54c1..bdb612d 100644
--- a/Sources/FlexUI/Classes/Extensions/FlexUI+UITextField.swift
+++ b/Sources/FlexUI/Classes/Extensions/FlexUI+UITextField.swift
@@ -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.
     ///
@@ -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
+    }
 }
diff --git a/Sources/FlexUI/Classes/Model/Command.swift b/Sources/FlexUI/Classes/Model/Command.swift
new file mode 100644
index 0000000..19ff61f
--- /dev/null
+++ b/Sources/FlexUI/Classes/Model/Command.swift
@@ -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()
+    }
+}

From 4e3df9d8dde3b7adad332c118db71998f3dae16c Mon Sep 17 00:00:00 2001
From: Nikita Vasilev <nv3212@gmail.com>
Date: Mon, 27 Jan 2025 17:16:05 +0100
Subject: [PATCH 2/2] Update `CHANGELOG.md`

---
 CHANGELOG.md | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index f4eca9f..e350ec9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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.