react-blessed
Version:
A react renderer for blessed.
246 lines (185 loc) • 8.29 kB
JavaScript
/**
* React Blessed Component
* ========================
*
* React component abstraction for the blessed library.
*/
;
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var _blessed = require('blessed');
var _blessed2 = _interopRequireDefault(_blessed);
var _reactLibReactMultiChild = require('react/lib/ReactMultiChild');
var _reactLibReactMultiChild2 = _interopRequireDefault(_reactLibReactMultiChild);
var _ReactBlessedIDOperations = require('./ReactBlessedIDOperations');
var _ReactBlessedIDOperations2 = _interopRequireDefault(_ReactBlessedIDOperations);
var _invariant = require('invariant');
var _invariant2 = _interopRequireDefault(_invariant);
var _update = require('./update');
var _update2 = _interopRequireDefault(_update);
var _solveClass = require('./solveClass');
var _solveClass2 = _interopRequireDefault(_solveClass);
var _lodash = require('lodash');
/**
* Variable types that must be solved as content rather than real children.
*/
var CONTENT_TYPES = { string: true, number: true };
/**
* Renders the given react element with blessed.
*
* @constructor ReactBlessedComponent
* @extends ReactMultiChild
*/
var ReactBlessedComponent = (function () {
function ReactBlessedComponent(tag) {
_classCallCheck(this, ReactBlessedComponent);
this._tag = tag.toLowerCase();
this._renderedChildren = null;
this._previousStyle = null;
this._previousStyleCopy = null;
this._rootNodeID = null;
this._wrapperState = null;
this._topLevelWrapper = null;
this._nodeWithLegacyProperties = null;
}
/**
* Extending the component with the MultiChild mixin.
*/
_createClass(ReactBlessedComponent, [{
key: 'construct',
value: function construct(element) {
var _this = this;
// Setting some properties
this._currentElement = element;
this._eventListener = function (type) {
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
var handler = _this._currentElement.props['on' + (0, _lodash.startCase)(type)];
if (typeof handler === 'function') handler.apply(null, args);
};
}
/**
* Mounting the root component.
*
* @internal
* @param {string} rootID - The root blessed ID for this node.
* @param {ReactBlessedReconcileTransaction} transaction
* @param {object} context
*/
}, {
key: 'mountComponent',
value: function mountComponent(rootID, transaction, context) {
this._rootNodeID = rootID;
// Mounting blessed node
var node = this.mountNode(_ReactBlessedIDOperations2['default'].getParent(rootID), this._currentElement);
_ReactBlessedIDOperations2['default'].add(rootID, node);
// Mounting children
var childrenToUse = this._currentElement.props.children;
childrenToUse = childrenToUse === null ? [] : [].concat(childrenToUse);
if (childrenToUse.length) {
// Discriminating content components from real children
var _groupBy = (0, _lodash.groupBy)(childrenToUse, function (c) {
return CONTENT_TYPES[typeof c] ? 'content' : 'realChildren';
});
var _groupBy$content = _groupBy.content;
var content = _groupBy$content === undefined ? null : _groupBy$content;
var _groupBy$realChildren = _groupBy.realChildren;
var realChildren = _groupBy$realChildren === undefined ? [] : _groupBy$realChildren;
// Setting textual content
if (content) node.setContent('' + content.join(''));
// Mounting real children
this.mountChildren(realChildren, transaction, context);
}
// Rendering the screen
_ReactBlessedIDOperations2['default'].screen.debouncedRender();
}
/**
* Mounting the blessed node itself.
*
* @param {BlessedNode|BlessedScreen} parent - The parent node.
* @param {ReactElement} element - The element to mount.
* @return {BlessedNode} - The mounted node.
*/
}, {
key: 'mountNode',
value: function mountNode(parent, element) {
var props = element.props;
var type = element.type;
var children = props.children;
var options = _objectWithoutProperties(props, ['children']);
var blessedElement = _blessed2['default'][type];
(0, _invariant2['default'])(!!blessedElement, 'Invalid blessed element "' + type + '".');
var node = _blessed2['default'][type]((0, _solveClass2['default'])(options));
node.on('event', this._eventListener);
parent.append(node);
return node;
}
/**
* Receive a component update.
*
* @param {ReactElement} nextElement
* @param {ReactReconcileTransaction} transaction
* @param {object} context
* @internal
* @overridable
*/
}, {
key: 'receiveComponent',
value: function receiveComponent(nextElement, transaction, context) {
var _nextElement$props = nextElement.props;
var children = _nextElement$props.children;
var options = _objectWithoutProperties(_nextElement$props, ['children']);
var node = _ReactBlessedIDOperations2['default'].get(this._rootNodeID);
(0, _update2['default'])(node, (0, _solveClass2['default'])(options));
// Updating children
var childrenToUse = children === null ? [] : [].concat(children);
if (childrenToUse.length) {
// Discriminating content components from real children
var _groupBy2 = (0, _lodash.groupBy)(childrenToUse, function (c) {
return CONTENT_TYPES[typeof c] ? 'content' : 'realChildren';
});
var _groupBy2$content = _groupBy2.content;
var content = _groupBy2$content === undefined ? null : _groupBy2$content;
var _groupBy2$realChildren = _groupBy2.realChildren;
var realChildren = _groupBy2$realChildren === undefined ? [] : _groupBy2$realChildren;
// Setting textual content
if (content) node.setContent('' + content.join(''));
this.updateChildren(realChildren, transaction, context);
}
_ReactBlessedIDOperations2['default'].screen.debouncedRender();
}
/**
* Dropping the component.
*/
}, {
key: 'unmountComponent',
value: function unmountComponent() {
this.unmountChildren();
var node = _ReactBlessedIDOperations2['default'].get(this._rootNodeID);
node.off('event', this._eventListener);
node.destroy();
_ReactBlessedIDOperations2['default'].drop(this._rootNodeID);
this._rootNodeID = null;
}
/**
* Getting a public instance of the component for refs.
*
* @return {BlessedNode} - The instance's node.
*/
}, {
key: 'getPublicInstance',
value: function getPublicInstance() {
return _ReactBlessedIDOperations2['default'].get(this._rootNodeID);
}
}]);
return ReactBlessedComponent;
})();
exports['default'] = ReactBlessedComponent;
(0, _lodash.extend)(ReactBlessedComponent.prototype, _reactLibReactMultiChild2['default'].Mixin);
module.exports = exports['default'];