Skip to content
Permalink
Browse files

Keep track of components which requested raw mode

  • Loading branch information...
vadimdemedes committed Mar 8, 2019
1 parent a897736 commit 321aa1eac51a76eec40efcff1286f71d08cc5019
Showing with 91 additions and 6 deletions.
  1. +22 −4 src/components/App.js
  2. +69 −2 test/components.js
@@ -17,6 +17,14 @@ export default class App extends PureComponent {
onExit: PropTypes.func.isRequired
};

constructor() {
super();

// Count how many components enabled raw mode to avoid disabling
// raw mode until all components don't need it anymore
this.rawModeEnabledCount = 0;
}

render() {
return (
<AppContext.Provider
@@ -55,12 +63,22 @@ export default class App extends PureComponent {
const {stdin} = this.props;

stdin.setEncoding('utf8');
stdin.setRawMode(isEnabled);

if (isEnabled) {
stdin.addListener('data', this.handleInput);
stdin.resume();
} else {
// Ensure raw mode is enabled only once
if (this.rawModeEnabledCount === 0) {
stdin.addListener('data', this.handleInput);
stdin.resume();
stdin.setRawMode(true);
}

this.rawModeEnabledCount++;
return;
}

// Disable raw mode only when no components left that are using it
if (--this.rawModeEnabledCount === 0) {
stdin.setRawMode(false);
stdin.removeListener('data', this.handleInput);
stdin.pause();
}
@@ -1,8 +1,10 @@
/* eslint-disable react/prop-types */
import EventEmitter from 'events';
import React, {useState} from 'react';
import test from 'ava';
import chalk from 'chalk';
import {spy} from 'sinon';
import {Box, Color, Static, render} from '..';
import {Box, Color, Static, StdinContext, render} from '..';
import renderToString from './helpers/render-to-string';

test('text', t => {
@@ -132,7 +134,7 @@ test('replace child node with text', t => {
columns: 100
};

const Dynamic = ({replace}) => ( // eslint-disable-line react/prop-types
const Dynamic = ({replace}) => (
<Box>
{replace ? 'x' : <Color green>test</Color>}
</Box>
@@ -148,3 +150,68 @@ test('replace child node with text', t => {
rerender(<Dynamic replace/>);
t.is(stdout.write.lastCall.args[0], 'x');
});

// See https://github.com/vadimdemedes/ink/issues/145
test('disable raw mode when all input components are unmounted', t => {
const stdout = {
write: spy(),
columns: 100
};

const stdin = new EventEmitter();
stdin.setEncoding = () => {};
stdin.setRawMode = spy();
stdin.resume = spy();
stdin.pause = spy();

const options = {
stdout,
stdin,
debug: true
};

class Input extends React.Component {
render() {
return <Box>Test</Box>;
}

componentDidMount() {
this.props.setRawMode(true);
}

componentWillUnmount() {
this.props.setRawMode(false);
}
}

const Test = ({renderFirstInput, renderSecondInput}) => (
<StdinContext.Consumer>
{({setRawMode}) => (
<>
{renderFirstInput && <Input setRawMode={setRawMode}/>}
{renderSecondInput && <Input setRawMode={setRawMode}/>}
</>
)}
</StdinContext.Consumer>
);

const {rerender} = render(<Test renderFirstInput renderSecondInput/>, options);

t.true(stdin.setRawMode.calledOnce);
t.deepEqual(stdin.setRawMode.firstCall.args, [true]);
t.true(stdin.resume.calledOnce);
t.false(stdin.pause.called);

rerender(<Test renderFirstInput/>);

t.true(stdin.setRawMode.calledOnce);
t.true(stdin.resume.calledOnce);
t.false(stdin.pause.called);

rerender(<Test/>);

t.true(stdin.setRawMode.calledTwice);
t.deepEqual(stdin.setRawMode.lastCall.args, [false]);
t.true(stdin.resume.calledOnce);
t.true(stdin.pause.calledOnce);
});

0 comments on commit 321aa1e

Please sign in to comment.
You can’t perform that action at this time.