|  |  |  | import UIKit | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public final class TextView : UITextView, UITextViewDelegate { | 
					
						
							|  |  |  |     private let usesDefaultHeight: Bool | 
					
						
							|  |  |  |     private let height: CGFloat | 
					
						
							|  |  |  |     private let horizontalInset: CGFloat | 
					
						
							|  |  |  |     private let verticalInset: CGFloat | 
					
						
							|  |  |  |     private let placeholder: String | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public override var contentSize: CGSize { didSet { centerTextVertically() } } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private lazy var placeholderLabel: UILabel = { | 
					
						
							|  |  |  |         let result = UILabel() | 
					
						
							|  |  |  |         result.font = .systemFont(ofSize: Values.smallFontSize) | 
					
						
							|  |  |  |         result.textColor = Colors.text.withAlphaComponent(Values.mediumOpacity) | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  |     }() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public init(placeholder: String, usesDefaultHeight: Bool = true, customHeight: CGFloat? = nil, customHorizontalInset: CGFloat? = nil, customVerticalInset: CGFloat? = nil) { | 
					
						
							|  |  |  |         self.usesDefaultHeight = usesDefaultHeight | 
					
						
							|  |  |  |         self.height = customHeight ?? TextField.height | 
					
						
							|  |  |  |         self.horizontalInset = customHorizontalInset ?? (isIPhone5OrSmaller ? Values.mediumSpacing : Values.largeSpacing) | 
					
						
							|  |  |  |         self.verticalInset = customVerticalInset ?? (isIPhone5OrSmaller ? Values.smallSpacing : Values.largeSpacing) | 
					
						
							|  |  |  |         self.placeholder = placeholder | 
					
						
							|  |  |  |         super.init(frame: CGRect.zero, textContainer: nil) | 
					
						
							|  |  |  |         self.delegate = self | 
					
						
							|  |  |  |         setUpStyle() | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public override init(frame: CGRect, textContainer: NSTextContainer?) { | 
					
						
							|  |  |  |         preconditionFailure("Use init(placeholder:) instead.") | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public required init?(coder: NSCoder) { | 
					
						
							|  |  |  |         preconditionFailure("Use init(placeholder:) instead.") | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private func setUpStyle() { | 
					
						
							|  |  |  |         showsHorizontalScrollIndicator = false | 
					
						
							|  |  |  |         showsVerticalScrollIndicator = false | 
					
						
							|  |  |  |         placeholderLabel.text = placeholder | 
					
						
							|  |  |  |         backgroundColor = .clear | 
					
						
							|  |  |  |         textColor = Colors.text | 
					
						
							|  |  |  |         font = .systemFont(ofSize: Values.smallFontSize) | 
					
						
							|  |  |  |         tintColor = Colors.accent | 
					
						
							|  |  |  |         keyboardAppearance = isLightMode ? .light : .dark | 
					
						
							|  |  |  |         if usesDefaultHeight { | 
					
						
							|  |  |  |             set(.height, to: height) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         layer.borderColor = isLightMode ? Colors.text.cgColor : Colors.border.withAlphaComponent(Values.lowOpacity).cgColor | 
					
						
							|  |  |  |         layer.borderWidth = 1 | 
					
						
							|  |  |  |         layer.cornerRadius = TextField.cornerRadius | 
					
						
							|  |  |  |         let horizontalInset = usesDefaultHeight ? self.horizontalInset : Values.mediumSpacing | 
					
						
							|  |  |  |         textContainerInset = UIEdgeInsets(top: 0, left: horizontalInset, bottom: 0, right: horizontalInset) | 
					
						
							|  |  |  |         addSubview(placeholderLabel) | 
					
						
							|  |  |  |         placeholderLabel.pin(.leading, to: .leading, of: self, withInset: horizontalInset + 3) // Slight visual adjustment | 
					
						
							|  |  |  |         placeholderLabel.pin(.top, to: .top, of: self) | 
					
						
							|  |  |  |         pin(.trailing, to: .trailing, of: placeholderLabel, withInset: horizontalInset) | 
					
						
							|  |  |  |         pin(.bottom, to: .bottom, of: placeholderLabel) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public func textViewDidChange(_ textView: UITextView) { | 
					
						
							|  |  |  |         placeholderLabel.isHidden = !text.isEmpty | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private func centerTextVertically() { | 
					
						
							|  |  |  |         let topInset = max(0, (bounds.size.height - contentSize.height * zoomScale) / 2) | 
					
						
							|  |  |  |         contentInset = UIEdgeInsets(top: topInset, left: 0, bottom: 0, right: 0) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |