aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--package.json2
-rw-r--r--src/components/InputTypes/Code.tsx11
-rw-r--r--src/components/InputTypes/code/Code.tsx74
-rw-r--r--src/components/InputTypes/code/prism_css.tsx194
-rw-r--r--src/components/InputTypes/index.tsx8
-rw-r--r--yarn.lock43
6 files changed, 319 insertions, 13 deletions
diff --git a/package.json b/package.json
index 0ebf702..65687a1 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"fs-extra": "9.1.0",
"html-webpack-plugin": "5.2.0",
"identity-obj-proxy": "3.0.0",
+ "prismjs": "1.23.0",
"react": "17.0.1",
"react-app-polyfill": "2.0.0",
"react-dom": "17.0.1",
@@ -59,6 +60,7 @@
"@testing-library/user-event": "12.7.2",
"@types/jest": "26.0.20",
"@types/node": "14.14.31",
+ "@types/prismjs": "1.16.3",
"@types/react": "17.0.1",
"@types/react-dom": "17.0.1",
"@types/react-router-dom": "5.1.7",
diff --git a/src/components/InputTypes/Code.tsx b/src/components/InputTypes/Code.tsx
deleted file mode 100644
index 51ca98d..0000000
--- a/src/components/InputTypes/Code.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-/** @jsx jsx */
-import { jsx } from "@emotion/react";
-import React, { ChangeEvent } from "react";
-
-interface CodeProps {
- handler: (event: ChangeEvent<HTMLInputElement>) => void
-}
-
-export default function Code(props: CodeProps): JSX.Element {
- return <input type="text" className="text" onChange={props.handler}/>;
-}
diff --git a/src/components/InputTypes/code/Code.tsx b/src/components/InputTypes/code/Code.tsx
new file mode 100644
index 0000000..31b82f0
--- /dev/null
+++ b/src/components/InputTypes/code/Code.tsx
@@ -0,0 +1,74 @@
+/** @jsx jsx */
+import { jsx, css } from "@emotion/react";
+import React, { ChangeEvent } from "react";
+
+import prismStyles from "./prism_css";
+import Prism from 'prismjs';
+
+/**
+ * For supported languages, and language codes, see:
+ * https://prismjs.com/#supported-languages
+ */
+interface CodeProps {
+ handler: (event: ChangeEvent<HTMLInputElement>) => void,
+ language: string,
+}
+
+const blockStyles = css`
+ pre[class*="language-"] {
+ min-height: 20rem;
+ height: 100%;
+ width: 100%;
+ box-sizing: border-box;
+
+ resize: vertical;
+ padding: 1rem;
+ background: whitesmoke;
+
+ color: black;
+ font-family: Hind, Helvetica, Arial, sans-serif;
+
+ margin: auto;
+
+ border: 0.1rem solid black;
+ border-radius: 8px;
+ font-size: 1rem;
+ }
+`;
+
+const textareaStyles = css`
+ position: absolute;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ opacity: 0;
+ resize: none;
+
+ font-family: Hind, Helvetica, Arial, sans-serif;
+ padding: 1rem;
+ box-sizing: border-box;
+ font-size: 1rem;
+ border: 0.1rem solid transparent;
+ border-radius: 8px;
+`;
+
+export default class Code extends React.Component<CodeProps> {
+ constructor(props: CodeProps) {
+ super(props);
+ }
+
+ render() {
+ const ref: React.RefObject<HTMLInputElement> = React.createRef();
+ const placeholder = "print(\"hello world\")"
+
+ return <div css={[prismStyles, blockStyles, css`position: relative;`]}>
+ <pre className="language-js">
+ <code className="language-js" ref={ref}>{placeholder}</code>
+ </pre>
+ <textarea css={textareaStyles} onChange={event => {
+ ref.current!.textContent = event.target.value || placeholder;
+ Prism.highlightElement(ref.current!);
+ }}/>
+ </div>
+ }
+}
diff --git a/src/components/InputTypes/code/prism_css.tsx b/src/components/InputTypes/code/prism_css.tsx
new file mode 100644
index 0000000..7e45b41
--- /dev/null
+++ b/src/components/InputTypes/code/prism_css.tsx
@@ -0,0 +1,194 @@
+/* PrismJS 1.23.0
+https://prismjs.com/download.html#themes=prism&languages=python&plugins=line-numbers+autoloader+keep-markup+normalize-whitespace */
+/**
+ * prism.js default theme for JavaScript, CSS and HTML
+ * Based on dabblet (http://dabblet.com)
+ * @author Lea Verou
+ */
+
+/** @jsx jsx */
+import { css } from "@emotion/react";
+
+// Note: this file is a mostly unmodified version of the auto generated Prism CSS.
+// To update, you just need to paste the new css below, and update the link at the top.
+
+export default css`
+ code[class*="language-"],
+ pre[class*="language-"] {
+ color: black;
+ background: none;
+ text-shadow: 0 1px white;
+ font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+ font-size: 1em;
+ text-align: left;
+ white-space: pre;
+ word-spacing: normal;
+ word-break: normal;
+ word-wrap: normal;
+ line-height: 1.5;
+
+ -moz-tab-size: 4;
+ -o-tab-size: 4;
+ tab-size: 4;
+
+ -webkit-hyphens: none;
+ -moz-hyphens: none;
+ -ms-hyphens: none;
+ hyphens: none;
+ }
+
+ pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
+ code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
+ text-shadow: none;
+ background: #b3d4fc;
+ }
+
+ pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
+ code[class*="language-"]::selection, code[class*="language-"] ::selection {
+ text-shadow: none;
+ background: #b3d4fc;
+ }
+
+ @media print {
+ code[class*="language-"],
+ pre[class*="language-"] {
+ text-shadow: none;
+ }
+ }
+
+ /* Code blocks */
+
+ pre[class*="language-"] {
+ padding: 1em;
+ margin: .5em 0;
+ overflow: auto;
+ }
+
+ :not(pre) > code[class*="language-"],
+ pre[class*="language-"] {
+ background: #f5f2f0;
+ }
+
+ /* Inline code */
+
+ :not(pre) > code[class*="language-"] {
+ padding: .1em;
+ border-radius: .3em;
+ white-space: normal;
+ }
+
+ .token.comment,
+ .token.prolog,
+ .token.doctype,
+ .token.cdata {
+ color: slategray;
+ }
+
+ .token.punctuation {
+ color: #999;
+ }
+
+ .token.namespace {
+ opacity: .7;
+ }
+
+ .token.property,
+ .token.tag,
+ .token.boolean,
+ .token.number,
+ .token.constant,
+ .token.symbol,
+ .token.deleted {
+ color: #905;
+ }
+
+ .token.selector,
+ .token.attr-name,
+ .token.string,
+ .token.char,
+ .token.builtin,
+ .token.inserted {
+ color: #690;
+ }
+
+ .token.operator,
+ .token.entity,
+ .token.url,
+ .language-css .token.string,
+ .style .token.string {
+ color: #9a6e3a;
+ /* This background color was intended by the author of this theme. */
+ background: hsla(0, 0%, 100%, .5);
+ }
+
+ .token.atrule,
+ .token.attr-value,
+ .token.keyword {
+ color: #07a;
+ }
+
+ .token.function,
+ .token.class-name {
+ color: #DD4A68;
+ }
+
+ .token.regex,
+ .token.important,
+ .token.variable {
+ color: #e90;
+ }
+
+ .token.important,
+ .token.bold {
+ font-weight: bold;
+ }
+
+ .token.italic {
+ font-style: italic;
+ }
+
+ .token.entity {
+ cursor: help;
+ }
+
+ pre[class*="language-"].line-numbers {
+ position: relative;
+ padding-left: 3.8em;
+ counter-reset: linenumber;
+ }
+
+ pre[class*="language-"].line-numbers > code {
+ position: relative;
+ white-space: inherit;
+ }
+
+ .line-numbers .line-numbers-rows {
+ position: absolute;
+ pointer-events: none;
+ top: 0;
+ font-size: 100%;
+ left: -3.8em;
+ width: 3em; /* works for line-numbers below 1000 lines */
+ letter-spacing: -1px;
+ border-right: 1px solid #999;
+
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+ }
+
+ .line-numbers-rows > span {
+ display: block;
+ counter-increment: linenumber;
+ }
+
+ .line-numbers-rows > span:before {
+ content: counter(linenumber);
+ color: #999;
+ display: block;
+ padding-right: 0.8em;
+ text-align: right;
+ }
+`;
diff --git a/src/components/InputTypes/index.tsx b/src/components/InputTypes/index.tsx
index bc65248..d624b96 100644
--- a/src/components/InputTypes/index.tsx
+++ b/src/components/InputTypes/index.tsx
@@ -1,5 +1,5 @@
import Checkbox from "./Checkbox";
-import Code from "./Code";
+import Code from "./code/Code";
import Radio from "./Radio";
import Range from "./Range";
import Select from "./Select";
@@ -25,6 +25,10 @@ export default function create_input({ question, public_state }: QuestionProp, h
// eslint-disable-next-line
// @ts-ignore
let options: string[] = question.data["options"];
+ // eslint-disable-next-line
+ // @ts-ignore
+ let language: string = question.data["language"] || "python";
+
let valid = true;
if (!public_state.get("valid")) {
valid = false;
@@ -64,7 +68,7 @@ export default function create_input({ question, public_state }: QuestionProp, h
case QuestionType.Code:
// TODO: Implement
- result = <Code handler={handler}/>;
+ result = <Code handler={handler} language={language}/>;
break;
default:
diff --git a/yarn.lock b/yarn.lock
index 070edfc..a852d08 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2091,6 +2091,11 @@
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.6.tgz#f4b1efa784e8db479cdb8b14403e2144b1e9ff03"
integrity sha512-6gOkRe7OIioWAXfnO/2lFiv+SJichKVSys1mSsgyrYHSEjk8Ctv4tSR/Odvnu+HWlH2C8j53dahU03XmQdd5fA==
+ version "1.16.3"
+ resolved "https://registry.yarnpkg.com/@types/prismjs/-/prismjs-1.16.3.tgz#73ae78b3e339777a1a1b7a8df89dcd6b8fe750c5"
+ integrity sha512-7lbX0Odbg9rnzXRdYdgPQZFkjd38QHpD6tvWxbLi6VXGQbXr054doixIS+TwftHP6afffA1zxCZrIcJRS/MkYQ==
+
"@types/prop-types@*":
version "15.7.3"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
@@ -3173,6 +3178,15 @@ clean-css@^4.2.3:
dependencies:
source-map "~0.6.0"
+clipboard@^2.0.0:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.6.tgz#52921296eec0fdf77ead1749421b21c968647376"
+ integrity sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==
+ dependencies:
+ good-listener "^1.2.2"
+ select "^1.1.2"
+ tiny-emitter "^2.0.0"
+
cliui@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
@@ -3685,6 +3699,11 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
+delegate@^3.1.2:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
+ integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==
+
depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
@@ -4718,6 +4737,13 @@ globby@^6.1.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
+good-listener@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
+ integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=
+ dependencies:
+ delegate "^3.1.2"
+
graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
@@ -7148,6 +7174,13 @@ pretty-format@^26.0.0, pretty-format@^26.6.2:
ansi-styles "^4.0.0"
react-is "^17.0.1"
+ version "1.23.0"
+ resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.23.0.tgz#d3b3967f7d72440690497652a9d40ff046067f33"
+ integrity sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==
+ optionalDependencies:
+ clipboard "^2.0.0"
+
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@@ -7805,6 +7838,11 @@ select-hose@^2.0.0:
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
+select@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
+ integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=
+
selfsigned@^1.10.8:
version "1.10.8"
resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.8.tgz#0d17208b7d12c33f8eac85c41835f27fc3d81a30"
@@ -8557,6 +8595,11 @@ thunky@^1.0.2:
resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==
+tiny-emitter@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
+ integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
+
tiny-invariant@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875"