react-transclusion
Version:
Render arbitrary components into outlets for use in dynamic layouts.
102 lines (84 loc) • 2.51 kB
JavaScript
const invariant = require('invariant');
/**
* This is the underlying module that allows you to register elements for
* [[Outlet | outlets]] and define them.
*/
module.exports = function OutletManager(config = {}) {
const exports = {};
const outlets = {};
const strict = config.strict !== false;
/**
* Define a new outlet in the layout. An outlet must be defined through this
* API before attempting to inject into it or even render it.
*
* @param {String} name
* The outlet name.
*
* @throws {InvariantError}
* If a similar outlet with this name had already been defined.
*/
exports.define = function(name) {
invariant(!getOutletByName(name),
`Outlet ${name} has already been defined.`
);
if (process.env.NODE_ENV !== 'production' && config.verbose) {
console.log('Outlet defined: "%s"', name);
}
outlets[name] = [];
};
/**
* Register an element to be rendered inside an [Outlet outlet]().
*
* @param {String} name
* The outlet ID.
*
* @param {Object} element
* A description of the element.
*
* @param {String} element.key
* **REQUIRED** - a unique identifier for the component (within that
* outlet.)
*
* @param {React.Class} element.component
* **REQUIRED** - the component to render inside the outlet.
*/
exports.add = function(name, element) {
const outlet = getOutletByName(name);
if (!outlet) {
if (strict) {
invariant(false, `Unknown outlet "${name}".`);
}
exports.define(name);
return exports.add(name, element);
}
const key = element.key || element.component && (
element.component.displayName ||
element.component.constructor.name
);
invariant(typeof key === 'string',
`Missing @key for outlet occupant of "${name}"`
);
invariant(typeof element.component === 'function',
"You must specify a React.Class as @component for the outlet component."
);
outlet.push(Object.assign({}, element, { key }));
};
exports.getElements = function(name) {
return getOutletByName(name) || [];
};
exports.isDefined = function(name) {
return !!getOutletByName(name);
};
exports.reset = function(name) {
if (name) {
outlets[name] = null;
}
else {
Object.keys(outlets).forEach(exports.reset);
}
};
return exports;
function getOutletByName(name) {
return outlets[name];
}
};