/**
 * mostly based on code from https://github.com/CharlesMangwa/react-native-simple-markdown
 */ import { createElement } from 'react' ; import { Image , Text , View , Linking , TextStyle , ViewStyle , ImageStyle , StyleProp , } from 'react-native' ; import SimpleMarkdown , { Output , ReactElements , State , SingleASTNode } from 'simple-markdown' ; interface Styles { [ key ] : StyleProp < ViewStyle | TextStyle | ImageStyle > ; } export default ( styles ) => ( { ... SimpleMarkdown . defaultRules , autolink : { ... SimpleMarkdown . defaultRules . autolink , react : ( node , output , state ) => { state . withinText = true ; return createElement ( Text , { key : state . key , style : styles . link , onPress : ( ) => null , } , output ( node . content , state ) ) ; } , } , blockQuote : { ... SimpleMarkdown . defaultRules . blockQuote , react : ( node , output , state ) => { state . withinText = true ; const blockBar = createElement ( View , { key : state . key , style : [ styles . blockQuoteSectionBar , styles . blockQuoteBar ] , } ) ; const blockText = createElement ( Text , { key : state . key , style : styles . blockQuoteText , } , output ( node . content , state ) ) ; return createElement ( View , { key : state . key , style : [ styles . blockQuoteSection , styles . blockQuote ] , } , [ blockBar , blockText ] ) ; } , } , br : { ... SimpleMarkdown . defaultRules . br , react : ( node , output , state ) => { return createElement ( Text , { key : state . key , style : styles . br , } , '\n\n' ) ; } , } , codeBlock : { ... SimpleMarkdown . defaultRules . codeBlock , react : ( node , output , state ) => { state . withinText = true ; return createElement ( Text , { key : state . key , style : styles . codeBlock , } , null ) ; } , } , del : { ... SimpleMarkdown . defaultRules . del , react : ( node , output , state ) => { state . withinText = true ; return createElement ( Text , { key : state . key , style : styles . del , } , output ( node . content , state ) ) ; } , } , em : { ... SimpleMarkdown . defaultRules . em , react : ( node , output , state ) => { state . withinText = true ; return createElement ( Text , { key : state . key , style : styles . em , } , output ( node . content , state ) ) ; } , } , heading : { ... SimpleMarkdown . defaultRules . heading , react : ( node , output , parentState ) => { const state = { ... parentState } ; state . withinText = true ; const stylesToApply = [ styles . heading , styles [ `heading${ node . level }` ] ] ; state . stylesToApply = stylesToApply ; return createElement ( Text , { key : state . key , style : stylesToApply , } , output ( node . content , state ) ) ; } , } , hr : { ... SimpleMarkdown . defaultRules . hr , react : ( node , output , state ) => createElement ( View , { key : state . key , style : styles . hr } ) , } , image : { ... SimpleMarkdown . defaultRules . image , react : ( node , output , state ) => createElement ( Image , { key : state . key , resizeMode : 'contain' , source : { uri : node . target } , style : ( node . target . match ( /youtu|vimeo/ ) ? styles . video : styles . image ) as ImageStyle , } ) , } , inlineCode : { ... SimpleMarkdown . defaultRules . inlineCode , react : ( node , output , state ) => { state . withinText = true ; return createElement ( Text , { key : state . key , style : styles . inlineCode , } , node . content ) ; } , } , link : { ... SimpleMarkdown . defaultRules . link , react : ( node , output , state ) => { state . withinText = true ; const openUrl = ( url ) => { Linking . openURL ( url ) . catch ( ( error ) => console . warn ( 'An error occurred: ' , error ) ) ; } ; return createElement ( Text , { style : node . target . match ( /@/ ) ? styles . mailTo : styles . link , key : state . key , onPress : ( ) => openUrl ( node . target ) , } , output ( node . content , state ) ) ; } , } , list : { ... SimpleMarkdown . defaultRules . list , react : ( node , output , state ) => { const items = node . items . map ( ( item , i ) => { let bullet ; if ( node . ordered ) { bullet = createElement ( Text , { key : state . key , style : styles . listItemNumber } , `${ i + 1 } . ` ) ; } else { bullet = createElement ( Text , { key : state . key , style : styles . listItemBullet } , '\u2022 ' ) ; } const listItemText = createElement ( Text , { key : ( state . key as number ) + 1 , style : styles . listItemText } , output ( item , state ) ) ; return createElement ( View , { key : i , style : styles . listItem , } , [ bullet , listItemText ] ) ; } ) ; return createElement ( View , { key : state . key , style : styles . list } , items ) ; } , } , newline : { ... SimpleMarkdown . defaultRules . newline , react : ( node , output , state ) => createElement ( Text , { key : state . key , style : styles . newline , } , '\n' ) , } , paragraph : { ... SimpleMarkdown . defaultRules . paragraph , react : ( node , output , state ) => createElement ( View , { key : state . key , style : styles . paragraph , } , output ( node . content , state ) ) , } , strong : { ... SimpleMarkdown . defaultRules . strong , react : ( node , output , state ) => { state . withinText = true ; return createElement ( Text , { key : state . key , style : styles . strong , } , output ( node . content , state ) ) ; } , } , table : { ... SimpleMarkdown . defaultRules . table , react : ( node , output , state ) => { const headers = node . header . map ( ( content , i ) => createElement ( Text , { style : styles . tableHeaderCell , key : i , } , output ( content , state ) ) ) ; const header = createElement ( View , { style : styles . tableHeader } , headers ) ; const rows = node . cells . map ( ( row , r ) => { const cells = row . map ( ( content , c ) => createElement ( View , { key : c , style : styles . tableRowCell , } , output ( content , state ) ) ) ; const rowStyles = [ styles . tableRow ] ; node . cells . length - 1 === r ? rowStyles . push ( styles . tableRowLast ) : null ; return createElement ( View , { key : r , style : rowStyles } , cells ) ; } ) ; return createElement ( View , { key : state . key , style : styles . table } , [ header , rows ] ) ; } , } , text : { ... SimpleMarkdown . defaultRules . text , react : ( node , output , parentState ) => { const state = { ... parentState } ; const textStyles = [ styles . text ] ; return createElement ( Text , { key : state . key , style : textStyles , } , node . content ) ; } , } , u : { ... SimpleMarkdown . defaultRules . u , react : ( node , output , state ) => { state . withinText = true ; return createElement ( Text , { key : state . key , style : styles . u , } , output ( node . content , state ) ) ; } , } , url : { ... SimpleMarkdown . defaultRules . url , react : ( node , output , state ) => { state . withinText = true ; const openURL = ( url ) => { Linking . openURL ( url ) . catch ( ( error ) => console . warn ( 'An error occurred: ' , error ) ) ; } ; return createElement ( Text , { key : state . key , style : styles . url , onPress : ( ) => openURL ( node . target ) , } , output ( node . content , state ) ) ; } , } , } ) ;