Repository URL to install this package:
|
Version:
1.2.12 ▾
|
"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;