import React , { PureComponent , ComponentType , ReactNode } from 'react' ; import { DocumentPropType , TextTransformSpecsType } from './types' ; import PropTypes from 'prop-types' ; import { Document } from '@model/document' ; import { StyleSheet , StyleProp , ViewStyle , TextStyle , ViewPropTypes , LayoutChangeEvent , ScrollViewProps , ScrollView , View , } from 'react-native' ; import { BlockAssembler } from '@model/BlockAssembler' ; import { genericStyles , overridePadding } from './styles' ; import { boundMethod } from 'autobind-decorator' ; import { Block } from '@model/Block' ; import { GenericBlockView } from './GenericBlockView' ; import { Images } from '@core/Images' ; import { Transforms } from '@core/Transforms' ; import { defaults } from './defaults' ; export interface DocumentRendererState { containerWidth : number | null ; } /**
 * A generic interface for components displaying  Document .
 *
 *  remarks public export interface DocumentRendererProps < ImageSource > { /**
     * The  Document to display.
      document : Document ; remarks The component MUST fit within the passed  Images . ComponentProps . printDimensions prop.
      ImageComponent ? : Images . Component < ImageSource > ; /**
     * A collection of text transforms.
     */ textTransformSpecs ? : Transforms . Specs < 'text' > ; /**
     * Default text style.
     */ textStyle ? : StyleProp < TextStyle > ; remarks maxMediaBlockWidth ? : number ; /**
     * The max height of a media block.
     */ maxMediaBlockHeight ? : number ; remarks spacing ? : number ; /**
     * Component style.
     */ style ? : StyleProp < ViewStyle > ; remarks This prop MUST NOT contain padding or margin rules. Such spacing rules will be zero-ed.
     * Instead,  DocumentRendererProps . spacing prop will add spacing between the edge of the scrollview and container.
      contentContainerStyle ? : StyleProp < ViewStyle > ; remarks documentStyle ? : StyleProp < ViewStyle > ; /**
     * Any  react-native props you wish to pass.
     *
     *  remarks scrollViewProps ? : ScrollViewProps ; /**
     * The component to replace RN default  react-native .
      ScrollView ? : ComponentType < any > ; } const contentRendererStyles = StyleSheet . create ( { scroll : { flex : 1 , } , documentStyle : { flexGrow : 1 , justifyContent : 'flex-start' , alignItems : 'stretch' , } , contentContainer : { flex : 1 , flexDirection : 'row' , alignSelf : 'stretch' , justifyContent : 'center' , } , } ) ; internal export class DocumentRenderer < P extends DocumentRendererProps < any > , S extends DocumentRendererState = DocumentRendererState > extends PureComponent < P , S > { public static propTypes : Record < keyof DocumentRendererProps < any > , any > = { document : DocumentPropType . isRequired , ImageComponent : PropTypes . func , style : ViewPropTypes . style , contentContainerStyle : ViewPropTypes . style , documentStyle : ViewPropTypes . style , textStyle : PropTypes . any , spacing : PropTypes . number , maxMediaBlockHeight : PropTypes . number , maxMediaBlockWidth : PropTypes . number , textTransformSpecs : TextTransformSpecsType , ScrollView : PropTypes . func , scrollViewProps : PropTypes . object , } ; public static defaultProps : Partial < Record < keyof DocumentRendererProps < any > , any > > = { ImageComponent : defaults . ImageComponent , spacing : defaults . spacing , textTransformSpecs : defaults . textTransformsSpecs , } ; protected assembler : BlockAssembler ; public constructor ( props ) { super ( props ) ; this . assembler = new BlockAssembler ( props . document ) ; } private getSpacing ( ) { return this . props . spacing as number ; } private handleOnContainerLayout = ( layoutEvent ) => { this . setState ( { containerWidth : layoutEvent . nativeEvent . layout . width , } ) ; } ; private getComponentStyles ( ) { return [ contentRendererStyles . scroll , this . props . style ] ; } private getContentContainerStyles ( ) { const padding = this . getSpacing ( ) ; return [ contentRendererStyles . contentContainer , this . props . contentContainerStyle , overridePadding ( padding ) ] ; } private getDocumentStyles ( ) { return [ contentRendererStyles . documentStyle , this . props . documentStyle , genericStyles . zeroPadding ] ; } protected getBlockStyle ( block ) { if ( block . isLast ( ) ) { return undefined ; } return { marginBottom : this . getSpacing ( ) , } ; } @ boundMethod protected renderBlockView ( block ) { const { textStyle , maxMediaBlockHeight , maxMediaBlockWidth , textTransformSpecs , ImageComponent } = this . props ; const { descriptor } = block ; const key = `block-view-${ descriptor . kind }-${ descriptor . blockIndex }` ; return ( < GenericBlockView blockStyle = { this . getBlockStyle ( block ) } maxMediaBlockHeight = { maxMediaBlockHeight } maxMediaBlockWidth = { maxMediaBlockWidth } key = { key } contentWidth = { this . state . containerWidth } textStyle = { textStyle } descriptor = { descriptor } ImageComponent = { ImageComponent as Images . Component < any > } textTransformSpecs = { textTransformSpecs as Transforms . Specs } / > ) ; } protected renderRoot ( children ) { const { scrollViewProps , ScrollView : UserScrollView } = this . props ; const ScrollViewComponent = ( UserScrollView || ScrollView ) as typeof ScrollView ; return ( < ScrollViewComponent { ... scrollViewProps } style = { this . getComponentStyles ( ) } keyboardShouldPersistTaps = "always" > < View style = { this . getContentContainerStyles ( ) } > < View style = { this . getDocumentStyles ( ) } onLayout = { this . handleOnContainerLayout } > { children } < /View> < /View> < /ScrollViewComponent>); } }