Skip to content

Instantly share code, notes, and snippets.

@developit
Last active April 21, 2020 19:16
Show Gist options
  • Save developit/9d9b01795a9d1c23116497104e25ebfa to your computer and use it in GitHub Desktop.
Save developit/9d9b01795a9d1c23116497104e25ebfa to your computer and use it in GitHub Desktop.
const Component = require('preact/compat').Component;
const AUTOBIND_BLACKLIST = {
constructor: 1,
render: 1,
shouldComponentUpdate: 1,
componentWillReceiveProps: 1,
componentWillUpdate: 1,
componentDidUpdate: 1,
componentWillMount: 1,
componentDidMount: 1,
componentWillUnmount: 1,
componentDidUnmount: 1
};
function F() { }
module.exports = function createClass(obj) {
function cl(props, context) {
bindAll(this);
Component.call(this, props, context);
}
obj = Object.assign({ constructor: cl }, obj);
// We need to apply mixins here so that getDefaultProps is correctly mixed
if (obj.mixins) {
applyMixins(obj, collateMixins(obj.mixins));
}
if (obj.statics) {
Object.assign(cl, obj.statics);
}
if (obj.propTypes) {
cl.propTypes = obj.propTypes;
}
if (obj.defaultProps) {
cl.defaultProps = obj.defaultProps;
}
if (obj.getDefaultProps) {
cl.defaultProps = obj.getDefaultProps.call(cl);
}
F.prototype = Component.prototype;
cl.prototype = Object.assign(new F(), obj);
cl.displayName = obj.displayName || 'Component';
return cl;
}
// Flatten an Array of mixins to a map of method name to mixin implementations
function collateMixins(mixins) {
let keyed = {};
for (let i = 0; i < mixins.length; i++) {
let mixin = mixins[i];
for (let key in mixin) {
if (mixin.hasOwnProperty(key) && typeof mixin[key] === 'function') {
(keyed[key] || (keyed[key] = [])).push(mixin[key]);
}
}
}
return keyed;
}
// apply a mapping of Arrays of mixin methods to a component prototype
function applyMixins(proto, mixins) {
for (let key in mixins)
if (mixins.hasOwnProperty(key)) {
proto[key] = multihook(
mixins[key].concat(proto[key] || ARR),
key === 'getDefaultProps' || key === 'getInitialState' || key === 'getChildContext'
);
}
}
function bindAll(ctx) {
for (let i in ctx) {
let v = ctx[i];
if (typeof v === 'function' && !v.__bound && !AUTOBIND_BLACKLIST.hasOwnProperty(i)) {
(ctx[i] = v.bind(ctx)).__bound = true;
}
}
}
function callMethod(ctx, m, args) {
if (typeof m === 'string') {
m = ctx.constructor.prototype[m];
}
if (typeof m === 'function') {
return m.apply(ctx, args);
}
}
function multihook(hooks, skipDuplicates) {
return function () {
let ret;
for (let i = 0; i < hooks.length; i++) {
let r = callMethod(this, hooks[i], arguments);
if (skipDuplicates && r != null) {
if (!ret) ret = {};
for (let key in r) if (r.hasOwnProperty(key)) {
ret[key] = r[key];
}
}
else if (typeof r !== 'undefined') ret = r;
}
return ret;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment