Comparing version 2.0.6 to 2.1.0
@@ -12,2 +12,6 @@ "use strict"; | ||
const hasOwnProperty = (obj, prop) => { | ||
return {}.hasOwnProperty.call(obj, prop); | ||
}; | ||
const applyMarginStyles = (node, style) => { | ||
@@ -110,2 +114,6 @@ if (style.margin) { | ||
if (hasOwnProperty(style, 'flexBasis')) { | ||
node.setFlexBasis(style.flexBasis); | ||
} | ||
if (style.alignItems) { | ||
@@ -148,2 +156,20 @@ if (style.alignItems === 'flex-start') { | ||
const applyDimensionStyles = (node, style) => { | ||
if (hasOwnProperty(style, 'width')) { | ||
node.setWidth(style.width); | ||
} | ||
if (hasOwnProperty(style, 'height')) { | ||
node.setHeight(style.height); | ||
} | ||
if (hasOwnProperty(style, 'minWidth')) { | ||
node.setMinWidth(style.minWidth); | ||
} | ||
if (hasOwnProperty(style, 'minHeight')) { | ||
node.setMinHeight(style.minHeight); | ||
} | ||
}; | ||
var _default = (node, style = {}) => { | ||
@@ -153,4 +179,5 @@ applyMarginStyles(node, style); | ||
applyFlexStyles(node, style); | ||
applyDimensionStyles(node, style); | ||
}; | ||
exports.default = _default; |
@@ -10,18 +10,9 @@ "use strict"; | ||
var _widestLine = _interopRequireDefault(require("widest-line")); | ||
var _applyStyles = _interopRequireDefault(require("./apply-styles")); | ||
var _measureText = _interopRequireDefault(require("./measure-text")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const measureText = text => { | ||
const width = (0, _widestLine.default)(text); | ||
const height = text.split('\n').length; | ||
return { | ||
width, | ||
height | ||
}; | ||
}; // Traverse the node tree, create Yoga nodes and assign styles to each Yoga node | ||
// Traverse the node tree, create Yoga nodes and assign styles to each Yoga node | ||
const buildLayout = (node, options) => { | ||
@@ -60,32 +51,12 @@ const { | ||
if (node.textContent) { | ||
if (node.textContent || node.nodeValue) { | ||
const { | ||
width, | ||
height | ||
} = measureText(node.textContent); | ||
} = (0, _measureText.default)(node.textContent || node.nodeValue); | ||
yogaNode.setWidth(style.width || width); | ||
yogaNode.setHeight(style.height || height); | ||
return node; | ||
} // Text node | ||
if (node.nodeValue) { | ||
const { | ||
width, | ||
height | ||
} = measureText(node.nodeValue); | ||
yogaNode.setWidth(width); | ||
yogaNode.setHeight(height); | ||
return node; | ||
} // Nodes with other nodes as children | ||
if (style.width) { | ||
yogaNode.setWidth(style.width); | ||
} | ||
if (style.height) { | ||
yogaNode.setHeight(style.height); | ||
} | ||
if (Array.isArray(node.childNodes) && node.childNodes.length > 0) { | ||
@@ -92,0 +63,0 @@ const childNodes = node.childNodes.filter(childNode => { |
@@ -72,5 +72,5 @@ "use strict"; | ||
_defineProperty(this, "handleExit", () => { | ||
_defineProperty(this, "handleExit", error => { | ||
this.handleSetRawMode(false); | ||
this.props.onExit(); | ||
this.props.onExit(error); | ||
}); | ||
@@ -108,2 +108,6 @@ | ||
componentDidCatch(error) { | ||
this.handleExit(error); | ||
} | ||
} | ||
@@ -110,0 +114,0 @@ |
@@ -66,9 +66,13 @@ "use strict"; | ||
paddingRight: _propTypes.default.number, | ||
width: _propTypes.default.number, | ||
height: _propTypes.default.number, | ||
width: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]), | ||
minWidth: _propTypes.default.number, | ||
height: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]), | ||
minHeight: _propTypes.default.number, | ||
flexGrow: _propTypes.default.number, | ||
flexShrink: _propTypes.default.number, | ||
flexDirection: _propTypes.default.oneOf(['row', 'row-reverse', 'column', 'column-reverse']), | ||
flexBasis: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]), | ||
alignItems: _propTypes.default.oneOf(['flex-start', 'center', 'flex-end']), | ||
justifyContent: _propTypes.default.oneOf(['flex-start', 'center', 'flex-end', 'space-between', 'space-around']), | ||
textWrap: _propTypes.default.oneOf(['wrap', 'truncate', 'truncate-start', 'truncate-middle', 'truncate-end']), | ||
unstable__transformChildren: _propTypes.default.func, | ||
@@ -75,0 +79,0 @@ children: _propTypes.default.node |
@@ -67,6 +67,2 @@ "use strict"; | ||
shouldComponentUpdate(nextProps, nextState) { | ||
return this.state.ignoreKeys === nextState.ignoreKeys; | ||
} | ||
saveRenderedKeys() { | ||
@@ -73,0 +69,0 @@ this.setState(prevState => { |
@@ -16,2 +16,6 @@ "use strict"; | ||
var _isCi = _interopRequireDefault(require("is-ci")); | ||
var _signalExit = _interopRequireDefault(require("signal-exit")); | ||
var _reconciler = _interopRequireDefault(require("./reconciler")); | ||
@@ -32,2 +36,3 @@ | ||
this.rootNode = (0, _dom.createNode)('root'); | ||
this.rootNode.onRender = this.onRender; | ||
this.renderer = (0, _renderer.default)({ | ||
@@ -42,13 +47,16 @@ terminalWidth: options.stdout.columns | ||
this.ignoreRender = false; // Store last output to only rerender when needed | ||
this.isUnmounted = false; // Store last output to only rerender when needed | ||
this.lastOutput = ''; | ||
this.lastStaticOutput = ''; // This variable is used only in debug mode to store full static output | ||
this.lastOutput = ''; // This variable is used only in debug mode to store full static output | ||
// so that it's rerendered every time, not just new static parts, like in non-debug mode | ||
this.fullStaticOutput = ''; | ||
this.reconciler = (0, _reconciler.default)(this.onRender); | ||
this.container = this.reconciler.createContainer(this.rootNode, false); | ||
this.exitPromise = new Promise(resolve => { | ||
this.container = _reconciler.default.createContainer(this.rootNode, false, false); | ||
this.exitPromise = new Promise((resolve, reject) => { | ||
this.resolveExitPromise = resolve; | ||
this.rejectExitPromise = reject; | ||
}); // Unmount when process exits | ||
this.unsubscribeExit = (0, _signalExit.default)(this.unmount, { | ||
alwaysLast: false | ||
}); | ||
@@ -58,3 +66,3 @@ } | ||
onRender() { | ||
if (this.ignoreRender) { | ||
if (this.isUnmounted) { | ||
return; | ||
@@ -68,8 +76,7 @@ } | ||
const hasNewStaticOutput = staticOutput && staticOutput !== '\n' && staticOutput !== this.lastStaticOutput; | ||
const hasStaticOutput = staticOutput && staticOutput !== '\n'; | ||
if (this.options.debug) { | ||
if (hasNewStaticOutput) { | ||
if (hasStaticOutput) { | ||
this.fullStaticOutput += staticOutput; | ||
this.lastStaticOutput = staticOutput; | ||
} | ||
@@ -82,11 +89,19 @@ | ||
if (hasNewStaticOutput) { | ||
this.log.clear(); | ||
if (hasStaticOutput) { | ||
if (!_isCi.default) { | ||
this.log.clear(); | ||
} | ||
this.options.stdout.write(staticOutput); | ||
this.log(output); | ||
this.lastStaticOutput = staticOutput; | ||
if (!_isCi.default) { | ||
this.log(output); | ||
} | ||
} | ||
if (output !== this.lastOutput) { | ||
this.throttledLog(output); | ||
if (!_isCi.default) { | ||
this.throttledLog(output); | ||
} | ||
this.lastOutput = output; | ||
@@ -104,11 +119,29 @@ } | ||
this.reconciler.updateContainer(tree, this.container); | ||
_reconciler.default.updateContainer(tree, this.container); | ||
} | ||
unmount() { | ||
unmount(error) { | ||
if (this.isUnmounted) { | ||
return; | ||
} | ||
this.onRender(); | ||
this.log.done(); | ||
this.ignoreRender = true; | ||
this.reconciler.updateContainer(null, this.container); | ||
this.resolveExitPromise(); | ||
this.unsubscribeExit(); // CIs don't handle erasing ansi escapes well, so it's better to | ||
// only render last frame of non-static output | ||
if (_isCi.default) { | ||
this.options.stdout.write(this.lastOutput + '\n'); | ||
} else if (!this.options.debug) { | ||
this.log.done(); | ||
} | ||
this.isUnmounted = true; | ||
_reconciler.default.updateContainer(null, this.container); | ||
if (error instanceof Error) { | ||
this.rejectExitPromise(error); | ||
} else { | ||
this.resolveExitPromise(); | ||
} | ||
} | ||
@@ -115,0 +148,0 @@ |
@@ -16,112 +16,113 @@ "use strict"; | ||
var _default = onRender => { | ||
const rootHostContext = {}; | ||
const childHostContext = {}; | ||
const hostConfig = { | ||
schedulePassiveEffects: _scheduler.unstable_scheduleCallback, | ||
cancelPassiveEffects: _scheduler.unstable_cancelCallback, | ||
now: Date.now, | ||
getRootHostContext: () => rootHostContext, | ||
prepareForCommit: () => {}, | ||
resetAfterCommit: onRender, | ||
getChildHostContext: () => childHostContext, | ||
shouldSetTextContent: (type, props) => { | ||
return typeof props.children === 'string' || typeof props.children === 'number'; | ||
}, | ||
createInstance: (type, newProps) => { | ||
const node = (0, _dom.createNode)(type); | ||
const NO_CONTEXT = true; | ||
const hostConfig = { | ||
schedulePassiveEffects: _scheduler.unstable_scheduleCallback, | ||
cancelPassiveEffects: _scheduler.unstable_cancelCallback, | ||
now: Date.now, | ||
getRootHostContext: () => NO_CONTEXT, | ||
prepareForCommit: () => {}, | ||
resetAfterCommit: rootNode => { | ||
rootNode.onRender(); | ||
}, | ||
getChildHostContext: () => NO_CONTEXT, | ||
shouldSetTextContent: (type, props) => { | ||
return typeof props.children === 'string' || typeof props.children === 'number'; | ||
}, | ||
createInstance: (type, newProps) => { | ||
const node = (0, _dom.createNode)(type); | ||
for (const [key, value] of Object.entries(newProps)) { | ||
if (key === 'children') { | ||
if (typeof value === 'string' || typeof value === 'number') { | ||
if (type === 'div') { | ||
// Text node must be wrapped in another node, so that text can be aligned within container | ||
const textElement = (0, _dom.createNode)('div'); | ||
textElement.textContent = String(value); | ||
(0, _dom.appendChildNode)(node, textElement); | ||
} | ||
for (const [key, value] of Object.entries(newProps)) { | ||
if (key === 'children') { | ||
if (typeof value === 'string' || typeof value === 'number') { | ||
if (type === 'div') { | ||
// Text node must be wrapped in another node, so that text can be aligned within container | ||
const textElement = (0, _dom.createNode)('div'); | ||
textElement.textContent = String(value); | ||
(0, _dom.appendChildNode)(node, textElement); | ||
} | ||
if (type === 'span') { | ||
node.textContent = String(value); | ||
} | ||
if (type === 'span') { | ||
node.textContent = String(value); | ||
} | ||
} else if (key === 'style') { | ||
Object.assign(node.style, value); | ||
} else if (key === 'unstable__transformChildren') { | ||
node.unstable__transformChildren = value; // eslint-disable-line camelcase | ||
} else if (key === 'unstable__static') { | ||
node.unstable__static = true; // eslint-disable-line camelcase | ||
} else { | ||
(0, _dom.setAttribute)(node, key, value); | ||
} | ||
} else if (key === 'style') { | ||
Object.assign(node.style, value); | ||
} else if (key === 'unstable__transformChildren') { | ||
node.unstable__transformChildren = value; // eslint-disable-line camelcase | ||
} else if (key === 'unstable__static') { | ||
node.unstable__static = true; // eslint-disable-line camelcase | ||
} else { | ||
(0, _dom.setAttribute)(node, key, value); | ||
} | ||
} | ||
return node; | ||
}, | ||
createTextInstance: _dom.createTextNode, | ||
resetTextContent: node => { | ||
if (node.textContent) { | ||
node.textContent = ''; | ||
} | ||
return node; | ||
}, | ||
createTextInstance: _dom.createTextNode, | ||
resetTextContent: node => { | ||
if (node.textContent) { | ||
node.textContent = ''; | ||
} | ||
if (node.childNodes.length > 0) { | ||
for (const childNode of node.childNodes) { | ||
childNode.yogaNode.free(); | ||
(0, _dom.removeChildNode)(node, childNode); | ||
} | ||
if (node.childNodes.length > 0) { | ||
for (const childNode of node.childNodes) { | ||
childNode.yogaNode.free(); | ||
(0, _dom.removeChildNode)(node, childNode); | ||
} | ||
}, | ||
getPublicInstance: instance => instance, | ||
appendInitialChild: _dom.appendChildNode, | ||
appendChild: _dom.appendChildNode, | ||
insertBefore: _dom.insertBeforeNode, | ||
finalizeInitialChildren: () => {}, | ||
supportsMutation: true, | ||
appendChildToContainer: _dom.appendChildNode, | ||
insertInContainerBefore: _dom.insertBeforeNode, | ||
removeChildFromContainer: _dom.removeChildNode, | ||
prepareUpdate: () => true, | ||
commitUpdate: (node, updatePayload, type, oldProps, newProps) => { | ||
for (const [key, value] of Object.entries(newProps)) { | ||
if (key === 'children') { | ||
if (typeof value === 'string' || typeof value === 'number') { | ||
if (type === 'div') { | ||
// Text node must be wrapped in another node, so that text can be aligned within container | ||
// If there's no such node, a new one must be created | ||
if (node.childNodes.length === 0) { | ||
const textElement = (0, _dom.createNode)('div'); | ||
textElement.textContent = String(value); | ||
(0, _dom.appendChildNode)(node, textElement); | ||
} else { | ||
node.childNodes[0].textContent = String(value); | ||
} | ||
} | ||
}, | ||
getPublicInstance: instance => instance, | ||
appendInitialChild: _dom.appendChildNode, | ||
appendChild: _dom.appendChildNode, | ||
insertBefore: _dom.insertBeforeNode, | ||
finalizeInitialChildren: () => {}, | ||
supportsMutation: true, | ||
appendChildToContainer: _dom.appendChildNode, | ||
insertInContainerBefore: _dom.insertBeforeNode, | ||
removeChildFromContainer: _dom.removeChildNode, | ||
prepareUpdate: () => true, | ||
commitUpdate: (node, updatePayload, type, oldProps, newProps) => { | ||
for (const [key, value] of Object.entries(newProps)) { | ||
if (key === 'children') { | ||
if (typeof value === 'string' || typeof value === 'number') { | ||
if (type === 'div') { | ||
// Text node must be wrapped in another node, so that text can be aligned within container | ||
// If there's no such node, a new one must be created | ||
if (node.childNodes.length === 0) { | ||
const textElement = (0, _dom.createNode)('div'); | ||
textElement.textContent = String(value); | ||
(0, _dom.appendChildNode)(node, textElement); | ||
} else { | ||
node.childNodes[0].textContent = String(value); | ||
} | ||
} | ||
if (type === 'span') { | ||
node.textContent = String(value); | ||
} | ||
if (type === 'span') { | ||
node.textContent = String(value); | ||
} | ||
} else if (key === 'style') { | ||
Object.assign(node.style, value); | ||
} else if (key === 'unstable__transformChildren') { | ||
node.unstable__transformChildren = value; // eslint-disable-line camelcase | ||
} else if (key === 'unstable__static') { | ||
node.unstable__static = true; // eslint-disable-line camelcase | ||
} else { | ||
(0, _dom.setAttribute)(node, key, value); | ||
} | ||
} | ||
}, | ||
commitTextUpdate: (node, oldText, newText) => { | ||
if (node.nodeName === '#text') { | ||
node.nodeValue = newText; | ||
} else if (key === 'style') { | ||
Object.assign(node.style, value); | ||
} else if (key === 'unstable__transformChildren') { | ||
node.unstable__transformChildren = value; // eslint-disable-line camelcase | ||
} else if (key === 'unstable__static') { | ||
node.unstable__static = true; // eslint-disable-line camelcase | ||
} else { | ||
node.textContent = newText; | ||
(0, _dom.setAttribute)(node, key, value); | ||
} | ||
}, | ||
removeChild: _dom.removeChildNode | ||
}; | ||
return (0, _reactReconciler.default)(hostConfig); // eslint-disable-line new-cap | ||
} | ||
}, | ||
commitTextUpdate: (node, oldText, newText) => { | ||
if (node.nodeName === '#text') { | ||
node.nodeValue = newText; | ||
} else { | ||
node.textContent = newText; | ||
} | ||
}, | ||
removeChild: _dom.removeChildNode | ||
}; | ||
var _default = (0, _reactReconciler.default)(hostConfig); // eslint-disable-line new-cap | ||
exports.default = _default; |
@@ -8,3 +8,61 @@ "use strict"; | ||
// After nodes are laid out, render each to output object, which later gets rendered to terminal | ||
var _widestLine = _interopRequireDefault(require("widest-line")); | ||
var _wrapText = _interopRequireDefault(require("./wrap-text")); | ||
var _getMaxWidth = _interopRequireDefault(require("./get-max-width")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const isAllTextNodes = node => { | ||
if (node.nodeName === '#text') { | ||
return true; | ||
} | ||
if (node.nodeName === 'SPAN') { | ||
if (node.textContent) { | ||
return true; | ||
} | ||
if (Array.isArray(node.childNodes)) { | ||
return node.childNodes.every(isAllTextNodes); | ||
} | ||
} | ||
return false; | ||
}; // Squashing text nodes allows to combine multiple text nodes into one and write | ||
// to `Output` instance only once. For example, <Text>hello{' '}world</Text> | ||
// is actually 3 text nodes, which would result 3 writes to `Output`. | ||
// | ||
// Also, this is necessary for libraries like ink-link (https://github.com/sindresorhus/ink-link), | ||
// which need to wrap all children at once, instead of wrapping 3 text nodes separately. | ||
const squashTextNodes = node => { | ||
let text = ''; | ||
for (const childNode of node.childNodes) { | ||
let nodeText; | ||
if (childNode.nodeName === '#text') { | ||
nodeText = childNode.nodeValue; | ||
} | ||
if (childNode.nodeName === 'SPAN') { | ||
nodeText = childNode.textContent || squashTextNodes(childNode); | ||
} // Since these text nodes are being concatenated, `Output` instance won't be able to | ||
// apply children transform, so we have to do it manually here for each text node | ||
if (childNode.unstable__transformChildren) { | ||
nodeText = childNode.unstable__transformChildren(nodeText); | ||
} | ||
text += nodeText; | ||
} | ||
return text; | ||
}; // After nodes are laid out, render each to output object, which later gets rendered to terminal | ||
const renderNodeToOutput = (node, output, { | ||
@@ -32,8 +90,20 @@ offsetX = 0, | ||
newTransformers = [node.unstable__transformChildren, ...transformers]; | ||
} // Text nodes | ||
} // Nodes with only text inside | ||
const text = node.textContent || node.nodeValue; | ||
if (node.textContent) { | ||
let text = node.textContent; // Since text nodes are always wrapped in an additional node, parent node | ||
// is where we should look for attributes | ||
if (text) { | ||
if (node.parentNode.style.textWrap) { | ||
const currentWidth = (0, _widestLine.default)(text); | ||
const maxWidth = (0, _getMaxWidth.default)(node.parentNode.yogaNode); | ||
if (currentWidth > maxWidth) { | ||
text = (0, _wrapText.default)(text, maxWidth, { | ||
textWrap: node.parentNode.style.textWrap | ||
}); | ||
} | ||
} | ||
output.write(x, y, text, { | ||
@@ -43,2 +113,10 @@ transformers: newTransformers | ||
return; | ||
} // Text nodes | ||
if (node.nodeName === '#text') { | ||
output.write(x, y, node.nodeValue, { | ||
transformers: newTransformers | ||
}); | ||
return; | ||
} // Nodes that have other nodes as children | ||
@@ -48,25 +126,16 @@ | ||
if (Array.isArray(node.childNodes) && node.childNodes.length > 0) { | ||
// Squashing text nodes allows to combine multiple text nodes into one and write | ||
// to `Output` instance only once. For example, <Text>hello{' '}world</Text> | ||
// is actually 3 text nodes, which would result 3 writes to `Output`. | ||
// | ||
// Also, this is necessary for libraries like ink-link (https://github.com/sindresorhus/ink-link), | ||
// which need to wrap all children at once, instead of wrapping 3 text nodes separately. | ||
const isFlexDirectionColumn = node.style.flexDirection === 'column'; | ||
const isAllTextNodes = node.childNodes.every(childNode => { | ||
return Boolean(childNode.nodeValue) || childNode.nodeName === 'SPAN' && Boolean(childNode.textContent); | ||
}); | ||
const isFlexDirectionRow = node.style.flexDirection === 'row'; | ||
if (!isFlexDirectionColumn && isAllTextNodes) { | ||
let text = ''; | ||
if (isFlexDirectionRow && node.childNodes.every(isAllTextNodes)) { | ||
let text = squashTextNodes(node); | ||
for (const childNode of node.childNodes) { | ||
let nodeText = childNode.nodeValue || childNode.textContent; // Since these text nodes are being concatenated, `Output` instance won't be able to | ||
// apply children transform, so we have to do it manually here for each text node | ||
if (node.style.textWrap) { | ||
const currentWidth = (0, _widestLine.default)(text); | ||
const maxWidth = (0, _getMaxWidth.default)(yogaNode); | ||
if (childNode.unstable__transformChildren) { | ||
nodeText = childNode.unstable__transformChildren(nodeText); | ||
if (currentWidth > maxWidth) { | ||
text = (0, _wrapText.default)(text, maxWidth, { | ||
textWrap: node.style.textWrap | ||
}); | ||
} | ||
text += nodeText; | ||
} | ||
@@ -73,0 +142,0 @@ |
@@ -45,3 +45,3 @@ "use strict"; | ||
rerender: instance.render, | ||
unmount: instance.unmount, | ||
unmount: () => instance.unmount(), | ||
waitUntilExit: instance.waitUntilExit, | ||
@@ -48,0 +48,0 @@ cleanup: () => instances.delete(options.stdout) |
@@ -18,5 +18,47 @@ "use strict"; | ||
var _measureText = _interopRequireDefault(require("./measure-text")); | ||
var _wrapText = _interopRequireDefault(require("./wrap-text")); | ||
var _getMaxWidth = _interopRequireDefault(require("./get-max-width")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
// Since <Static> components can be placed anywhere in the tree, this helper finds and returns them | ||
// Since we need to know the width of text container to wrap text, we have to calculate layout twice | ||
// This function is executed after first layout calculation to reassign width and height of text nodes | ||
const calculateWrappedText = node => { | ||
if (node.textContent && typeof node.parentNode.style.textWrap === 'string') { | ||
const { | ||
yogaNode | ||
} = node; | ||
const parentYogaNode = node.parentNode.yogaNode; | ||
const maxWidth = (0, _getMaxWidth.default)(parentYogaNode); | ||
const currentWidth = yogaNode.getComputedWidth(); | ||
if (currentWidth > maxWidth) { | ||
const { | ||
textWrap | ||
} = node.parentNode.style; | ||
const wrappedText = (0, _wrapText.default)(node.textContent, maxWidth, { | ||
textWrap | ||
}); | ||
const { | ||
width, | ||
height | ||
} = (0, _measureText.default)(wrappedText); | ||
yogaNode.setWidth(width); | ||
yogaNode.setHeight(height); | ||
} | ||
return; | ||
} | ||
if (Array.isArray(node.childNodes) && node.childNodes.length > 0) { | ||
for (const childNode of node.childNodes) { | ||
calculateWrappedText(childNode); | ||
} | ||
} | ||
}; // Since <Static> components can be placed anywhere in the tree, this helper finds and returns them | ||
const getStaticNodes = element => { | ||
@@ -69,5 +111,3 @@ const staticNodes = []; | ||
const rootNode = (0, _dom.createNode)('root'); | ||
(0, _dom.appendStaticNode)(rootNode, staticElements[0], { | ||
woot: true | ||
}); | ||
(0, _dom.appendStaticNode)(rootNode, staticElements[0]); | ||
const { | ||
@@ -80,2 +120,4 @@ yogaNode: staticYogaNode | ||
}); | ||
staticYogaNode.calculateLayout(_yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.DIRECTION_LTR); | ||
calculateWrappedText(rootNode); | ||
staticYogaNode.calculateLayout(_yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.DIRECTION_LTR); // Save current Yoga node tree to free up memory later | ||
@@ -100,2 +142,4 @@ | ||
}); | ||
yogaNode.calculateLayout(_yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.DIRECTION_LTR); | ||
calculateWrappedText(node); | ||
yogaNode.calculateLayout(_yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.UNDEFINED, _yogaLayoutPrebuilt.default.DIRECTION_LTR); // Save current node tree to free up memory later | ||
@@ -102,0 +146,0 @@ |
@@ -123,4 +123,6 @@ import * as React from "react"; | ||
export interface BoxProps { | ||
readonly width?: number; | ||
readonly height?: number; | ||
readonly width?: number | string; | ||
readonly height?: number | string; | ||
readonly minWidth?: number; | ||
readonly minHeight?: number; | ||
readonly paddingTop?: number; | ||
@@ -143,2 +145,3 @@ readonly paddingBottom?: number; | ||
readonly flexDirection?: "row" | "row-reverse" | "column" | "column-reverse"; | ||
readonly flexBasis?: string | number; | ||
readonly alignItems?: "flex-start" | "center" | "flex-end"; | ||
@@ -151,2 +154,8 @@ readonly justifyContent?: | ||
| "space-around"; | ||
readonly textWrap?: | ||
| "wrap" | ||
| "truncate" | ||
| "truncate-start" | ||
| "truncate-middle" | ||
| "truncate-end"; | ||
} | ||
@@ -185,3 +194,3 @@ | ||
*/ | ||
readonly exit: () => void; | ||
readonly exit: (error?: Error) => void; | ||
}>; | ||
@@ -188,0 +197,0 @@ |
{ | ||
"name": "ink", | ||
"version": "2.0.6", | ||
"version": "2.1.0", | ||
"description": "React for CLI", | ||
@@ -48,2 +48,4 @@ "license": "MIT", | ||
"cli-cursor": "^2.1.0", | ||
"cli-truncate": "^1.1.0", | ||
"is-ci": "^2.0.0", | ||
"lodash.throttle": "^4.1.1", | ||
@@ -54,5 +56,7 @@ "log-update": "^3.0.0", | ||
"scheduler": "^0.13.2", | ||
"signal-exit": "^3.0.2", | ||
"slice-ansi": "^1.0.0", | ||
"string-length": "^2.0.0", | ||
"widest-line": "^2.0.0", | ||
"wrap-ansi": "^5.0.0", | ||
"yoga-layout-prebuilt": "^1.9.3" | ||
@@ -78,2 +82,3 @@ }, | ||
"sinon": "^7.2.7", | ||
"strip-ansi": "^5.2.0", | ||
"svg-term-cli": "^2.1.1", | ||
@@ -80,0 +85,0 @@ "xo": "^0.24.0" |
@@ -282,2 +282,76 @@ <h1 align="center"> | ||
##### Dimensions | ||
###### width | ||
Type: `number`, `string` | ||
Width of the element in spaces. You can also set it in percent, which will calculate the width based on the width of parent element. | ||
```jsx | ||
<Box width={4}>X</Box> //=> 'X ' | ||
``` | ||
```jsx | ||
<Box width={10}> | ||
<Box width="50%">X</Box> | ||
Y | ||
</Box> //=> 'X Y' | ||
``` | ||
###### height | ||
Type: `number`, `string` | ||
Height of the element in lines (rows). You can also set it in percent, which will calculate the height based on the height of parent element. | ||
```jsx | ||
<Box height={4}>X</Box> //=> 'X\n\n\n' | ||
``` | ||
```jsx | ||
<Box height={6} flexDirection="column"> | ||
<Box height="50%">X</Box> | ||
Y | ||
</Box> //=> 'X\n\n\nY\n\n' | ||
``` | ||
###### minWidth | ||
Type: `number` | ||
Sets a minimum width of the element. Percentages aren't supported yet, see https://github.com/facebook/yoga/issues/872. | ||
###### minHeight | ||
Type: `number` | ||
Sets a minimum height of the element. Percentages aren't supported yet, see https://github.com/facebook/yoga/issues/872. | ||
##### Wrapping | ||
###### textWrap | ||
Type: `string`<br> | ||
Values: `wrap` `truncate` `truncate-start` `truncate-middle` `truncate-end` | ||
This property tells Ink to wrap or truncate text content of `<Box>` if its width is larger than container. If `wrap` is passed, Ink will wrap text and split it into multiple lines. If `truncate-*` is passed, Ink will truncate text instead, which will result in one line of text with the rest cut off. | ||
*Note:* Ink doesn't wrap text by default. | ||
```jsx | ||
<Box textWrap="wrap">Hello World</Box> | ||
//=> 'Hello\nWorld' | ||
// `truncate` is an alias to `truncate-end` | ||
<Box textWrap="truncate">Hello World</Box> | ||
//=> 'Hello…' | ||
<Box textWrap="truncate-middle">Hello World</Box> | ||
//=> 'He…ld' | ||
<Box textWrap="truncate-start">Hello World</Box> | ||
//=> '…World' | ||
``` | ||
##### Padding | ||
@@ -413,2 +487,22 @@ | ||
###### flexBasis | ||
Type: `number`, `string`<br> | ||
See [flex-basis](https://css-tricks.com/almanac/properties/f/flex-basis/). | ||
```jsx | ||
<Box width={6}> | ||
<Box flexBasis={3}>X</Box> | ||
Y | ||
</Box> //=> 'X Y' | ||
``` | ||
```jsx | ||
<Box width={6}> | ||
<Box flexBasis="50%">X</Box> | ||
Y | ||
</Box> //=> 'X Y' | ||
``` | ||
###### flexDirection | ||
@@ -643,2 +737,4 @@ | ||
If `exit` is called with an Error, `waitUntilExit` will reject with that error. | ||
#### `<StdinContext>` | ||
@@ -645,0 +741,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
83476
27
1577
869
19
20
+ Addedcli-truncate@^1.1.0
+ Addedis-ci@^2.0.0
+ Addedsignal-exit@^3.0.2
+ Addedwrap-ansi@^5.0.0
+ Addedci-info@2.0.0(transitive)
+ Addedcli-truncate@1.1.0(transitive)
+ Addedis-ci@2.0.0(transitive)