Skip to content

Commit

Permalink
Fancy playground editor (#498)
Browse files Browse the repository at this point in the history
* Factor out Editor component.

* Use Ace editor.

* Working tests using Ace editor.

* Styling.
  • Loading branch information
torhovland authored Jun 7, 2023
1 parent fc26dc5 commit 61d076c
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 32 deletions.
35 changes: 16 additions & 19 deletions web-playground/e2e/sample-tester.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ describe('test all grammars with puppeteer', () => {
const button = await page.$('#formatButton') ?? fail('Did not find button');
await button.click();

await waitForOutput(page, "#output");
const output = await readOutput();

// Useful for debugging:
Expand All @@ -110,7 +109,6 @@ async function testInputFile(input: string, expected: string, query: string, lan
const button = await page.$('#formatButton') ?? fail('Did not find button');
await button.click();

await waitForOutput(page, "#output");
const output = await readOutput();

// Useful for debugging:
Expand All @@ -120,38 +118,37 @@ async function testInputFile(input: string, expected: string, query: string, lan
}

async function setTextarea(selector: string, text: string) {
let textInput = await page.$(selector) ?? fail('Did not find text area');
let textInput = await page.$(selector) ?? fail('Did not find text input control');
let textAreaSelector = `${selector} textarea`;

// Clear the text area first, otherwise the following doesn't work.
await textInput.click({ clickCount: 3 });
await textInput.click();
await page.keyboard.down('ControlLeft')
await page.keyboard.press('KeyA')
await page.keyboard.up('ControlLeft')
await textInput.press('Backspace');

// Quick way to enter text into a field. See https://github.com/puppeteer/puppeteer/issues/4192
await page.evaluate((selector, text) => {
(<HTMLInputElement>document.querySelector(selector)).value = text;
}, selector, text);
}, textAreaSelector, text);

// Without this hack, the textarea simply won't get updated.
await page.keyboard.type("X");
await textInput.press('Backspace');
}

async function readOutput() {
const outputElement = await page.$("#output");
return await page.evaluate(element => element?.textContent, outputElement);
}

const waitForOutput = async (
page: Page,
selector: string,
options: FrameWaitForFunctionOptions = { polling: "mutation", timeout: 30000 }
) => {
const el = typeof selector === "string" ?
(await page.waitForSelector(selector)) : selector;
const outputSelector = "#rawOutput";
const el = await page.waitForSelector(outputSelector);

return page.waitForFunction(
// Wait for useful output.
await page.waitForFunction(
el => el?.textContent !== "" && el?.textContent !== "Formatting ...",
options,
{ polling: "mutation", timeout: 30000 },
el
);
};

const outputElement = await page.$(outputSelector);
return await page.evaluate(element => element?.textContent, outputElement);
}
82 changes: 73 additions & 9 deletions web-playground/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion web-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"private": true,
"homepage": "/playground",
"dependencies": {
"ace-builds": "^1.22.0",
"react": "^18.2.0",
"react-ace": "^10.1.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
Expand Down Expand Up @@ -52,4 +54,4 @@
"last 1 safari version"
]
}
}
}
4 changes: 4 additions & 0 deletions web-playground/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,7 @@ button:not(:disabled) {
border-color: #c792fa;
color: #212529;
}

.hidden {
display: none;
}
8 changes: 5 additions & 3 deletions web-playground/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ReactElement, useCallback, useEffect, useRef, useState } from "react";
import Editor from "./components/editor";
import useDebounce from "./hooks/useDebounce";
import languages from './samples/languages_export';
import init, {
Expand Down Expand Up @@ -142,15 +143,16 @@ function App() {
<div className="columns">
<div className="column">
<h1>Query</h1>
<textarea id="query" value={query} onChange={e => setQuery(e.target.value)} />
<Editor id="query" value={query} onChange={s => setQuery(s)} placeholder="Enter your query here ..." />
</div>
<div className="column">
<h1>Input</h1>
<textarea id="input" value={input} onChange={e => setInput(e.target.value)} />
<Editor id="input" value={input} onChange={s => setInput(s)} placeholder="Enter your input here ..." />
</div>
<div className="column">
<h1>Output</h1>
<textarea id="output" value={output} readOnly></textarea>
<Editor id="output" value={output} readOnly placeholder="The formatted code will appear here ..." />
<textarea id="rawOutput" value={output} readOnly className="hidden"></textarea>
</div>
</div>
</div>
Expand Down
32 changes: 32 additions & 0 deletions web-playground/src/components/editor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import AceEditor from "react-ace";

import "ace-builds/src-noconflict/ext-language_tools";
import "ace-builds/src-noconflict/mode-plain_text";
import "ace-builds/src-noconflict/theme-clouds.js";

export default function Editor(props: {
id: string,
value: string,
placeholder: string,
readOnly?: boolean,
onChange?: (value: string) => void
}) {
return (
<AceEditor
mode="plain_text"
theme="clouds"
name={props.id}
value={props.value}
placeholder={props.placeholder}
readOnly={props.readOnly}
onChange={props.onChange}
width="100%"
height="100%"
tabSize={2}
enableBasicAutocompletion={true}
enableLiveAutocompletion={true}
enableSnippets={true}
/>
)
}

0 comments on commit 61d076c

Please sign in to comment.