@jhessin/react-hyperscript-helpers
Version:
Terse syntax for hyperscript using react avoiding the use of brackets
114 lines (96 loc) • 2.98 kB
JavaScript
import React from 'react';
import { TAG_NAMES } from './tag-names.js';
const isArray = x => Array.isArray(x);
const isString = x => typeof x === 'string' && x.length > 0;
const startsWith = (string, start) => string.indexOf(start) === 0;
const isSelector = x => isString(x) && (startsWith(x, '.') || startsWith(x, '#'));
const isChildren = x =>
/string|number|boolean|function/.test(typeof x) || isArray(x) || React.isValidElement(x);
const split = (string, separator) => string.split(separator);
const subString = (string, start, end) => string.substring(start, end);
const parseSelector = selector => {
const classIdSplit = /([\.#]?[a-zA-Z0-9\u007F-\uFFFF_:-]+)/;
const parts = split(selector, classIdSplit);
return parts.reduce(
(acc, part) => {
if (startsWith(part, '#')) {
acc.id = subString(part, 1);
} else if (startsWith(part, '.')) {
acc.className = `${acc.className} ${subString(part, 1)}`.trim();
}
return acc;
},
{ className: '' }
);
};
const createElement = (nameOrType, properties = {}, children = []) => {
if (properties.isRendered !== undefined && !properties.isRendered) {
return null;
}
const { ...props } = properties;
const args = [ nameOrType, props ];
if (!isArray(children)) {
args.push(children);
} else {
args.push(...children);
}
return React.createElement.apply(React, args);
};
export const hh = nameOrType => (first, second, third, ...rest) => {
rest = rest || [];
const parseChild = child => {
if (child instanceof Array) {
rest = [ ...child, ...rest ];
} else {
rest = [ child, ...rest ];
}
};
if (isSelector(first)) {
const selector = parseSelector(first);
// selector, ...children
if (isChildren(second)) {
if (isChildren(third)) {
parseChild(third);
}
parseChild(second);
return createElement(nameOrType, selector, rest);
}
// selector, props, ...children
let { className = '' } = second || {};
className = `${selector.className} ${className} `.trim();
const props = { ...second, ...selector, className };
if (isChildren(third)) {
parseChild(third);
return createElement(nameOrType, props, rest);
}
return createElement(nameOrType, props);
}
// children
if (isChildren(first)) {
if (isChildren(second)) {
if (isChildren(third)) {
parseChild(third);
}
parseChild(second);
}
parseChild(first);
return createElement(nameOrType, {}, rest);
}
// props, children
if (isChildren(second)) {
if (isChildren(third)) {
parseChild(third);
}
parseChild(second);
return createElement(nameOrType, first, rest);
}
return createElement(nameOrType, first);
};
export const h = (nameOrType, ...rest) => hh(nameOrType)(...rest);
module.exports = TAG_NAMES.reduce(
(exported, type) => {
exported[type] = hh(type);
return exported;
},
{ h, hh }
);