2021-11-23 08:35:32 +00:00
//
// C o p y r i g h t 2 0 2 1 N e w V e c t o r L t d
//
// L i c e n s e d u n d e r t h e A p a c h e L i c e n s e , V e r s i o n 2 . 0 ( t h e " L i c e n s e " ) ;
// y o u m a y n o t u s e t h i s f i l e e x c e p t i n c o m p l i a n c e w i t h t h e L i c e n s e .
// Y o u m a y o b t a i n a c o p y o f t h e L i c e n s e a t
//
// h t t p : / / w w w . a p a c h e . o r g / l i c e n s e s / L I C E N S E - 2 . 0
//
// U n l e s s r e q u i r e d b y a p p l i c a b l e l a w o r a g r e e d t o i n w r i t i n g , s o f t w a r e
// d i s t r i b u t e d u n d e r t h e L i c e n s e i s d i s t r i b u t e d o n a n " A S I S " B A S I S ,
// W I T H O U T W A R R A N T I E S O R C O N D I T I O N S O F A N Y K I N D , e i t h e r e x p r e s s o r i m p l i e d .
// S e e t h e L i c e n s e f o r t h e s p e c i f i c l a n g u a g e g o v e r n i n g p e r m i s s i o n s a n d
// l i m i t a t i o n s u n d e r t h e L i c e n s e .
//
import SwiftUI
@ available ( iOS 14.0 , * )
struct RoundedBorderTextField : View {
// MARK: - P r o p e r t i e s
2022-03-24 09:50:48 +00:00
var title : String ? = nil
let placeHolder : String
2021-11-23 08:35:32 +00:00
@ Binding var text : String
2022-03-24 09:50:48 +00:00
var footerText : String ? = nil
var isError : Bool = false
2021-12-01 22:56:59 +00:00
var isFirstResponder = false
2021-11-23 08:35:32 +00:00
var configuration : UIKitTextInputConfiguration = UIKitTextInputConfiguration ( )
2022-03-24 09:50:48 +00:00
var onTextChanged : ( ( String ) -> Void ) ? = nil
var onEditingChanged : ( ( Bool ) -> Void ) ? = nil
2021-11-23 08:35:32 +00:00
// MARK: P r i v a t e
@ State private var editing = false
@ Environment ( \ . theme ) private var theme : ThemeSwiftUI
2022-03-04 11:53:42 +00:00
@ Environment ( \ . isEnabled ) private var isEnabled
2021-12-13 13:43:05 +00:00
2021-11-23 08:35:32 +00:00
// MARK: P u b l i c
var body : some View {
VStack ( alignment : . leading , spacing : - 1 ) {
if let title = self . title {
Text ( title )
. foregroundColor ( theme . colors . primaryContent )
. font ( theme . fonts . subheadline )
. multilineTextAlignment ( . leading )
. padding ( EdgeInsets ( top : 0 , leading : 0 , bottom : 8 , trailing : 0 ) )
}
ZStack ( alignment : . leading ) {
if text . isEmpty {
Text ( placeHolder )
. font ( theme . fonts . callout )
. foregroundColor ( theme . colors . tertiaryContent )
. lineLimit ( 1 )
2022-04-14 10:06:12 +00:00
. accessibilityHidden ( true )
2021-11-23 08:35:32 +00:00
}
2022-03-04 11:53:42 +00:00
if isEnabled {
ThemableTextField ( placeholder : " " , text : $ text , configuration : configuration , onEditingChanged : { edit in
self . editing = edit
onEditingChanged ? ( edit )
} )
. makeFirstResponder ( isFirstResponder )
. showClearButton ( text : $ text )
2022-04-14 10:06:12 +00:00
. onChange ( of : text ) { newText in
2022-03-04 11:53:42 +00:00
onTextChanged ? ( newText )
2022-04-14 10:06:12 +00:00
}
2022-03-04 11:53:42 +00:00
. frame ( height : 30 )
2022-04-14 10:06:12 +00:00
. accessibilityLabel ( text . isEmpty ? placeHolder : " " )
2022-03-04 11:53:42 +00:00
} else {
ThemableTextField ( placeholder : " " , text : $ text , configuration : configuration , onEditingChanged : { edit in
self . editing = edit
onEditingChanged ? ( edit )
} )
. makeFirstResponder ( isFirstResponder )
2022-04-14 10:06:12 +00:00
. onChange ( of : text ) { newText in
2022-03-04 11:53:42 +00:00
onTextChanged ? ( newText )
2022-04-14 10:06:12 +00:00
}
2022-03-04 11:53:42 +00:00
. frame ( height : 30 )
. allowsHitTesting ( false )
. opacity ( 0.5 )
2022-04-14 10:06:12 +00:00
. accessibilityLabel ( text . isEmpty ? placeHolder : " " )
2022-03-04 11:53:42 +00:00
}
2021-11-23 08:35:32 +00:00
}
2021-12-09 08:04:21 +00:00
. padding ( EdgeInsets ( top : 8 , leading : 8 , bottom : 8 , trailing : text . isEmpty ? 8 : 0 ) )
2022-03-04 11:53:42 +00:00
. background ( RoundedRectangle ( cornerRadius : 8 ) . fill ( theme . colors . background ) )
2021-11-23 08:35:32 +00:00
. overlay ( RoundedRectangle ( cornerRadius : 8 )
. stroke ( editing ? theme . colors . accent : ( footerText != nil && isError ? theme . colors . alert : theme . colors . quinaryContent ) , lineWidth : editing || ( footerText != nil && isError ) ? 2 : 1 ) )
if let footerText = self . footerText {
Text ( footerText )
. foregroundColor ( isError ? theme . colors . alert : theme . colors . tertiaryContent )
. font ( theme . fonts . footnote )
. multilineTextAlignment ( . leading )
. padding ( EdgeInsets ( top : 8 , leading : 0 , bottom : 0 , trailing : 0 ) )
. transition ( . opacity )
}
}
. animation ( . easeOut ( duration : 0.2 ) )
}
}
// MARK: - P r e v i e w s
@ available ( iOS 14.0 , * )
struct TextFieldWithError_Previews : PreviewProvider {
static var previews : some View {
Group {
2022-03-04 11:53:42 +00:00
sampleView . theme ( . light ) . preferredColorScheme ( . light )
sampleView . theme ( . dark ) . preferredColorScheme ( . dark )
2021-11-23 08:35:32 +00:00
}
. padding ( )
}
2022-03-04 11:53:42 +00:00
static var sampleView : some View {
VStack ( alignment : . center , spacing : 20 ) {
2022-03-24 09:50:48 +00:00
RoundedBorderTextField ( title : " A title " , placeHolder : " A placeholder " , text : . constant ( " " ) , footerText : nil , isError : false )
RoundedBorderTextField ( placeHolder : " A placeholder " , text : . constant ( " Some text " ) , footerText : nil , isError : false )
RoundedBorderTextField ( title : " A title " , placeHolder : " A placeholder " , text : . constant ( " Some very long text used to check overlapping with the delete button " ) , footerText : " Some error text " , isError : true )
RoundedBorderTextField ( title : " A title " , placeHolder : " A placeholder " , text : . constant ( " Some very long text used to check overlapping with the delete button " ) , footerText : " Some normal text " , isError : false )
RoundedBorderTextField ( title : " A title " , placeHolder : " A placeholder " , text : . constant ( " Some very long text used to check overlapping with the delete button " ) , footerText : " Some normal text " , isError : false )
2022-03-04 11:53:42 +00:00
. disabled ( true )
}
}
2021-11-23 08:35:32 +00:00
}