import { fail } from '@turbox3d/shared' ; import { store , depCollector , REACTIVE_COMPONENT_NAME , UNSUBSCRIBE_HANDLER } from '@turbox3d/reactivity' ; import * as React from 'react' ; import ErrorBoundary from './ErrorBoundary' ; import { copyStaticProperties } from '../utils/index' ; export const TURBOX_PREFIX = '@@TURBOX__' ; const IS_INNER = `${ TURBOX_PREFIX }isInner` ; /**
 * Returns a high order component with auto refresh feature.
 */ export function Reactive < T extends Function > ( arg ) ; export function Reactive ( ) ; export function Reactive < P extends object > ( arg ? ) { const decorator = < P extends object > ( Target ) : React . ComponentType < P > => { const displayName = Target . displayName || Target . name || '<TURBOX_COMPONENT>' ; let _this ; if ( typeof Target === 'function' && ( ! Target . prototype || ! Target . prototype . render ) && ( ! Target . prototype || ! Target . prototype . isReactClass ) && ! React . Component . isPrototypeOf ( Target ) ) { const ObservableTarget = ( props ) => { let result ; try { depCollector . start ( _this ) ; const fn = Target as React . FunctionComponent < P > ; result = fn ( props ) ; depCollector . end ( ) ; } catch ( error ) { if ( ! _this [ IS_INNER ] ) { throw error ; } return null ; } return result ; } ; class Wrapper extends React . Component < P > { unsubscribeHandler ? : ( ) => void ; componentDidMount ( ) { if ( ! store ) { fail ( 'store is not ready, please init first.' ) ; } this . unsubscribeHandler = store . subscribe ( ( isInner ) => { _this [ IS_INNER ] = isInner ; this . forceUpdate ( ) ; } , this ) ; } componentWillUnmount ( ) { if ( this . unsubscribeHandler !== void 0 ) { this . unsubscribeHandler ( ) ; } depCollector . clear ( this ) ; } render ( ) { _this = this ; _this [ REACTIVE_COMPONENT_NAME ] = displayName ; return ( < ErrorBoundary > < ObservableTarget { ... this . props as P } / > < /ErrorBoundary>); } } copyStaticProperties ( Target , Wrapper ) ; return Wrapper ; } const target = Target . prototype || Target ; const baseRender = target . render ; const baseComponentDidMount = target . componentDidMount ; const baseComponentWillUnmount = target . componentWillUnmount ; target . render = function ( ) { let result ; try { depCollector . start ( this ) ; result = baseRender . call ( this ) ; depCollector . end ( ) ; } catch ( error ) { if ( ! this [ IS_INNER ] ) { throw error ; } return null ; } return result ; } ; target . componentDidMount = function ( ) { baseComponentDidMount && baseComponentDidMount . call ( this ) ; if ( ! store ) { fail ( 'store is not ready, please init first.' ) ; } this [ UNSUBSCRIBE_HANDLER ] = store . subscribe ( ( isInner ) => { this [ IS_INNER ] = isInner ; this . forceUpdate ( ) ; } , this ) ; } ; target . componentWillUnmount = function ( ) { if ( this [ UNSUBSCRIBE_HANDLER ] !== void 0 ) { this [ UNSUBSCRIBE_HANDLER ] ( ) ; } depCollector . clear ( this ) ; baseComponentWillUnmount && baseComponentWillUnmount . call ( this ) ; } ; class ObservableTargetComponent extends React . Component < P > { render ( ) { return ( < ErrorBoundary > < Target { ... this . props as P } / > < /ErrorBoundary>); } } copyStaticProperties ( Target , ObservableTargetComponent ) ; return ObservableTargetComponent ; } ; if ( arg === void 0 ) { return decorator ; } return decorator . call ( null , arg ) ; }