Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@skava/modules-modules / observable-utils / decorateComponentStatics.ts
Size: Mime:
/* utils */
import hoistNonReactStatic from 'hoist-non-react-statics'
import { toComponentName } from '@skava/identifier'

/**
 * @description
 *  || Observable.Container
 *  @ connectToData(TargetViewComponent) // decorates component
 *  |> ViewInsideContainer              // is react wrapper to let containers top into the view
 *  |> Observer(ViewInsideContainer)   // makes it update for any observable property changes
 *  => TargetViewContainer.render     // call original view component, with all our injections form container
 *                                   // ^ such as on props
 * @example
 *    const state = observable({
 *       text: 'loading',
 *       list: [1, 2],
 *    })
 *    class Container {
 *      static connectToData(Target) {
 *         Target = observer(Target)
 *
 *         class ViewInsideContainer extends Target {
 *            componentWillMount() {
 *                setTimeout(() => state.text = 'eh' && list.push(3), 1000)
 *            }
 *            render() {
 *                // or {text={state.text}, list={state.list}}
 *                // but this handles dereferencing problems
 *                return <Target {...state/>
 *            }
 *         }
 *         return observer(ViewInsideContainer)
 *      }
 *    }
 *    class Button extends React.Component {
 *        static types = { text: '' }
 *        componentDidUpdate = () => console.log(this.props.list)
 *        render = () => <button>{this.props.text}</button>
 *    }
 *
 *
 * @example
 *
 *    <Button />
 *
 *    => <button>loading</button>
 *    -> console.log([1, 2, 3])
 *
 *    // 1 second later
 *    => <button>eh</button>
 *    -> console.log([1, 2, 3])
 *
 * @alias decorateHigherOrderComponent
 * @alias decorateComponentStaticProperties
 *
 * @param {ViewInsideContainer} ViewInsideContainer HigherOrder.ReactComponent
 * @param {TargetViewComponent} TargetViewComponent ReactComponent.componentClass
 * @param {ObservableContainer | *} [container=undefined] Container wrapping ReactComponent
 *
 * @inner side effect only - returns component ONLY for convenience :s
 * @return {ViewInsideContainer}
 */
function decorateComponentStatics(
  ViewInsideContainer,
  TargetViewComponent,
  container
) {
  /**
   * @tutorial https://reactjs.org/docs/higher-order-components.html#static-methods-must-be-copied-over
   * @see https://github.com/mridgway/hoist-non-react-statics/blob/master/index.js
   *
   * @description basically copies all properties from 1 class to another
   *              (that aren't going to conflict with a wrapping React.Component)
   */
  hoistNonReactStatic(ViewInsideContainer, TargetViewComponent)

  /**
   * @see https://reactjs.org/docs/react-component.html#displayname
   * @description this is the name that is displayed in react devtools
   * @type {String}
   * @TODO add store name passed in here
   *
   * this will get the best name for this component
   * 1. if it has static displayName, use that
   * 2. if it's a class, get the constructor/class name
   * 3. if it's a function, get the function name
   * 4. if it has any name prop, use that
   */
  ViewInsideContainer.displayName =
    toComponentName(TargetViewComponent) +
    '(' +
    toComponentName(container) +
    ')'

  /**
   * @description reference to our container
   * @type {ObservableContainer}
   */
  ViewInsideContainer.container = container

  /**
   * @tutorial https://reactjs.org/docs/refs-and-the-dom.html
   * @see https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e
   * @spec https://www.ecma-international.org/ecma-262/8.0/index.html#sec-object.getownpropertynames
   *
   * @alias originalComponentReference
   * @description gives us a static reference to the original component
   * @type {ReactComponent}
   */
  ViewInsideContainer.wrappedComponentRef = TargetViewComponent

  /**
   * @see https://github.com/mobxjs/mobx-react/blob/master/src/observer.js#L306
   * @description now we lift the react-specific props
   * @note injector does not want you to do this
   */
  // ViewInsideContainer.contextTypes = TargetViewComponent.contextTypes
  ViewInsideContainer.propTypes = TargetViewComponent.propTypes
  ViewInsideContainer.defaultProps = TargetViewComponent.defaultProps

  return ViewInsideContainer
}

export { decorateComponentStatics }
export default decorateComponentStatics