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
struct RoundedBorderTextEditor : 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 textMaxHeight : CGFloat ? = nil
var error : String ? = nil
2021-11-23 08:35:32 +00:00
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
@ State private var editing = false
// MARK: P r i v a t e
@ Environment ( \ . theme ) private var theme : ThemeSwiftUI
2022-03-04 11:53:42 +00:00
@ Environment ( \ . isEnabled ) private var isEnabled
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 : . topLeading ) {
if text . isEmpty {
Text ( placeHolder )
. padding ( EdgeInsets ( top : 10 , leading : 10 , bottom : 0 , trailing : 0 ) )
. font ( theme . fonts . callout )
. foregroundColor ( theme . colors . tertiaryContent )
. allowsHitTesting ( false )
}
2022-03-04 11:53:42 +00:00
if isEnabled {
ThemableTextEditor ( text : $ text , onEditingChanged : { edit in
self . editing = edit
onEditingChanged ? ( edit )
} )
. showClearButton ( text : $ text )
// F o u n d n o g o o d s o l u t i o n h e r e . H i d d i n g n e x t b u t t o n f o r t h e m o m e n t
// . m o d i f i e r ( N e x t V i e w M o d i f i e r ( a l i g n m e n t : . b o t t o m T r a i l i n g , i s E d i t i n g : $ e d i t i n g ) )
. padding ( EdgeInsets ( top : 2 , leading : 6 , bottom : 0 , trailing : 0 ) )
. onChange ( of : text , perform : { newText in
onTextChanged ? ( newText )
} )
} else {
ThemableTextEditor ( text : $ text , onEditingChanged : { edit in
self . editing = edit
onEditingChanged ? ( edit )
} )
. padding ( EdgeInsets ( top : 2 , leading : 6 , bottom : 0 , trailing : 6 ) )
. onChange ( of : text , perform : { newText in
onTextChanged ? ( newText )
} )
. opacity ( 0.5 )
. allowsHitTesting ( false )
}
2021-11-23 08:35:32 +00:00
}
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 : ( error = = nil ? theme . colors . quinaryContent : theme . colors . alert ) , lineWidth : editing || error != nil ? 2 : 1 ) )
. frame ( height : textMaxHeight )
if let error = self . error {
Text ( error )
. foregroundColor ( theme . colors . alert )
. font ( theme . fonts . footnote )
. multilineTextAlignment ( . leading )
. padding ( EdgeInsets ( top : 8 , leading : 0 , bottom : 0 , trailing : 0 ) )
. transition ( . opacity )
}
}
. animation ( . easeOut ( duration : 0.2 ) , value : error )
}
}
// MARK: - P r e v i e w s
struct ThemableTextEditor_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 : 40 ) {
2022-03-24 09:50:48 +00:00
RoundedBorderTextEditor ( title : " A title " , placeHolder : " A placeholder " , text : . constant ( " " ) , error : nil )
RoundedBorderTextEditor ( placeHolder : " A placeholder " , text : . constant ( " Some text " ) , error : nil )
RoundedBorderTextEditor ( title : " A title " , placeHolder : " A placeholder " , text : . constant ( " Some very long text used to check overlapping with the delete button " ) , error : " Some error text " )
RoundedBorderTextEditor ( title : " A title " , placeHolder : " A placeholder " , text : . constant ( " Some very long text used to check overlapping with the delete button " ) , error : " Some error text " )
2022-03-04 11:53:42 +00:00
. disabled ( true )
}
}
2021-11-23 08:35:32 +00:00
}