Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/browser-repl/src/components/ace-theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const foregroundColor = uiColors.gray.light3;
const backgroundColor = uiColors.gray.dark3;
const borderColor = uiColors.gray.dark1;
const activeLineColor = uiColors.gray.dark2;
const selectionColor = uiColors.gray.dark1;

const cursorColor = uiColors.green.base;

Expand Down Expand Up @@ -40,7 +41,7 @@ const layoutCss = `
background: transparent;
}
.ace-mongosh .ace_marker-layer .ace_selection {
background: transparent;
background: ${selectionColor};
}
`;

Expand Down
10 changes: 10 additions & 0 deletions packages/browser-repl/src/components/editor.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,14 @@ describe('<Editor />', () => {
execCommandBoundTo(aceEditor, 'Down');
expect(spy).not.to.have.been.called;
});

it('sets the input ref for the editor', () => {
const spy = sinon.spy();
const wrapper = mount(<Editor setInputRef={spy} />);

const aceEditor = getAceEditorInstance(wrapper);

expect(spy).to.have.been.calledOnce;
expect(spy.args[0][0].editor).to.equal(aceEditor);
});
});
7 changes: 7 additions & 0 deletions packages/browser-repl/src/components/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface EditorProps {
onArrowDownOnLastLine?(): void | Promise<void>;
onChange?(value: string): void | Promise<void>;
autocompleter?: Autocompleter;
setInputRef?(ref): void;
value?: string;
}

Expand All @@ -30,6 +31,7 @@ export class Editor extends Component<EditorProps> {
onArrowUpOnFirstLine: PropTypes.func,
onArrowDownOnLastLine: PropTypes.func,
onChange: PropTypes.func,
setInputRef: PropTypes.func,
value: PropTypes.string
};

Expand Down Expand Up @@ -71,6 +73,11 @@ export class Editor extends Component<EditorProps> {
}}
name={`mongosh-ace-${Date.now()}`}
mode="javascript"
ref={(ref: any): void => {
if (this.props.setInputRef) {
this.props.setInputRef(ref);
}
}}
theme="mongosh"
onChange={this.props.onChange}
onLoad={this.onEditorLoad}
Expand Down
5 changes: 4 additions & 1 deletion packages/browser-repl/src/components/shell-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface ShellInputProps {
onInput?(code: string): void | Promise<void>;
history?: readonly string[];
autocompleter?: Autocompleter;
setInputRef?(ref): void;
}

interface ShellInputState {
Expand All @@ -22,7 +23,8 @@ export class ShellInput extends Component<ShellInputProps, ShellInputState> {
static propTypes = {
onInput: PropTypes.func,
history: PropTypes.arrayOf(PropTypes.string),
autocompleter: PropTypes.object
autocompleter: PropTypes.object,
setInputRef: PropTypes.func
};

readonly state: ShellInputState = {
Expand Down Expand Up @@ -120,6 +122,7 @@ export class ShellInput extends Component<ShellInputProps, ShellInputState> {
onArrowUpOnFirstLine={this.historyBack}
onArrowDownOnLastLine={this.historyNext}
autocompleter={this.props.autocompleter}
setInputRef={this.props.setInputRef}
/>);

const className = classnames(styles['shell-input']);
Expand Down
31 changes: 31 additions & 0 deletions packages/browser-repl/src/components/shell.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { ShellInput } from './shell-input';
import { ShellOutput } from './shell-output';
import { ShellOutputEntry } from './shell-output-line';

const styles = require('./shell.less');

const wait: (ms?: number) => Promise<void> = (ms = 10) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};
Expand All @@ -17,6 +19,7 @@ describe('<Shell />', () => {
let fakeRuntime;
let wrapper: ShallowWrapper | ReactWrapper;
let scrollIntoView;
let elementFocus;
let onInput;

beforeEach(() => {
Expand All @@ -27,6 +30,7 @@ describe('<Shell />', () => {
};

scrollIntoView = sinon.spy(Element.prototype, 'scrollIntoView');
elementFocus = sinon.spy(HTMLElement.prototype, 'focus');

fakeRuntime = {
evaluate: sinon.fake.returns({ value: 'some result' })
Expand All @@ -43,6 +47,7 @@ describe('<Shell />', () => {

afterEach(() => {
scrollIntoView.restore();
elementFocus.restore();
});

it('renders a ShellOutput component', () => {
Expand Down Expand Up @@ -265,4 +270,30 @@ describe('<Shell />', () => {

expect(Element.prototype.scrollIntoView).to.have.been.calledTwice;
});

it('focuses on the input when the background container is clicked', () => {
wrapper = mount(<Shell runtime={fakeRuntime} />);
const container = wrapper.find(`.${styles.shell}`);

const fakeMouseEvent: any = {
target: 'a',
currentTarget: 'a'
};
container.prop('onClick')(fakeMouseEvent);

expect(HTMLElement.prototype.focus).to.have.been.calledOnce;
});

it('does not focus on the input when an element that is not the background container is clicked', () => {
wrapper = mount(<Shell runtime={fakeRuntime} />);
const container = wrapper.find(`.${styles.shell}`);

const fakeMouseEvent: any = {
target: 'a',
currentTarget: 'b'
};
container.prop('onClick')(fakeMouseEvent);

expect(HTMLElement.prototype.focus).to.not.have.been.called;
});
});
41 changes: 30 additions & 11 deletions packages/browser-repl/src/components/shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ export class Shell extends Component<ShellProps, ShellState> {
};

private shellInputElement?: HTMLElement;
private shellInputRef?: {
editor?: HTMLElement;
};

readonly state: ShellState = {
output: this.props.initialOutput.slice(-this.props.maxOutputLength),
Expand Down Expand Up @@ -188,18 +191,34 @@ export class Shell extends Component<ShellProps, ShellState> {
this.shellInputElement.scrollIntoView();
}

private onShellClicked = (event: React.MouseEvent): void => {
// Focus on input when clicking the shell background (not clicking output).
if (event.currentTarget === event.target) {
if (this.shellInputRef && this.shellInputRef.editor) {
this.shellInputRef.editor.focus();
}
}
};

render(): JSX.Element {
return (<div className={classnames(styles.shell)}>
<div>
<ShellOutput
output={this.state.output} />
</div>
<div ref={(el): void => { this.shellInputElement = el; }}>
<ShellInput
onInput={this.onInput}
history={this.state.history}
autocompleter={this.props.runtime} />
return (
<div
className={classnames(styles.shell)}
onClick={this.onShellClicked}
>
<div>
<ShellOutput
output={this.state.output} />
</div>
<div ref={(el): void => { this.shellInputElement = el; }}>
<ShellInput
onInput={this.onInput}
history={this.state.history}
autocompleter={this.props.runtime}
setInputRef={(ref): void => { this.shellInputRef = ref;}}
/>
</div>
</div>
</div>);
);
}
}