2022-09-27 07:17:22 +00:00
//
2022-02-02 12:24:22 +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 , introduced : 14.0 , deprecated : 15.0 , message : " Use Text with an AttributedString instead that includes a link and handle the tap by adding an OpenURLAction to the environment. " )
// / A ` B u t t o n ` , t h a t f a k e s h a v i n g a t a p p a b l e s t r i n g i n s i d e o f a r e g u l a r s t r i n g .
struct InlineTextButton : View {
2022-02-04 17:46:27 +00:00
private struct StringComponent {
2022-02-02 12:24:22 +00:00
let string : Substring
let isTinted : Bool
}
// MARK: - P r o p e r t i e s
// MARK: P r i v a t e
// / T h e i n d i v i d u a l c o m p o n e n t s o f t h e s t r i n g .
private let components : [ StringComponent ]
private let action : ( ) -> Void
// MARK: - S e t u p
// / C r e a t e s a n e w ` I n l i n e T e x t B u t t o n ` .
// / - P a r a m e t e r s :
// / - m a i n T e x t : T h e m a i n t e x t t h a t s h o u l d n ' t a p p e a r t a p p a b l e . T h i s m u s t c o n t a i n a s i n g l e ` % @ ` p l a c e h o l d e r s o m e w h e r e w i t h i n .
// / - t a p p a b l e T e x t : T h e t a p p a b l e t e x t t h a t w i l l b e s u b s t i t u t e d i n t o t h e ` % @ ` p l a c e h o l d e r .
// / - a c t i o n : T h e a c t i o n t o p e r f o r m w h e n t a p p i n g t h e b u t t o n .
internal init ( _ mainText : String , tappableText : String , action : @ escaping ( ) -> Void ) {
guard let range = mainText . range ( of : " %@ " ) else {
2022-09-27 07:17:22 +00:00
components = [ StringComponent ( string : Substring ( mainText ) , isTinted : false ) ]
2022-02-02 12:24:22 +00:00
self . action = action
return
}
let firstComponent = StringComponent ( string : mainText [ . . < range . lowerBound ] , isTinted : false )
let middleComponent = StringComponent ( string : Substring ( tappableText ) , isTinted : true )
let lastComponent = StringComponent ( string : mainText [ range . upperBound . . . ] , isTinted : false )
2022-09-27 07:17:22 +00:00
components = [ firstComponent , middleComponent , lastComponent ]
2022-02-02 12:24:22 +00:00
self . action = action
}
// MARK: - V i e w s
var body : some View {
Button ( action : action ) {
EmptyView ( )
}
. buttonStyle ( Style ( components : components ) )
2022-09-27 07:17:22 +00:00
. accessibilityLabel ( components . map ( \ . string ) . joined ( ) )
2022-02-02 12:24:22 +00:00
}
2022-02-04 17:46:27 +00:00
private struct Style : ButtonStyle {
2022-02-02 12:24:22 +00:00
let components : [ StringComponent ]
func makeBody ( configuration : Configuration ) -> some View {
components . reduce ( Text ( " " ) ) { lastValue , component in
lastValue + Text ( component . string )
. foregroundColor ( component . isTinted ? . accentColor . opacity ( configuration . isPressed ? 0.2 : 1 ) : nil )
}
}
}
}
struct Previews_InlineButtonText_Previews : PreviewProvider {
static var previews : some View {
InlineTextButton ( " Hello there this is a sentence. %@. " ,
tappableText : " And this is a button " ,
action : { } )
. padding ( )
}
}