import { ComponentClass } from 'react'; import { connect } from 'react-redux'; import { WrappedComponentWithDefaultProps, WrappedComponentWithMappedProps, DefaultStoreState, Id, uiStateSelector, setUIStateSelector, defaultUIStateBranchSelector, UIStateBranchSelector, Props, StateProps, DispatchProps, } from './utils'; // tslint:disable-next-line:class-name export interface __IMPORT_FIX { UIStateBranchSelector: UIStateBranchSelector<{}>; } export type MapConnectUIStateProps = ( props: StateProps & DispatchProps, ownProps: Readonly, ) => TTransformedProps; export const defaultMapper = (props: Props) => props; /** * A higher order component responsible for injecting Redux UI State props (uiState and setUIState) into a Component * @param id A string or function that accepts component props and returns a string * @param mapProps A function that maps raw props into a nicer more contextually relevant shape */ export interface ConnectUIState { (id: Id): ( Component: WrappedComponentWithDefaultProps ) => ComponentClass; ( id: Id, mapProps: MapConnectUIStateProps< TUIState, TMappedProps, TProps > ): ( Component: WrappedComponentWithMappedProps< TUIState, TProps, TMappedProps > ) => ComponentClass; } /** * A higher order component factory that passes UI state related properties and functions to the wrapped component. * The first function should always be called only once during the life of an application as shown below, with the * result being a standard HOC. * * // utils.ts * const connectUIState = createConnectUIState(state => state.ui); * * // Counter.ts * ... * export default connectUIState('counter')(Counter); * * @param uiStateBranchSelector The function that selects the uiState branch from the store */ export const setupConnectUIState = ( uiStateBranchSelector = defaultUIStateBranchSelector ): ConnectUIState => < TUIState, TProps extends {}, TMappedProps, TAppState >( id: Id, mapProps?: MapConnectUIStateProps< TUIState, TMappedProps, TProps > ) => ( Component: | WrappedComponentWithDefaultProps | WrappedComponentWithMappedProps // tslint:disable-line:max-line-length ): ComponentClass => connect( (state: TAppState, props: TProps) => ({ uiState: uiStateSelector( state, Object.assign({ uiStateId: id, uiStateBranchSelector }, props) ) as TUIState }), (dispatch, props: TProps) => ({ setUIState: setUIStateSelector(dispatch, Object.assign({ uiStateId: id }, props)), }), (stateProps, dispatchProps, ownProps) => mapProps ? mapProps(Object.assign({}, stateProps, dispatchProps), ownProps) : Object.assign({}, stateProps, dispatchProps, ownProps) )( // This any is in place because the function is overloaded - function interface variants will // catch errors relating to passing mismatching components and mapping functions // tslint:disable-next-line:no-any Component as any ); export const defaultConnectUIState = setupConnectUIState( defaultUIStateBranchSelector );