From 042bace2c6f52dceb0c914923b9acb7c153dbaee Mon Sep 17 00:00:00 2001 From: Luck Date: Sun, 6 Nov 2022 22:46:13 +0000 Subject: [PATCH] Convert to typescript --- .gitignore | 2 + .prettierrc | 14 +- package.json | 32 ++- src/{App.js => App.tsx} | 78 +++---- src/components/Button.tsx | 23 ++ src/components/{Editor.js => Editor.tsx} | 61 ++---- .../{EditorControls.js => EditorControls.tsx} | 69 +++--- src/components/EditorGlobalStyle.tsx | 12 ++ .../{EditorTextArea.js => EditorTextArea.tsx} | 199 +++++++++++------- src/components/{Menu.js => MenuButton.tsx} | 136 ++++++------ src/hooks/usePreference.ts | 28 +++ src/{index.js => index.tsx} | 7 +- src/style/{themes.js => themes.ts} | 43 +++- src/util/{constants.js => constants.ts} | 0 src/util/{highlighting.js => highlighting.ts} | 0 src/util/storage.ts | 83 ++++++++ tsconfig.json | 27 +++ yarn.lock | 100 +++++++-- 18 files changed, 593 insertions(+), 321 deletions(-) rename src/{App.js => App.tsx} (54%) create mode 100644 src/components/Button.tsx rename src/components/{Editor.js => Editor.tsx} (52%) rename src/components/{EditorControls.js => EditorControls.tsx} (73%) create mode 100644 src/components/EditorGlobalStyle.tsx rename src/components/{EditorTextArea.js => EditorTextArea.tsx} (64%) rename src/components/{Menu.js => MenuButton.tsx} (71%) create mode 100644 src/hooks/usePreference.ts rename src/{index.js => index.tsx} (70%) rename src/style/{themes.js => themes.ts} (83%) rename src/util/{constants.js => constants.ts} (100%) rename src/util/{highlighting.js => highlighting.ts} (100%) create mode 100644 src/util/storage.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index 4d29575..7d4754a 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* + +.idea \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index efe5fdb..8c37c3a 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,9 +1,9 @@ { - "tabWidth": 2, - "useTabs": false, - "semi": true, - "singleQuote": true, - "trailingComma": "es5", - "arrowParens": "avoid", - "quoteProps": "consistent" + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": true, + "trailingComma": "es5", + "arrowParens": "avoid", + "quoteProps": "consistent" } \ No newline at end of file diff --git a/package.json b/package.json index 1c4660d..e98a796 100644 --- a/package.json +++ b/package.json @@ -3,26 +3,40 @@ "version": "0.1.0", "private": true, "dependencies": { - "@monaco-editor/react": "^4.3.1", - "@testing-library/jest-dom": "^5.11.4", - "@testing-library/react": "^13.3.0", - "@testing-library/user-event": "^14.2.0", - "content-type-parser": "^1.0.2", + "@monaco-editor/react": "4.4.6", "copy-to-clipboard": "^3.3.1", "history": "^5.0.0", "local-storage": "^2.0.0", "pako": "^2.0.3", - "react": "^18.1.0", + "react": "^18.2.0", "react-device-detect": "^2.1.2", - "react-dom": "^18.1.0", + "react-dom": "^18.2.0", "react-scripts": "5.0.1", - "styled-components": "^5.2.1" + "styled-components": "^5.2.1", + "typescript": "^4.8.4", + "whatwg-mimetype": "^3.0.0" + }, + "devDependencies": { + "@testing-library/jest-dom": "^5.11.4", + "@testing-library/react": "^13.3.0", + "@testing-library/user-event": "^14.2.0", + "@types/jest": "^29.2.2", + "@types/node": "^18.11.9", + "@types/pako": "^2.0.0", + "@types/react": "^18.0.25", + "@types/react-dom": "^18.0.8", + "@types/styled-components": "^5.1.26", + "@types/whatwg-mimetype": "^3.0.0", + "monaco-editor": "^0.34.1", + "prettier": "^2.7.1", + "prettier-plugin-organize-imports": "^3.1.1" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", - "eject": "react-scripts eject" + "eject": "react-scripts eject", + "format": "prettier --write '**/*.ts' '**/*.tsx' '**/*.css'" }, "eslintConfig": { "extends": [ diff --git a/src/App.js b/src/App.tsx similarity index 54% rename from src/App.js rename to src/App.tsx index 97f2cb8..2bb57ea 100644 --- a/src/App.js +++ b/src/App.tsx @@ -1,62 +1,27 @@ import { useCallback, useEffect, useState } from 'react'; import Editor from './components/Editor'; -import parseContentType from 'content-type-parser'; -import { languageIds } from './util/highlighting'; -import { bytebinUrl } from './util/constants'; - -function getPasteIdFromUrl() { - const path = window.location.pathname; - if (path && /^\/[a-zA-Z0-9]+$/.test(path)) { - return path.substring(1); - } else { - return undefined; - } -} - -async function loadFromBytebin(id) { - try { - const resp = await fetch(bytebinUrl + id); - if (resp.ok) { - const content = await resp.text(); - const type = parseLanguageFromContentType( - resp.headers.get('content-type') - ); - - document.title = 'pastes | ' + id; - return { ok: true, content, type }; - } else { - return { ok: false }; - } - } catch (e) { - return { ok: false }; - } -} - -function parseLanguageFromContentType(contentType) { - const { type, subtype: subType } = parseContentType(contentType); - if (type === 'application' && subType === 'json') { - return 'json'; - } - if (type === 'text' && languageIds.includes(subType.toLowerCase())) { - return subType.toLowerCase(); - } -} +import { loadFromBytebin } from './util/storage'; const INITIAL = Symbol(); const LOADING = Symbol(); const LOADED = Symbol(); -export default function App() { - const [pasteId] = useState(getPasteIdFromUrl); - const [state, setState] = useState(INITIAL); - const [forcedContent, setForcedContent] = useState(''); - const [actualContent, setActualContent] = useState(''); - const [contentType, setContentType] = useState(); +type LoadingState = typeof INITIAL | typeof LOADING | typeof LOADED; - const setContent = useCallback((content) => { - setActualContent(content); - setForcedContent(content); - }, [setActualContent, setForcedContent]); +export default function App() { + const [pasteId] = useState(getPasteIdFromUrl); + const [state, setState] = useState(INITIAL); + const [forcedContent, setForcedContent] = useState(''); + const [actualContent, setActualContent] = useState(''); + const [contentType, setContentType] = useState(); + + const setContent = useCallback( + (content: string) => { + setActualContent(content); + setForcedContent(content); + }, + [setActualContent, setForcedContent] + ); useEffect(() => { if (pasteId && state === INITIAL) { @@ -88,7 +53,7 @@ export default function App() { ); } -function get404Message(pasteId) { +function get404Message(pasteId: string) { return ` ██╗ ██╗ ██████╗ ██╗ ██╗ ██║ ██║██╔═████╗██║ ██║ @@ -101,3 +66,12 @@ function get404Message(pasteId) { maybe the paste expired? `; } + +function getPasteIdFromUrl() { + const path = window.location.pathname; + if (path && /^\/[a-zA-Z0-9]+$/.test(path)) { + return path.substring(1); + } else { + return undefined; + } +} diff --git a/src/components/Button.tsx b/src/components/Button.tsx new file mode 100644 index 0000000..8601989 --- /dev/null +++ b/src/components/Button.tsx @@ -0,0 +1,23 @@ +import styled from 'styled-components'; + +const Button = styled.div` + cursor: pointer; + height: 100%; + display: flex; + align-items: center; + padding: 0 0.25em; + color: inherit; + text-decoration: none; + + :hover { + background: ${props => props.theme.highlight}; + } + + @media (max-width: 640px) { + span { + display: none; + } + } +`; + +export default Button; diff --git a/src/components/Editor.js b/src/components/Editor.tsx similarity index 52% rename from src/components/Editor.js rename to src/components/Editor.tsx index e4ad099..f84bb7d 100644 --- a/src/components/Editor.js +++ b/src/components/Editor.tsx @@ -1,11 +1,21 @@ -import { useState, useEffect } from 'react'; -import { ThemeProvider, createGlobalStyle } from 'styled-components'; +import { useEffect, useState } from 'react'; import { isMobile } from 'react-device-detect'; -import ls from 'local-storage'; +import { ThemeProvider } from 'styled-components'; +import usePreference from '../hooks/usePreference'; +import themes, { Themes } from '../style/themes'; import EditorControls from './EditorControls'; +import EditorGlobalStyle from './EditorGlobalStyle'; import EditorTextArea from './EditorTextArea'; -import themes from '../style/themes'; + +export interface EditorProps { + forcedContent: string; + setForcedContent: (value: string) => void; + actualContent: string; + setActualContent: (value: string) => void; + contentType?: string; + pasteId?: string; +} export default function Editor({ forcedContent, @@ -14,16 +24,16 @@ export default function Editor({ setActualContent, contentType, pasteId, -}) { - const [language, setLanguage] = useState('plain'); - const [readOnly, setReadOnly] = useState(isMobile && pasteId); +}: EditorProps) { + const [language, setLanguage] = useState('plain'); + const [readOnly, setReadOnly] = useState(isMobile && !!pasteId); - const [theme, setTheme] = usePreference( + const [theme, setTheme] = usePreference( 'theme', 'dark', pref => !!themes[pref] ); - const [fontSize, setFontSize, fontSizeCheck] = usePreference( + const [fontSize, setFontSize, fontSizeCheck] = usePreference( 'fontsize', 16, pref => pref >= 10 && pref <= 22 @@ -35,7 +45,7 @@ export default function Editor({ } }, [contentType]); - function zoom(delta) { + function zoom(delta: number) { const newFontSize = fontSize + delta; if (fontSizeCheck(newFontSize)) { setFontSize(newFontSize); @@ -65,39 +75,8 @@ export default function Editor({ language={language} fontSize={fontSize} readOnly={readOnly} - setReadOnly={setReadOnly} /> ); } - -const EditorGlobalStyle = createGlobalStyle` - html, body { - color-scheme: ${props => props.theme.lightOrDark}; - scrollbar-color: ${props => props.theme.lightOrDark}; - background-color: ${props => props.theme.editor.background}; - } -`; - -// hook used to load "preference" settings from local storage, or fall back to a default value. -function usePreference(id, defaultValue, valid) { - const [value, setValue] = useState(() => { - const pref = ls.get(id); - if (pref && valid(pref)) { - return pref; - } else { - return defaultValue; - } - }); - - useEffect(() => { - if (value === defaultValue) { - ls.remove(id); - } else { - ls.set(id, value); - } - }, [value, id, defaultValue]); - - return [value, setValue, valid]; -} diff --git a/src/components/EditorControls.js b/src/components/EditorControls.tsx similarity index 73% rename from src/components/EditorControls.js rename to src/components/EditorControls.tsx index 35a67f8..f7a8fb3 100644 --- a/src/components/EditorControls.js +++ b/src/components/EditorControls.tsx @@ -1,13 +1,25 @@ -import { useState, useEffect, useCallback } from 'react'; -import styled from 'styled-components'; -import { gzip } from 'pako'; -import history from 'history/browser'; import copy from 'copy-to-clipboard'; +import history from 'history/browser'; +import { useCallback, useEffect, useState } from 'react'; +import styled from 'styled-components'; -import { MenuButton, Button } from './Menu'; +import themes, { Themes } from '../style/themes'; import { languages } from '../util/highlighting'; -import themes from '../style/themes'; -import { postUrl } from '../util/constants'; +import { saveToBytebin } from '../util/storage'; +import Button from './Button'; +import MenuButton from './MenuButton'; + +export interface EditorControlsProps { + actualContent: string; + setForcedContent: (value: string) => void; + language: string; + setLanguage: (value: string) => void; + readOnly: boolean; + setReadOnly: (value: boolean) => void; + theme: keyof Themes; + setTheme: (value: keyof Themes) => void; + zoom: (delta: number) => void; +} export default function EditorControls({ actualContent, @@ -19,9 +31,9 @@ export default function EditorControls({ theme, setTheme, zoom, -}) { - const [saving, setSaving] = useState(false); - const [recentlySaved, setRecentlySaved] = useState(false); +}: EditorControlsProps) { + const [saving, setSaving] = useState(false); + const [recentlySaved, setRecentlySaved] = useState(false); useEffect(() => { setRecentlySaved(false); @@ -46,7 +58,7 @@ export default function EditorControls({ }, [actualContent, language, recentlySaved]); useEffect(() => { - const listener = e => { + const listener = (e: KeyboardEvent) => { if (e.ctrlKey || e.metaKey) { if (e.key === 's' || e.key === 'S') { e.preventDefault(); @@ -100,7 +112,7 @@ export default function EditorControls({ label="theme" value={theme} setValue={setTheme} - ids={Object.keys(themes)} + ids={Object.keys(themes) as (keyof Themes)[]} /> + ); +} const Menu = styled.ul` position: absolute; @@ -60,58 +109,3 @@ const Menu = styled.ul` background-color: ${props => props.theme.secondary}; } `; - -export const MenuButton = ({ label, ids, value, setValue }) => { - const [open, setOpen] = useState(false); - - useEffect(() => { - const listener = e => setOpen(false); - window.addEventListener('click', listener); - return () => window.removeEventListener('click', listener); - }, [setOpen]); - - function toggleOpen(e) { - e.stopPropagation(); - setOpen(!open); - } - - function select(e, id) { - e.stopPropagation(); - setOpen(false); - setValue(id); - } - - function make(ids) { - return ids.map(id => ( -
  • select(e, id)} - > - {id} -
  • - )); - } - - let items; - if (Array.isArray(ids)) { - items = make(ids); - } else { - items = Object.entries(ids).map(([title, values]) => - [ -
  • e.stopPropagation()}> - [{title}] -
  • , - ] - .concat(make(values)) - .flat() - ); - } - - return ( - - ); -}; diff --git a/src/hooks/usePreference.ts b/src/hooks/usePreference.ts new file mode 100644 index 0000000..c2b98da --- /dev/null +++ b/src/hooks/usePreference.ts @@ -0,0 +1,28 @@ +import { get as lsGet, remove as lsRemove, set as lsSet } from 'local-storage'; +import { Dispatch, SetStateAction, useEffect, useState } from 'react'; + +// hook used to load "preference" settings from local storage, or fall back to a default value. +export default function usePreference( + id: string, + defaultValue: T, + valid: (value: T) => boolean +): [T, Dispatch>, (value: T) => boolean] { + const [value, setValue] = useState(() => { + const pref = lsGet(id) as T; + if (pref && valid(pref)) { + return pref; + } else { + return defaultValue; + } + }); + + useEffect(() => { + if (value === defaultValue) { + lsRemove(id); + } else { + lsSet(id, value); + } + }, [value, id, defaultValue]); + + return [value, setValue, valid]; +} diff --git a/src/index.js b/src/index.tsx similarity index 70% rename from src/index.js rename to src/index.tsx index 2204074..3b7cfef 100644 --- a/src/index.js +++ b/src/index.tsx @@ -1,12 +1,13 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; -import './style/base.css'; import App from './App'; +import './style/base.css'; -const root = ReactDOM.createRoot(document.getElementById('root')); +const root = ReactDOM.createRoot( + document.getElementById('root') as HTMLElement +); root.render( ); - \ No newline at end of file diff --git a/src/style/themes.js b/src/style/themes.ts similarity index 83% rename from src/style/themes.js rename to src/style/themes.ts index ef8ba11..e47f54c 100644 --- a/src/style/themes.js +++ b/src/style/themes.ts @@ -1,4 +1,43 @@ -const themes = { +import type { editor } from 'monaco-editor'; + +export interface Theme { + id: string; + primary: string; + secondary: string; + highlight: string; + lightOrDark: string; + + editor: { + background: string; + lineNumber: string; + lineNumberHl: string; + lineNumberHlBackground: string; + primary: string; + selection: string; + comment: string; + commentTag: string; + punctuation: string; + annotation: string; + namespace: string; + property: string; + constant: string; + number: string; + selector: string; + operator: string; + keyword: string; + function: string; + className: string; + variable: string; + }; +} + +export interface Themes { + light: Theme; + blue: Theme; + dark: Theme; +} + +const themes: Themes = { light: { id: 'light', primary: '#aaddff', @@ -93,7 +132,7 @@ const themes = { export default themes; -export function makeMonacoTheme(theme) { +export function makeMonacoTheme(theme: Theme): editor.IStandaloneThemeData { return { base: theme.lightOrDark === 'light' ? 'vs' : 'vs-dark', inherit: true, diff --git a/src/util/constants.js b/src/util/constants.ts similarity index 100% rename from src/util/constants.js rename to src/util/constants.ts diff --git a/src/util/highlighting.js b/src/util/highlighting.ts similarity index 100% rename from src/util/highlighting.js rename to src/util/highlighting.ts diff --git a/src/util/storage.ts b/src/util/storage.ts new file mode 100644 index 0000000..bae6508 --- /dev/null +++ b/src/util/storage.ts @@ -0,0 +1,83 @@ +import { gzip } from 'pako'; +import MIMEType from 'whatwg-mimetype'; +import { bytebinUrl, postUrl } from './constants'; +import { languageIds } from './highlighting'; + +interface LoadResultSuccess { + ok: true; + content: string; + type?: string; +} + +interface LoadResultFail { + ok: false; + content?: never; + type?: never; +} + +export type LoadResult = LoadResultSuccess | LoadResultFail; + +export async function loadFromBytebin(id: string): Promise { + try { + const resp = await fetch(bytebinUrl + id); + if (resp.ok) { + const content = await resp.text(); + const type = contentTypeToLanguage( + resp.headers.get('content-type') as string + ); + + document.title = 'pastes | ' + id; + return { ok: true, content, type }; + } else { + return { ok: false }; + } + } catch (e) { + return { ok: false }; + } +} + +export async function saveToBytebin( + code: string, + language: string +): Promise { + try { + const compressed = gzip(code); + const contentType = languageToContentType(language); + + const resp = await fetch(postUrl, { + method: 'POST', + headers: { + 'Content-Type': contentType, + 'Content-Encoding': 'gzip', + 'Accept': 'application/json', + }, + body: compressed, + }); + + if (resp.ok) { + const json = await resp.json(); + return json.key; + } + } catch (e) { + console.log(e); + } + return null; +} + +export function contentTypeToLanguage(contentType: string) { + const { type, subtype: subType } = new MIMEType(contentType); + if (type === 'application' && subType === 'json') { + return 'json'; + } + if (type === 'text' && languageIds.includes(subType.toLowerCase())) { + return subType.toLowerCase(); + } +} + +export function languageToContentType(language: string) { + if (language === 'json') { + return 'application/json'; + } else { + return 'text/' + language; + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..127fa61 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": [ + "src/*.ts", + "src/*.tsx" + ] +} diff --git a/yarn.lock b/yarn.lock index 554639f..09a23a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1565,10 +1565,10 @@ dependencies: state-local "^1.0.6" -"@monaco-editor/react@^4.3.1": - version "4.4.5" - resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.4.5.tgz#beabe491efeb2457441a00d1c7651c653697f65b" - integrity sha512-IImtzU7sRc66OOaQVCG+5PFHkSWnnhrUWGBuH6zNmH2h0YgmAhcjHZQc/6MY9JWEbUtVF1WPBMJ9u1XuFbRrVA== +"@monaco-editor/react@4.4.6": + version "4.4.6" + resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.4.6.tgz#8ae500b0edf85276d860ed702e7056c316548218" + integrity sha512-Gr3uz3LYf33wlFE3eRnta4RxP5FSNxiIV9ENn2D2/rN8KgGAD8ecvcITRtsbbyuOuNkwbuHYxfeaz2Vr+CtyFA== dependencies: "@monaco-editor/loader" "^1.3.2" prop-types "^15.7.2" @@ -1961,6 +1961,14 @@ dependencies: "@types/node" "*" +"@types/hoist-non-react-statics@*": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/html-minifier-terser@^6.0.0": version "6.1.0" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" @@ -2000,6 +2008,14 @@ expect "^29.0.0" pretty-format "^29.0.0" +"@types/jest@^29.2.2": + version "29.2.2" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.2.2.tgz#874e7dc6702fa6a3fe6107792aa98636dcc480b4" + integrity sha512-og1wAmdxKoS71K2ZwSVqWPX6OVn3ihZ6ZT2qvZvZQm90lJVDyXIjYcu4Khx2CNIeaFv12rOU/YObOsI3VOkzog== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + "@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" @@ -2020,6 +2036,16 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.14.tgz#0fe081752a3333392d00586d815485a17c2cf3c9" integrity sha512-6bbDaETVi8oyIARulOE9qF1/Qdi/23z6emrUh0fNJRUmjznqrixD4MpGDdgOFk5Xb0m2H6Xu42JGdvAxaJR/wA== +"@types/node@^18.11.9": + version "18.11.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4" + integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg== + +"@types/pako@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/pako/-/pako-2.0.0.tgz#12ab4c19107528452e73ac99132c875ccd43bdfb" + integrity sha512-10+iaz93qR5WYxTo+PMifD5TSxiOtdRaxBf7INGGXMQgTCu8Z/7GYWYFUOS3q/G0nE5boj1r4FEB+WSy7s5gbA== + "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" @@ -2057,6 +2083,13 @@ dependencies: "@types/react" "*" +"@types/react-dom@^18.0.8": + version "18.0.8" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.8.tgz#d2606d855186cd42cc1b11e63a71c39525441685" + integrity sha512-C3GYO0HLaOkk9dDAz3Dl4sbe4AKUGTCfFIZsz3n/82dPNN8Du533HzKatDxeUYWu24wJgMP1xICqkWk1YOLOIw== + dependencies: + "@types/react" "*" + "@types/react@*": version "18.0.18" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.18.tgz#9f16f33d57bc5d9dca848d12c3572110ff9429ac" @@ -2066,6 +2099,15 @@ "@types/scheduler" "*" csstype "^3.0.2" +"@types/react@^18.0.25": + version "18.0.25" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.25.tgz#8b1dcd7e56fe7315535a4af25435e0bb55c8ae44" + integrity sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + "@types/resolve@1.17.1": version "1.17.1" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" @@ -2110,6 +2152,15 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/styled-components@^5.1.26": + version "5.1.26" + resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.26.tgz#5627e6812ee96d755028a98dae61d28e57c233af" + integrity sha512-KuKJ9Z6xb93uJiIyxo/+ksS7yLjS1KzG6iv5i78dhVg/X3u5t1H7juRWqVmodIdz6wGVaIApo1u01kmFRdJHVw== + dependencies: + "@types/hoist-non-react-statics" "*" + "@types/react" "*" + csstype "^3.0.2" + "@types/testing-library__jest-dom@^5.9.1": version "5.14.5" resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz#d113709c90b3c75fdb127ec338dad7d5f86c974f" @@ -2122,6 +2173,11 @@ resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756" integrity sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg== +"@types/whatwg-mimetype@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#4ff45f787a085e7d22b7e01f3724f28a97d84c67" + integrity sha512-xHFOhd41VpUR6Y0k8ZinlyFv5cyhC/r2zghJgWWN8oNxqNo45Nf0qCBInJsFeifLeoHcIF4voEfap4A2GYHWkw== + "@types/ws@^8.5.1": version "8.5.3" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" @@ -3234,11 +3290,6 @@ content-disposition@0.5.4: dependencies: safe-buffer "5.2.1" -content-type-parser@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.2.tgz#caabe80623e63638b2502fd4c7f12ff4ce2352e7" - integrity sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ== - content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" @@ -4764,7 +4815,7 @@ history@^5.0.0: dependencies: "@babel/runtime" "^7.7.6" -hoist-non-react-statics@^3.0.0: +hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -6213,6 +6264,11 @@ mkdirp@~0.5.1: dependencies: minimist "^1.2.6" +monaco-editor@^0.34.1: + version "0.34.1" + resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.34.1.tgz#1b75c4ad6bc4c1f9da656d740d98e0b850a22f87" + integrity sha512-FKc80TyiMaruhJKKPz5SpJPIjL+dflGvz4CpuThaPMc94AyN7SeC9HQ8hrvaxX7EyHdJcUY5i4D0gNyJj1vSZQ== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -7196,6 +7252,16 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== +prettier-plugin-organize-imports@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.1.1.tgz#e581cb6fa528cf72f7d95b807ce38c3e51c3c27c" + integrity sha512-6bHIQzybqA644h0WGUW3gpWEVbMBvzui5wCMRBi7qA++d5ov2xjjfDk8pxJJ/ardfZrGAwizKMq/fQMFdJ+0Zw== + +prettier@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== + pretty-bytes@^5.3.0, pretty-bytes@^5.4.1: version "5.6.0" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" @@ -7389,7 +7455,7 @@ react-device-detect@^2.1.2: dependencies: ua-parser-js "^1.0.2" -react-dom@^18.1.0: +react-dom@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== @@ -7477,7 +7543,7 @@ react-scripts@5.0.1: optionalDependencies: fsevents "^2.3.2" -react@^18.1.0: +react@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== @@ -8547,6 +8613,11 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typescript@^4.8.4: + version "4.8.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" + integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== + ua-parser-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.2.tgz#e2976c34dbfb30b15d2c300b2a53eac87c57a775" @@ -8871,6 +8942,11 @@ whatwg-mimetype@^2.3.0: resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +whatwg-mimetype@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" + integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== + whatwg-url@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06"