import _ from 'lodash' ; import React , { useState , useCallback , useRef , useMemo , MutableRefObject , useEffect , useImperativeHandle } from 'react' ; import { LayoutRectangle , StyleSheet , View , LayoutChangeEvent , Insets , TouchableOpacity , TouchableOpacityProps , GestureResponderEvent , I18nManager , Animated , Text } from 'react-native' ; import MathjaxFactory from '../../mathjax/MathjaxFactory' ; import MathView from '../../android/MathView' ; import HitRectUtil , { defaultHitSlop , MathFragmentRect } from './HitRectUtil' ; import * as TreeWalker from '../../mathjax/TreeWalker' ; import { MathViewProps } from '../../common' ; import { MathFragmentResponse } from '../../mathjax/MathjaxAdaptor' ; function useLayout ( initial = { x : 0 , y : 0 , width : 0 , height : 0 } ) { const [ layout , setLayout ] = useState < LayoutRectangle > ( initial ) ; const onLayout = useCallback ( ( e ) => setLayout ( e . nativeEvent . layout ) , [ ] ) ; return [ layout , onLayout ] as [ LayoutRectangle , ( e : LayoutChangeEvent ) => void ] ; } interface FragmentedMathViewProps extends MathViewProps { hitSlop : number | Insets ; dev : boolean ; } function FragmentedMathView ( props , ref ) { const [ layout , onLayout ] = useLayout ( null ) ; const [ data , setData ] = useState < MathFragmentResponse [ ] > ( ) ; const hitRectUtil = useMemo ( ( ) => new HitRectUtil ( ) , [ ] ) ; useEffect ( ( ) => { if ( ! layout ) return ; setData ( MathjaxFactory ( ) . toSVGArray ( props . math ) ) ; } , [ props . math , layout ] ) ; useEffect ( ( ) => { if ( layout && data ) hitRectUtil . set ( layout , data ) ; } , [ layout , data , hitRectUtil ] ) ; useEffect ( ( ) => { hitRectUtil . setHitSlop ( props . hitSlop ) ; } , [ props . hitSlop , hitRectUtil ] ) ; const __ref = useRef ( ) ; const anima = useMemo ( ( ) => _ . map ( new Array ( _ . size ( data ) ) , ( ) => new Animated . Value ( 1 ) ) , [ data ] ) ; const animaF = useMemo ( ( ) => _ . map ( data , ( { viewBox } , i ) => { if ( ! layout || ! data ) return ; const rect = new MathFragmentRect ( ) . setRect ( layout , viewBox ) ; return Animated . multiply ( layout . width * 0.5 - rect . left , Animated . subtract ( anima [ i ] , 1 ) ) ; } ) , [ layout , data , anima ] ) ; useImperativeHandle ( ref , ( ) => _ . assign ( { } , __ref . current , { test : ( x , y ) => hitRectUtil . test ( x , y ) , __test : ( x , y ) => { const hitResult = hitRectUtil . test ( x , y ) ; _ . map ( hitResult , ( { node , namespace , index , hitResult } ) => { anima [ index ] . setValue ( 2 ) ; Animated . spring ( anima [ index ] , { toValue : 1 , useNativeDriver : true , delay : 100 } ) . start ( ) ; console . log ( namespace . char ) ; } ) ; } , __pip ( ) { _ . map ( new Array ( data . length ) , ( a , i ) => anima [ i ] . setValue ( 2 ) ) ; setTimeout ( ( ) => { } , 200 ) ; Animated . stagger ( 50 , _ . concat ( _ . map ( new Array ( data . length ) , ( a , i ) => Animated . spring ( anima [ i ] , { toValue : 1 , useNativeDriver : true , delay : 500 } ) ) ) ) . start ( ) ; } } ) ) ; return ( < Animated . View collapsable = { false } style = { styles . flexContainer } renderToHardwareTextureAndroid > < MathView { ... props } onLayout = { onLayout } ref = { __ref } / > { layout && data && _ . map ( data , ( { svg , viewBox , namespace : { char } } , index ) => { return ( < Animated . View pointerEvents = 'none' key = { `MathFragment${ index }` } style = { [ StyleSheet . absoluteFill , styles . flexContainer , { transform : [ { translateX : animaF [ index ] } , { scale : anima [ index ] } ] } ] } > < MathBaseView { ... props } svg = { svg } style = { { color : 'blue' } } /> < /Animated.View>); } ) } { __DEV__ && props . dev && layout && _ . map ( data , ( { svg , viewBox , namespace : { char } } , index ) => { const rect = _ . pick ( new MathFragmentRect ( ) . setRect ( layout , viewBox ) , 'left' , 'top' , 'right' , 'bottom' , 'width' , 'height' ) ; return ( < View key = { `MathFragmentBorder${ index }` } style = { [ StyleSheet . absoluteFill , { borderColor : 'blue' , borderWidth : 2 , ... rect , opacity : 0.5 } ] } > < Text > { char } < /Text> < /View>); } ) } < /Animated.View>); } const styles = StyleSheet . create ( { flexContainer : { display : 'flex' , flexDirection : I18nManager . isRTL ? 'row-reverse' : 'row' , } , } ) ; const FragmentedMathViewWrapper = React . forwardRef ( FragmentedMathView ) ; FragmentedMathViewWrapper . defaultProps = FragmentedMathView . defaultProps = { resizeMode : 'contain' , hitSlop : defaultHitSlop , dev : false } as Partial < FragmentedMathViewProps > ; export default FragmentedMathViewWrapper ;