Skip to content

Commit 61d7214

Browse files
authored
feat(browser-repl): allow to render browser-repl in light mode (#2061)
1 parent 855e4cf commit 61d7214

File tree

5 files changed

+97
-49
lines changed

5 files changed

+97
-49
lines changed

packages/browser-repl/src/components/password-prompt.tsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
import React, { Component } from 'react';
2-
import { css, palette, fontFamilies } from '@mongodb-js/compass-components';
2+
import { css, fontFamilies, TextInput } from '@mongodb-js/compass-components';
33

44
const passwordPrompt = css({
55
paddingLeft: 23,
66
'& input': {
7-
fontSize: '13px',
8-
lineHeight: '24px',
97
fontFamily: fontFamilies.code,
10-
backgroundColor: palette.gray.dark4,
11-
color: palette.gray.light3,
12-
padding: '0 3px',
13-
border: `1px solid ${palette.gray.light3}`,
14-
borderRadius: 3,
158
},
169
});
1710

11+
const passwordPropmtInputStyles = css({
12+
display: 'inline-block',
13+
});
14+
1815
interface PasswordPromptProps {
1916
onFinish: (result: string) => void;
2017
onCancel: () => void;
@@ -42,9 +39,16 @@ export class PasswordPrompt extends Component<PasswordPromptProps> {
4239

4340
render(): JSX.Element {
4441
return (
45-
<label className={passwordPrompt}>
42+
<label id="password-promt-label" className={passwordPrompt}>
4643
{this.props.prompt}:&nbsp;
47-
<input type="password" onKeyDown={this.onKeyDown} autoFocus />
44+
<TextInput
45+
aria-labelledby="password-promt-label"
46+
type="password"
47+
onKeyDown={this.onKeyDown}
48+
className={passwordPropmtInputStyles}
49+
sizeVariant="xsmall"
50+
autoFocus
51+
></TextInput>
4852
</label>
4953
);
5054
}

packages/browser-repl/src/components/shell-loader.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
import React, { Component } from 'react';
2-
import { SpinLoader, css, palette } from '@mongodb-js/compass-components';
3-
4-
// TODO: Add dark mode to compass components spinner
5-
const shellLoader = css({
6-
'& div': { borderTopColor: palette.green.light2 },
7-
});
2+
import { SpinLoader } from '@mongodb-js/compass-components';
83

94
interface ShellLoaderProps {
105
size?: string;
@@ -18,7 +13,7 @@ export default class ShellLoader extends Component<ShellLoaderProps> {
1813
render() {
1914
const { size } = this.props;
2015
return (
21-
<div className={shellLoader}>
16+
<div>
2217
<SpinLoader size={size} />
2318
</div>
2419
);

packages/browser-repl/src/components/shell.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { expect } from '../../testing/chai';
44
import type { ReactWrapper, ShallowWrapper } from '../../testing/enzyme';
55
import { mount, shallow } from '../../testing/enzyme';
66
import { PasswordPrompt } from './password-prompt';
7-
import { Shell } from './shell';
7+
import { _Shell as Shell } from './shell';
88
import { ShellInput } from './shell-input';
99
import { ShellOutput } from './shell-output';
1010
import type { ShellOutputEntry } from './shell-output-line';

packages/browser-repl/src/components/shell.tsx

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import React, { Component } from 'react';
22
import type { EditorRef } from '@mongodb-js/compass-editor';
33
import {
44
css,
5-
ThemeProvider,
6-
Theme,
75
palette,
86
fontFamilies,
7+
useDarkMode,
8+
cx,
99
} from '@mongodb-js/compass-components';
1010
import type { Runtime } from '@mongosh/browser-runtime-core';
1111
import { changeHistory } from '@mongosh/history';
@@ -19,8 +19,6 @@ const shellContainer = css({
1919
fontSize: '13px',
2020
lineHeight: '24px',
2121
fontFamily: fontFamilies.code,
22-
backgroundColor: palette.gray.dark4,
23-
color: palette.gray.light3,
2422
padding: '4px 0',
2523
width: '100%',
2624
height: '100%',
@@ -46,6 +44,16 @@ const shellContainer = css({
4644
},
4745
});
4846

47+
const shellContainerLightModeStyles = css({
48+
backgroundColor: palette.white,
49+
color: palette.black,
50+
});
51+
52+
const shellContainerDarkModeStyles = css({
53+
backgroundColor: palette.gray.dark4,
54+
color: palette.gray.light3,
55+
});
56+
4957
interface ShellProps {
5058
/* The runtime used to evaluate code.
5159
*/
@@ -118,6 +126,10 @@ interface ShellProps {
118126
* Note: new entries will not be appended to the array.
119127
*/
120128
initialHistory: readonly string[];
129+
130+
darkMode?: boolean;
131+
132+
className?: string;
121133
}
122134

123135
interface ShellState {
@@ -135,7 +147,7 @@ const noop = (): void => {
135147
/**
136148
* The browser-repl Shell component
137149
*/
138-
export class Shell extends Component<ShellProps, ShellState> {
150+
export class _Shell extends Component<ShellProps, ShellState> {
139151
static defaultProps = {
140152
onHistoryChanged: noop,
141153
onOperationStarted: noop,
@@ -422,24 +434,38 @@ export class Shell extends Component<ShellProps, ShellState> {
422434

423435
render(): JSX.Element {
424436
return (
425-
<ThemeProvider theme={{ theme: Theme.Dark, enabled: true }}>
437+
<div
438+
data-testid="shell"
439+
className={cx(
440+
shellContainer,
441+
this.props.darkMode
442+
? shellContainerDarkModeStyles
443+
: shellContainerLightModeStyles,
444+
this.props.className
445+
)}
446+
onClick={this.onShellClicked}
447+
>
448+
<div>
449+
<ShellOutput output={this.state.output} />
450+
</div>
426451
<div
427-
data-testid="shell"
428-
className={shellContainer}
429-
onClick={this.onShellClicked}
452+
ref={(el): void => {
453+
this.shellInputElement = el;
454+
}}
430455
>
431-
<div>
432-
<ShellOutput output={this.state.output} />
433-
</div>
434-
<div
435-
ref={(el): void => {
436-
this.shellInputElement = el;
437-
}}
438-
>
439-
{this.renderInput()}
440-
</div>
456+
{this.renderInput()}
441457
</div>
442-
</ThemeProvider>
458+
</div>
443459
);
444460
}
445461
}
462+
463+
type DefaultProps = keyof (typeof _Shell)['defaultProps'];
464+
465+
export const Shell = function ShellWithDarkMode(
466+
props: Omit<ShellProps, DefaultProps | 'darkMode'> &
467+
Partial<Pick<ShellProps, DefaultProps>>
468+
) {
469+
const darkMode = useDarkMode();
470+
return <_Shell darkMode={darkMode} {...props}></_Shell>;
471+
};

packages/browser-repl/src/sandbox.tsx

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import ReactDOM from 'react-dom';
22
import React, { useEffect, useMemo, useState } from 'react';
33
import {
44
css,
5+
ThemeProvider,
6+
Theme,
57
Description,
68
FormFieldContainer,
79
Label,
@@ -151,6 +153,7 @@ class DemoServiceProvider {
151153
const runtime = new IframeRuntime(new DemoServiceProvider() as any);
152154

153155
const IframeRuntimeExample: React.FunctionComponent = () => {
156+
const [darkMode, setDarkMode] = useState(true);
154157
const [redactInfo, setRedactInfo] = useState(false);
155158
const [maxOutputLength, setMaxOutputLength] = useState(1000);
156159
const [maxHistoryLength, setMaxHistoryLength] = useState(1000);
@@ -163,6 +166,8 @@ const IframeRuntimeExample: React.FunctionComponent = () => {
163166
'show dbs',
164167
'db.coll.stats()',
165168
'{x: 1, y: {z: 2}, k: [1, 2, 3]}',
169+
'passwordPrompt()',
170+
'(() => { throw new Error("Whoops!"); })()',
166171
]);
167172

168173
useEffect(() => {
@@ -179,19 +184,37 @@ const IframeRuntimeExample: React.FunctionComponent = () => {
179184
return (
180185
<div className={sandboxContainer}>
181186
<div className={shellContainer}>
182-
<Shell
183-
key={key}
184-
runtime={runtime}
185-
redactInfo={redactInfo}
186-
maxOutputLength={maxOutputLength}
187-
maxHistoryLength={maxHistoryLength}
188-
initialInput={initialInput}
189-
initialEvaluate={initialEvaluate.filter(Boolean)}
190-
initialOutput={initialOutput}
191-
initialHistory={initialHistory.filter(Boolean)}
192-
/>
187+
<ThemeProvider
188+
theme={{ theme: darkMode ? Theme.Dark : Theme.Light, enabled: true }}
189+
>
190+
<Shell
191+
key={key}
192+
runtime={runtime}
193+
redactInfo={redactInfo}
194+
maxOutputLength={maxOutputLength}
195+
maxHistoryLength={maxHistoryLength}
196+
initialInput={initialInput}
197+
initialEvaluate={initialEvaluate.filter(Boolean)}
198+
initialOutput={initialOutput}
199+
initialHistory={initialHistory.filter(Boolean)}
200+
/>
201+
</ThemeProvider>
193202
</div>
194203
<div className={controlsContainer}>
204+
<FormFieldContainer className={formField}>
205+
<Label id="darkModeLabel" htmlFor="darkMode">
206+
darkMode
207+
</Label>
208+
<Description>Toggle shell dark mode</Description>
209+
<Toggle
210+
aria-labelledby="darkModeLabel"
211+
id="darkMode"
212+
size="small"
213+
checked={darkMode}
214+
onChange={setDarkMode}
215+
/>
216+
</FormFieldContainer>
217+
195218
<FormFieldContainer className={formField}>
196219
<Label id="redactInfoLabel" htmlFor="redactInfo">
197220
redactInfo

0 commit comments

Comments
 (0)