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 / deps / createElementWithStyle.js
Size: Mime:
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.createElementWithStyle = createElementWithStyle;
exports.default = void 0;

var _react = _interopRequireDefault(require("react"));

var _exotic = require("exotic");

var _classnames = _interopRequireDefault(require("classnames"));

var _identifier = require("../../identifier");

var _selectors = require("../styles/selectors");

var _jsxFileName = "view-container/deps/createElementWithStyle.js";

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

const isStringOrFunction = x => (0, _exotic.isString)(x) || (0, _exotic.isFunction)(x);

const hasFunctionKeys = x => {
  if ((0, _exotic.isObj)(x)) {
    const keys = Object.keys(x);

    for (let index = 0; index < keys.length; index++) {
      const key = keys[index];
      const value = x[key];

      if ((0, _exotic.isFunction)(value)) {
        return true;
      }
    }
  } // else if (isFunction(value)) {
  //   return true
  // }


  return false;
};

const isFunctionOrHasFunctionKeys = x => hasFunctionKeys(x) || (0, _exotic.isFunction)(x);

const isValid = x => (0, _exotic.isSafe)(x) && (0, _exotic.isString)(x) && (0, _exotic.isEmpty)(x) === false;
/**
 * @todo support things like
 *   renderProps: children => ['wording', children]
 *   aliasProps: [from, to]
 *
 * @alias callWithProps
 * @param {Object} traversee
 * @param {React.Props} props
 * @return {React.Props}
 */


const fromDynamicPropsToReactProps = (traversee, props) => {
  // @todo only spread when frozen
  const dynamicProps = _objectSpread({}, props);

  Object.keys(traversee).forEach(key => {
    const method = traversee[key];

    if ((0, _exotic.isFunction)(method)) {
      const returned = method(props);

      if ((0, _exotic.isSafe)(returned)) {
        dynamicProps[key] = returned;
      }
    } else {
      dynamicProps[key] = traversee[key];
    }
  });
  return dynamicProps;
};

const styledMixinReferencesList = Object.freeze(['tabletOrSmaller', 'tabletOrLarger', 'phoneOrSmaller', 'phoneOrLarger', 'desktopOrLarger']);
/**
 * @todo @james and when no styles...
 *
 * @param {React.ReactElement} tagName
 * @param {styled | CSS | String | undefined} [_styles='']
 * @param {Object | undefined} [_attributes=EMPTY_OBJ]
 *
 * @return {reactElementFactory | Function | Class}
 */

function createElementWithStyle(tagName, _styles, _attributes) {
  // is a className
  if ((0, _selectors.isClassName)(_styles) && isStringOrFunction(_attributes) === false) {
    _attributes = ''; // return createElementWithClassName(tagName, _styles)
  } // is classname + styles
  // arguments.length === 3 <- overriden by check above


  const isClassNameAndStyles = tagName && (0, _selectors.isClassName)(_styles) && isStringOrFunction(_attributes); // DynamicAttributesOnly

  const isAttributes = (0, _exotic.isObj)(_styles); // for displayName

  let debugName;
  const styles = isClassNameAndStyles ? _attributes : _styles;
  let className = isClassNameAndStyles ? _styles : '';
  const attributes = isClassNameAndStyles ? {} : isAttributes ? _styles : _attributes;
  let firstSafeClassName = className;
  /**
   * @type {Object}
   * @description scope the css to allow chain appendage
   */

  let css = isStringOrFunction(styles) ? styles : '';
  /**
   * @type {Object}
   * @description scope the attributes to merge all
   */

  let scoped = (0, _exotic.isObj)(attributes) ? attributes : _exotic.EMPTY_OBJ; // was debugging mounted styles hah
  // if (className.includes('rendered') || className.includes('modal-container-wrapper')) {
  //   console.log({
  //     // 1 - args
  //     tagName,
  //     _styles,
  //     _attributes,
  //     // 2 - computed
  //     styles,
  //     attributes,
  //     className,
  //     // 3 - injected
  //     scoped,
  //     css,
  //   })
  // }
  // ========= split ^v like with Money =========

  /**
   * @note we could also use a class with static props...
   *
   * @member reactElementFactory
   * @name reactElementFactory
   *
   * @property {String} displayName
   * @property {Function} styles
   * @property {Function} styled
   * @property {Function} attributes
   * @method styles
   * @method styled
   * @method attributes
   * @method styled.replace
   * @method styled.add
   * @method styled.tabletOrSmaller
   * @method styled.tabletOrLarger
   * @method styled.phoneOrSmaller
   * @method styled.desktopOrLarger
   * @method styled.phoneOrLarger
   *
   * @param {React.Props} props
   * @param {React.Context} context
   * @return {React.ReactElement}
   */

  function reactElementFactory(props, context) {
    // React always passes in props + context?
    // if (arguments.length === 2)
    // @todo - traverse classNames to pass in for dynamic props
    // @todo - eventually if possible with perf use this with styles too
    // const classes = attributes.classNames || props.classNames
    // const classNames = classnames(attributes.classNames || props.classNames)
    // 1. set up our classname
    // 2. the scope is always by-reference to props
    // 3. this is possible because
    //    react keeps a memoized props
    //    so the same ref can be used
    //
    // @note this is "cool" and it works, but doesn't provide api how people use/want it
    // className = isSafe(props) && isString(props.className)
    //   ? props.className
    //   : isSafe(attributes) && isSafe(attributes.className)
    //     ? attributes.className
    //     : isSafe(className)
    //       ? className
    //       : 'selectorless-' + toIdentifier(props)
    if ((0, _exotic.isSafe)(props) && (0, _exotic.isString)(props.className) && className.includes(props.className) === false) {
      // or toClassName
      className += ' ' + props.className;
    } // we may have set it after
    // if (isSafe(firstSafeClassName) === false && isSafe(className) === false) {
    //   firstSafeClassName = 'selectorless-' + toIdentifier(props)
    // }


    if (isValid(firstSafeClassName) && className.includes(firstSafeClassName) === false) {
      className += ' ' + firstSafeClassName;
    }

    if (isValid(attributes) && isValid(attributes.className) && className.includes(attributes.className) === false) {
      className += ' ' + attributes.className;
    } // may still have no className


    if (isValid(firstSafeClassName) === false && isValid(className) === false) {
      firstSafeClassName = 'selectorless-' + (0, _identifier.toIdentifier)(props);
      className = firstSafeClassName;
    }

    className = className.trim();

    if ((0, _exotic.isFunction)(scoped.classList)) {
      className = scoped.classList(props);
    } else if ((0, _exotic.isSafe)(scoped.classList)) {
      // @note - this duplicated
      className = (0, _classnames.default)(className, scoped.classList);
    } // 1. merge in dynamic attributes
    // 2. ensure we have a className
    // 3. className always works here as a unique key
    // @todo IT IS NOT ALWAYS UNIQUE IF WE HAVE MULTIPLE OF THE SAME


    const base = {
      className,
      key: className // when we use a function, or an object full of functions
      // we can render props dynamically
      //
      // @note we assign to a new var, vs overriding scoped
      //       for subsequent renders
      //
      // @todo - this does not handle renderProps,
      // ...but renderProps for elements is not valid so...
      //
      // @todo - this assumes using .element

    };
    const frozenScoped = isFunctionOrHasFunctionKeys(scoped) === false ? scoped : fromDynamicPropsToReactProps(scoped, props);
    /**
     * @note - this extra assignment when it was not empty added props of self
     * which is the log of ".toComponent is not known prop on div..."
     */

    const merged = frozenScoped === _exotic.EMPTY_OBJ || (0, _exotic.isFunction)(frozenScoped.toComponent) ? Object.assign(base, props) : Object.assign(base, scoped, props); // create this up here because we may not have styles

    const component = _react.default.createElement(tagName, merged); // we have no styles


    if (css === _exotic.EMPTY_STRING) {
      // console.log('NO-STYLES')
      return component;
    } // @todo - can use `id`


    const cssClass = '.' + className;
    const hasSelectorInStyles = isStringOrFunction(css) && css.toString().includes(cssClass);
    const stringWithSelectors = (0, _selectors.fromSelectorsAndStylesToBlock)(cssClass, css); // const stylesWithSelectors = hasSelectorInStyles === true ? css : styled`
    //   ${stringWithSelectors}
    // `

    const stylesWithSelectors = styled`
      ${stringWithSelectors}
    `;
    const Stylish = stylesWithSelectors.toComponent(); // console.log({ stylesWithSelectors, Stylish })
    // as-siblings

    return [_react.default.createElement(Stylish, {
      key: "stylish",
      __source: {
        fileName: _jsxFileName,
        lineNumber: 287
      },
      __self: this
    }), component];
  }
  /**
   * @todo should traverse and pass in props for dynamic
   *
   * @memberof reactElementFactory
   *
   * @param {React.props} addedAttributes
   * @return {reactElementFactory}
   */


  reactElementFactory.attributes = function (addedAttributes) {
    scoped = addedAttributes;
    return reactElementFactory;
  };
  /**
   * @memberof reactElementFactory
   *
   * @param {Object | classList | classnames} classListProvided
   * @return {reactElementFactory}
   */


  reactElementFactory.classList = function (classListProvided) {
    const keys = Object.keys(classListProvided);
    let currentClassName = ``;

    if (scoped === _exotic.EMPTY_OBJ) {
      scoped = {};
    }

    function classListFactory(props) {
      // allow passing in a classList or className to startFrom
      if ((0, _exotic.isString)(props.className)) {
        currentClassName = props.className;
      } // if we pass in a function, allow `tapping` that classList


      if ((0, _exotic.isFunction)(classListProvided)) {
        currentClassName = classListProvided(currentClassName, props);
      } // render all keys, almost the same as classnames
      // @variation 1. no `default` key
      // @variation 2. no using `string`, `object` params
      // @variation 3. allow using functions
      //               - though you could with `get`,
      //               - those cannot be 1 line so nobody uses


      for (let index = 0; index < keys.length; index++) {
        const key = keys[index];
        const classNameValue = classListProvided[key];

        if ((0, _exotic.isFunction)(classNameValue)) {
          currentClassName += classNameValue(props);
        } else if (classNameValue === false) {// ignore
        } else {
          // normal string for key
          currentClassName += ' ' + key;
        }
      }

      return currentClassName.trim();
    }

    Object.defineProperty(scoped, 'classList', {
      configurable: true,
      enumerable: false,
      writable: true,
      value: classListFactory
    });
    return reactElementFactory;
  };
  /**
   * @todo should traverse and pass in props for dynamic
   *
   * @memberof reactElementFactory
   *
   * @prop {styled | reactElementFactory.styles} tabletOrSmaller
   * @prop {styled | reactElementFactory.styles} phoneOrSmaller
   * @prop {styled | reactElementFactory.styles} tabletOrLarger
   * @prop {styled | reactElementFactory.styles} phoneOrLarger
   * @prop {styled | reactElementFactory.styles} desktopOrLarger
   *
   * @param {styled | CSS | String} addedStyles
   * @return {reactElementFactory}
   */


  reactElementFactory.styles = function (addedStyles) {
    css += addedStyles;
    return reactElementFactory;
  };
  /**
   * @todo should traverse and pass in props for dynamic
   *
   * @memberof reactElementFactory
   * @see this.styles
   *
   * @param {styled | CSS | String} addedStyles
   * @return {reactElementFactory}
   */


  reactElementFactory.styled = function () {
    return reactElementFactory.styles(styled.apply(this, arguments));
  };
  /**
   * @memberof reactElementFactory
   * @alias styled.add
   * @type {Function}
   * @description use template highlighting hack
   */


  reactElementFactory.styled.add = reactElementFactory.styled;
  /**
   * @description REPLACE the styles
   *
   * @memberof reactElementFactory
   *
   * @param {styled | CSS | String} addedStyles
   * @return {reactElementFactory}
   */

  reactElementFactory.styled.replace = function () {
    css = styled.apply(this, arguments);
    return reactElementFactory;
  }; // =========

  /**
   * @memberof ReactElementFactory
   * @description clone the element
   * @return {reactElementFactory} @chainable
   */


  reactElementFactory.extend = function () {
    return createElementWithStyle(tagName, css, _objectSpread({}, scoped));
  };
  /**
   * @memberof ReactElementFactory
   * @param {String | *} name for react displayName
   * @return {reactElementFactory} @chainable
   */


  reactElementFactory.named = function named(name) {
    debugName = (0, _identifier.toComponentName)(name);
    return reactElementFactory;
  }; // =========


  Object.defineProperty(reactElementFactory, 'displayName', {
    configurable: true,
    enumerable: true,

    get value() {
      // we actually DO NOT WANT THIS camelCase(className)
      const tag = tagName || 'reactElementFactory';
      return (0, _exotic.isString)(debugName) ? debugName : `🔎 ${tag}(  .${className}  )`;
    }

  }); // =========

  /**
   * @see styled
   *
   * @description add shorthand access to `.styled.[mixin-name]`
   * @modifies reactElementFactory.styled
   *
   * @param {String} name property name on `styled`
   */

  function addStyledReference(name) {
    reactElementFactory.styled[name] = function () {
      return reactElementFactory.styles(styled[name].apply(this, arguments));
    };
  }

  styledMixinReferencesList.forEach(addStyledReference);
  return reactElementFactory;
}

var _default = createElementWithStyle;
exports.default = _default;