Skip to content

Commit

Permalink
impl validation for input form
Browse files Browse the repository at this point in the history
  • Loading branch information
RyosukeCla committed Dec 20, 2023
1 parent e59c6f5 commit 8a38f01
Showing 1 changed file with 126 additions and 1 deletion.
127 changes: 126 additions & 1 deletion ios/Nativebrik/Nativebrik/forms.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,106 @@
import Foundation
import UIKit
import YogaKit
import TipKit

class TooltipViewController: UIViewController, UIPopoverPresentationControllerDelegate {
var message: String? = ""
init(message: String, source: UIView) {
super.init(nibName: nil, bundle: nil)
self.message = message
self.preferredContentSize = CGSize(width: 400, height: 32)
self.modalPresentationStyle = .popover
self.popoverPresentationController?.sourceView = source
self.popoverPresentationController?.delegate = self
self.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection([.down, .up])
}

required init?(coder: NSCoder) {
super.init(coder: coder)
}

override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .init(white: 0, alpha: 0)
let label = UILabel(frame: CGRect(x: 16, y: 16, width: 280 - 32, height: 16))
label.lineBreakMode = .byWordWrapping;
label.numberOfLines = 0;
label.text = self.message
label.font = .systemFont(ofSize: 16, weight: .semibold)
self.view.addSubview(label)

let labelHeight = label.intrinsicContentSize.height
label.frame.size.height = labelHeight
self.preferredContentSize = CGSize(width: 400, height: 32 + labelHeight)
}

// UIPopoverPresentationControllerDelegate
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return .none
}
}

class InputIconView: UIControl {
required init?(coder: NSCoder) {
super.init(coder: coder)
}
init(systemName: String, message: String?, color: UIColor?, size: Int?, padding: Int?) {
super.init(frame: .zero)
let size = size ?? 16
let paddingRight = padding ?? 0
let paddingLeft = padding ?? 4

self.configureLayout { layout in
layout.isEnabled = true
layout.paddingLeft = .init(integerLiteral: paddingLeft)
layout.paddingRight = .init(integerLiteral: paddingRight)
layout.height = .init(value: 100, unit: .percent)
layout.width = .init(integerLiteral: paddingLeft + paddingRight + size)
layout.alignItems = .center
layout.justifyContent = .center
}

let iconView = UIImageView(image: UIImage(systemName: systemName))
iconView.configureLayout { layout in
layout.isEnabled = true
layout.width = .init(integerLiteral: size)
layout.height = .init(integerLiteral: size)
}
iconView.sizeToFit()
if let color = color {
iconView.tintColor = color
}

if #available(iOS 14.0, *), let message = message {
self.addAction(.init { _ in
if #available(iOS 17.0, *) {
let tooltip = TooltipViewController(message: message, source: iconView)
self.window?.rootViewController?.present(tooltip, animated: true)
}
}, for: .touchDown)
}

self.addSubview(iconView)
}

deinit {
if self.window?.rootViewController?.presentedViewController is TooltipViewController {
self.window?.rootViewController?.dismiss(animated: true)
}
}

override func layoutSubviews() {
super.layoutSubviews()
self.yoga.applyLayout(preservingOrigin: true)
}
}

class TextInputView: UIView, UITextFieldDelegate {
var textInput: UITextField? = nil
var validateRegex: String? = nil
var fontSize: Int? = nil
var paddingRight: Int? = nil
var errorMessage: UITooltipMessage? = nil

required init?(coder: NSCoder) {
super.init(coder: coder)
Expand All @@ -19,6 +116,11 @@ class TextInputView: UIView, UITextFieldDelegate {
init(block: UITextInputBlock) {
super.init(frame: .zero)

self.fontSize = block.data?.size
self.paddingRight = block.data?.frame?.paddingRight
self.errorMessage = block.data?.errorMessage
self.validateRegex = block.data?.regex

// wrap layout
self.configureLayout { layout in
layout.isEnabled = true
Expand All @@ -38,8 +140,8 @@ class TextInputView: UIView, UITextFieldDelegate {
// input layout
let textInput = UITextField()
self.textInput = textInput
textInput.addTarget(self, action: #selector(onEditingChanged(sender: )), for: .editingChanged)
textInput.textAlignment = parseTextAlign(block.data?.textAlign)

textInput.inputAccessoryView = toolbar
textInput.delegate = self
textInput.configureLayout { layout in
Expand All @@ -55,12 +157,14 @@ class TextInputView: UIView, UITextFieldDelegate {
textInput.rightView = UIView(frame: CGRect(x: 0, y: 0, width: paddingRight, height: 0))
textInput.rightViewMode = .always
}

if let color = block.data?.color {
textInput.textColor = parseColor(color)
} else {
textInput.textColor = .label
}
textInput.font = parseTextBlockDataToUIFont(block.data?.size, block.data?.weight, block.data?.design)
self.fontSize = block.data?.size
if let placeholder = block.data?.placeholder {
textInput.placeholder = placeholder
}
Expand All @@ -70,6 +174,8 @@ class TextInputView: UIView, UITextFieldDelegate {
} else {
textInput.autocorrectionType = .no
}
} else {
textInput.autocorrectionType = .no
}
if let secure = block.data?.secure {
textInput.isSecureTextEntry = secure
Expand All @@ -87,6 +193,25 @@ class TextInputView: UIView, UITextFieldDelegate {
self.textInput?.resignFirstResponder()
}

@objc func onEditingChanged(sender: UITextField) {
guard let regexPattern = self.validateRegex else {
return
}
guard let text = sender.text else {
return
}
if containsPattern(text, regexPattern) {
let view = InputIconView(systemName: "checkmark.circle", message: nil, color: .systemBlue, size: self.fontSize, padding: self.paddingRight)
sender.rightView = view
sender.rightViewMode = .always
} else {
let view = InputIconView(systemName: "info.circle.fill", message: self.errorMessage?.title, color: .systemRed, size: self.fontSize, padding: self.paddingRight)
sender.rightView = view
sender.rightViewMode = .always
}
return
}

// UITextFieldDelegate
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
Expand Down

0 comments on commit 8a38f01

Please sign in to comment.