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 / ___dist / view-container / viewElementFactory.js
Size: Mime:
import React from 'react'
import PropTypes from 'prop-types'
import { fromArgumentsToArray } from 'chain-able-boost'
import { isPureObj } from 'exotic'
// import { hoistNonReactStatics } from 'src/bootstrapper/connectData/deps'
import hoistNonReactStatics from 'hoist-non-react-statics'
import { toComponentName } from '../identifier'
import { exoticPropTypes } from './propTypesTypes/'
import { renderSchemaMethod } from './deps'

// https://github.com/acdlite/recompose/blob/master/src/packages/recompose/branch.js
// https://github.com/acdlite/recompose/blob/master/src/packages/recompose/renameProps.js
// https://github.com/acdlite/recompose/blob/master/src/packages/recompose/toClass.js

// could check if we already have the instance,
// or could decorate any instances with static properties...
// const ViewRegistry = new WeakMap()

function withWrapper(elementToWrapWith) {
  return function(Target) {
    class Wrapped extends Target {
      render() {
        // or super.render
        return React.createElement(
          elementToWrapWith,
          Target.prototype.render.call(this, this)
        )
      }
    }
    hoistNonReactStatics(Wrapped)
    return Wrapped
  }
}

/**
 * if arg = class, extend it
 * if arg = obj, use to build class
 *    if obj.keys.length = 1, take key as tagName
 *
 * @param {Class | Object} [options]
 */
function View(options = undefined) {
  if (arguments.length === 0) {
    return View
  } else if (isPureObj(options)) {
    return viewFrom(options)
  } else if (options !== undefined && options.isBuilder === true) {
    return View.bind(options, options)
  } else {
    // handleView(options)
    return View
  }
}

// View.lazyLoad = function() {
//   throw new Error('@TODO')
// }
// View.withName = function(name) {}
// View.withCustomizable = withCustomizable

// View.withStyles = withStyles

// View.connectToData = function() {
//   throw new Error('@TODO when michael has factory')
// }

// should be the last thing called
View.react = setPrototypeOfReact
// alias
// View.classNames = View.class = View.className = View.withClassName = withClassName

View.tagName = View.withTag
View.tag = View.withTag

View.displayName = View.withName
View.named = View.displayName

View.from = viewFrom

function setPrototypeOfReact(OptionalTarget = undefined) {
  let Parent = React.PureComponent
  function decorator(Target) {
    return Object.setPrototypeOf(Target, Parent)
  }

  if (arguments.length === 1) {
    if (OptionalTarget === React.PureComponent) {
      Parent = OptionalTarget
    } else if (OptionalTarget === React.Component) {
      Parent = React.Component
    }
    return decorator(OptionalTarget)
    // else if (OptionalTarget.prototype)
  } else {
    return decorator
  }
}

// @TODO recompose prob does better already, but if more perf
// function addToContext() {
//   return class {
//     // now we can pick up, expose, and change any of the things we want customizable
//     // and provide it transparently
//     getChildContext() {
//       return customizable
//     }
//   }
// }

function createElementWithBoundTagName(displayName, tagName, attributes) {
  // let factory = React.createFactory(tagName)
  // factory = factory.bind(factory, props)

  return function(runtimeProps = {}) {
    console.log('rendering...')
    // return React.createElement(tagName, attributes)
    // return <tagName {...attributes} />
    return React.createElement(tagName, { ...attributes, ...runtimeProps })
  }
  // let factory = React.createElement.bind(
  //   React.createElement,
  //   tagName,
  //   attributes
  // )
  // factory.displayName = displayName
  // return factory
}

function renderStylesMethod(styles) {
  // transpile
  return React.createElement('style', styles)
}

function decorateTarget(Data, Target) {
  // console.dir({ Data, Target })

  const { schema, wrapper, styles } = Data

  let tag = Data.tag || Data.tagName
  let className =
    Data.className || Data.class || Data.classNames || Data.classes

  const displayName = toComponentName(Target)

  const render = Target.prototype ? Target.prototype.render : undefined

  if (render === undefined) {
    const element = createElementWithBoundTagName(displayName, tag, {
      className,
      schema,
    })

    // if (styles !== undefined) {
    //   return [renderStylesMethod.bind(null, styles), element]
    // }

    return element
    // if (wrapper !== undefined) {
    //   return React.createElement.bind(React.createElement, wrapper, element)
    // }
  }

  // .types
  exoticPropTypes(Target)

  // Target.prototype.renderSchema = renderSchemaMethod
  Target.prototype.renderStyles = renderStylesMethod.bind(this, styles)
  Target.prototype.render = function() {
    let rendered = render.apply(this, arguments)

    // or React.isValidElement(wrapper)
    if (wrapper !== undefined) {
      rendered = React.createElement(wrapper, rendered)
    }
    if (styles !== undefined) {
      const siblings = [rendered]
      // @TODO like autoWrap setting...
      // if (schema !== undefined) {
      //   siblings.unshift(renderSchemaMethod.call(this))
      // }

      siblings.unshift(this.renderStylesMethod())
      return siblings
    }

    return rendered
  }

  return Target
}

function viewFromKeys(objConfig, Target) {
  let TargetAsReducedComposed = Target

  Object.keys(objConfig).forEach(key => {
    const arg = objConfig[key]
    const staticMethod = View[key]
    TargetAsReducedComposed = staticMethod(arg)
  })
  return TargetAsReducedComposed
}

// what is in structured-ui, lift up .types & such
// like any chain .from, calls all methods and allows obj config
function viewFrom(options = false) {
  // if (arguments.length !== 1) {
  //   throw new Error('not supported yet, feel free to add')
  // }

  function decoratorFrom(Target) {
    if (isPureObj(options)) {
      return decorateTarget(options, Target)
    } else {
      return decorateTarget(Target, Target)
    }
  }

  // if we have no options
  if (options === false) {
    return decoratorFrom
  } else if (arguments.length === 1 && isPureObj(options)) {
    if (options.name !== undefined) {
      return decoratorFrom(options, options)
    }
    return decoratorFrom
  } else {
    return decoratorFrom(options)
  }
}

// div, div
// function createElementFromParentChildClassNames() {}

function tagd(tagName) {
  return function(Target) {
    Target.tag = tagName
    return Target
  }
}
function classNamed(className) {
  return function(Target) {
    Target.className = className
    return Target
  }
}

export {
  withWrapper,
  viewFrom,
  setPrototypeOfReact,
  View,
  View as view,
  View as withView,
  createElementWithBoundTagName,
  classNamed as className,
  tagd as tag,
}