From 8cbf8fdcfdceab8a330bdc82e4260a55c125c37d Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Sun, 22 Aug 2021 19:54:51 +0200 Subject: Covert language-web to TypeScript --- language-web/src/main/js/App.jsx | 92 --------------- language-web/src/main/js/App.tsx | 92 +++++++++++++++ language-web/src/main/js/Navbar.jsx | 37 ------ language-web/src/main/js/RootStore.jsx | 28 ----- language-web/src/main/js/RootStore.tsx | 28 +++++ language-web/src/main/js/editor/Editor.jsx | 52 --------- language-web/src/main/js/editor/Editor.tsx | 20 ++++ language-web/src/main/js/editor/EditorButtons.jsx | 75 ------------ language-web/src/main/js/editor/EditorButtons.tsx | 75 ++++++++++++ language-web/src/main/js/editor/EditorStore.jsx | 87 -------------- language-web/src/main/js/editor/EditorStore.ts | 127 +++++++++++++++++++++ language-web/src/main/js/index.jsx | 79 ------------- language-web/src/main/js/index.tsx | 79 +++++++++++++ language-web/src/main/js/makeStyles.js | 4 - language-web/src/main/js/makeStyles.ts | 4 + .../src/main/js/xtext/xtext-codemirror.d.ts | 43 +++++++ 16 files changed, 468 insertions(+), 454 deletions(-) delete mode 100644 language-web/src/main/js/App.jsx create mode 100644 language-web/src/main/js/App.tsx delete mode 100644 language-web/src/main/js/Navbar.jsx delete mode 100644 language-web/src/main/js/RootStore.jsx create mode 100644 language-web/src/main/js/RootStore.tsx delete mode 100644 language-web/src/main/js/editor/Editor.jsx create mode 100644 language-web/src/main/js/editor/Editor.tsx delete mode 100644 language-web/src/main/js/editor/EditorButtons.jsx create mode 100644 language-web/src/main/js/editor/EditorButtons.tsx delete mode 100644 language-web/src/main/js/editor/EditorStore.jsx create mode 100644 language-web/src/main/js/editor/EditorStore.ts delete mode 100644 language-web/src/main/js/index.jsx create mode 100644 language-web/src/main/js/index.tsx delete mode 100644 language-web/src/main/js/makeStyles.js create mode 100644 language-web/src/main/js/makeStyles.ts create mode 100644 language-web/src/main/js/xtext/xtext-codemirror.d.ts (limited to 'language-web/src/main/js') diff --git a/language-web/src/main/js/App.jsx b/language-web/src/main/js/App.jsx deleted file mode 100644 index 5bd46c09..00000000 --- a/language-web/src/main/js/App.jsx +++ /dev/null @@ -1,92 +0,0 @@ -import React from 'react'; -import AppBar from '@material-ui/core/AppBar'; -import Box from '@material-ui/core/Box'; -import Button from '@material-ui/core/Button'; -import IconButton from '@material-ui/core/IconButton'; -import Toolbar from '@material-ui/core/Toolbar'; -import Typography from '@material-ui/core/Typography'; -import MenuIcon from '@material-ui/icons/Menu'; -import PlayArrowIcon from '@material-ui/icons/PlayArrow'; - -import { makeStyles } from './makeStyles'; -import Editor from './editor/Editor'; -import EditorButtons from './editor/EditorButtons'; - -const useStyles = makeStyles()(theme => ({ - container: { - maxHeight: '100vh', - }, - menuButton: { - marginRight: theme.spacing(2), - }, - title: { - flexGrow: 1, - }, - editorBox: { - overflow: 'auto', - }, -})); - -export default () => { - const { classes, cx } = useStyles(); - - return ( - - - - - - - - GraphSolver - - - - - - - - - - - - - - - - ); -}; diff --git a/language-web/src/main/js/App.tsx b/language-web/src/main/js/App.tsx new file mode 100644 index 00000000..5bd46c09 --- /dev/null +++ b/language-web/src/main/js/App.tsx @@ -0,0 +1,92 @@ +import React from 'react'; +import AppBar from '@material-ui/core/AppBar'; +import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; +import IconButton from '@material-ui/core/IconButton'; +import Toolbar from '@material-ui/core/Toolbar'; +import Typography from '@material-ui/core/Typography'; +import MenuIcon from '@material-ui/icons/Menu'; +import PlayArrowIcon from '@material-ui/icons/PlayArrow'; + +import { makeStyles } from './makeStyles'; +import Editor from './editor/Editor'; +import EditorButtons from './editor/EditorButtons'; + +const useStyles = makeStyles()(theme => ({ + container: { + maxHeight: '100vh', + }, + menuButton: { + marginRight: theme.spacing(2), + }, + title: { + flexGrow: 1, + }, + editorBox: { + overflow: 'auto', + }, +})); + +export default () => { + const { classes, cx } = useStyles(); + + return ( + + + + + + + + GraphSolver + + + + + + + + + + + + + + + + ); +}; diff --git a/language-web/src/main/js/Navbar.jsx b/language-web/src/main/js/Navbar.jsx deleted file mode 100644 index cf1bc54f..00000000 --- a/language-web/src/main/js/Navbar.jsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; -import { Button, Navbar, Nav } from 'react-bootstrap'; -import { FaGithub, FaPlayCircle } from 'react-icons/fa'; - -export default () => ( - - GraphSolver - - - - - - -); diff --git a/language-web/src/main/js/RootStore.jsx b/language-web/src/main/js/RootStore.jsx deleted file mode 100644 index a437fdd0..00000000 --- a/language-web/src/main/js/RootStore.jsx +++ /dev/null @@ -1,28 +0,0 @@ -import React, { createContext, useContext } from 'react'; - -import EditorStore from './editor/EditorStore'; - -export default class RootStore { - editorStore; - - constructor() { - this.editorStore = new EditorStore(); - } -} - -const StoreContext = createContext(undefined); - -export const RootStoreProvider = ({ children, rootStore }) => ( - - {children} - -); - -/** @returns {RootStore} */ -export const useRootStore = () => { - const rootStore = useContext(StoreContext); - if (!rootStore) { - throw new Error('useRootStore must be used within RootStoreProvider'); - } - return rootStore; -}; diff --git a/language-web/src/main/js/RootStore.tsx b/language-web/src/main/js/RootStore.tsx new file mode 100644 index 00000000..2159f440 --- /dev/null +++ b/language-web/src/main/js/RootStore.tsx @@ -0,0 +1,28 @@ + +import React, { createContext, useContext } from 'react'; + +import EditorStore from './editor/EditorStore'; + +export default class RootStore { + editorStore; + + constructor() { + this.editorStore = new EditorStore(); + } +} + +const StoreContext = createContext(undefined); + +export const RootStoreProvider: React.FC<{ rootStore: RootStore }> = ({ children, rootStore }) => ( + + {children} + +); + +export const useRootStore = () => { + const rootStore = useContext(StoreContext); + if (!rootStore) { + throw new Error('useRootStore must be used within RootStoreProvider'); + } + return rootStore; +}; diff --git a/language-web/src/main/js/editor/Editor.jsx b/language-web/src/main/js/editor/Editor.jsx deleted file mode 100644 index 4cd9b3bd..00000000 --- a/language-web/src/main/js/editor/Editor.jsx +++ /dev/null @@ -1,52 +0,0 @@ -import { observer } from 'mobx-react-lite'; -import 'mode-problem'; -import React, { useCallback } from 'react'; -import { Controlled as CodeMirror } from 'react-codemirror2-react-17'; -import { createServices, removeServices } from 'xtext/xtext-codemirror'; - -import { useRootStore } from '../RootStore'; - -export default observer(() => { - const editorStore = useRootStore().editorStore; - - const codeMirrorOptions = { - mode: 'xtext/problem', - indentUnit: 2, - theme: 'material-darker', - lineNumbers: editorStore.showLineNumbers, - }; - - const xtextOptions = { - xtextLang: 'problem', - enableFormattingAction: true, - } - - const editorDidMount = useCallback((editor) => { - createServices(editor, xtextOptions); - editorStore.updateEditor(editor); - }, [editorStore]); - - const editorWillUnmount = useCallback((editor) => { - editorStore.editor = null; - removeServices(editor); - }, [editorStore]); - - const onBeforeChange = useCallback((_editor, _data, value) => { - editorStore.updateValue(value); - }, [editorStore]); - - const onChange = useCallback((_editor, _data, _value) => { - editorStore.reportChanged(); - }, [editorStore]); - - return ( - - ); -}); diff --git a/language-web/src/main/js/editor/Editor.tsx b/language-web/src/main/js/editor/Editor.tsx new file mode 100644 index 00000000..f81c5c37 --- /dev/null +++ b/language-web/src/main/js/editor/Editor.tsx @@ -0,0 +1,20 @@ +import { observer } from 'mobx-react-lite'; +import React from 'react'; +import { Controlled as CodeMirror } from 'react-codemirror2'; + +import { useRootStore } from '../RootStore'; + +export default observer(() => { + const { editorStore } = useRootStore(); + + return ( + editorStore.editorDidMount(editor)} + editorWillUnmount={() => editorStore.editorWillUnmount()} + onBeforeChange={(_editor, _data, value) => editorStore.updateValue(value)} + onChange={() => editorStore.reportChanged()} + /> + ); +}); diff --git a/language-web/src/main/js/editor/EditorButtons.jsx b/language-web/src/main/js/editor/EditorButtons.jsx deleted file mode 100644 index a5a57f93..00000000 --- a/language-web/src/main/js/editor/EditorButtons.jsx +++ /dev/null @@ -1,75 +0,0 @@ -import { observer } from 'mobx-react-lite'; -import React from 'react'; -import Button from '@material-ui/core/Button'; -import ButtonGroup from '@material-ui/core/ButtonGroup'; -import ToggleButton from '@material-ui/core/ToggleButton'; -import Divider from '@material-ui/core/Divider'; -import FormatListNumberedIcon from '@material-ui/icons/FormatListNumbered'; -import RedoIcon from '@material-ui/icons/Redo'; -import UndoIcon from '@material-ui/icons/Undo'; - -import { makeStyles } from '../makeStyles'; -import { useRootStore } from '../RootStore'; - -const useStyles = makeStyles()(theme => ({ - iconButton: { - padding: 7, - border: 0, - color: theme.palette.text.primary, - '&, &.MuiButtonGroup-grouped': { - minWidth: 36, - }, - '&.MuiButtonGroup-grouped:not(:last-of-type)': { - borderRight: 0, - }, - }, - divider: { - margin: theme.spacing(0.5), - }, -})); - -export default observer(() => { - const editorStore = useRootStore().editorStore; - const { classes, cx } = useStyles(); - return ( - <> - - - - - - editorStore.toggleLineNumbers()} - size='small' - className={cx(classes.iconButton)} - aria-label='Show line numbers' - value='show-line-numbers' - > - - - - ); -}); diff --git a/language-web/src/main/js/editor/EditorButtons.tsx b/language-web/src/main/js/editor/EditorButtons.tsx new file mode 100644 index 00000000..1a187635 --- /dev/null +++ b/language-web/src/main/js/editor/EditorButtons.tsx @@ -0,0 +1,75 @@ +import { observer } from 'mobx-react-lite'; +import React from 'react'; +import Button from '@material-ui/core/Button'; +import ButtonGroup from '@material-ui/core/ButtonGroup'; +import ToggleButton from '@material-ui/core/ToggleButton'; +import Divider from '@material-ui/core/Divider'; +import FormatListNumberedIcon from '@material-ui/icons/FormatListNumbered'; +import RedoIcon from '@material-ui/icons/Redo'; +import UndoIcon from '@material-ui/icons/Undo'; + +import { makeStyles } from '../makeStyles'; +import { useRootStore } from '../RootStore'; + +const useStyles = makeStyles()(theme => ({ + iconButton: { + padding: 7, + border: 0, + color: theme.palette.text.primary, + '&, &.MuiButtonGroup-grouped': { + minWidth: 36, + }, + '&.MuiButtonGroup-grouped:not(:last-of-type)': { + borderRight: 0, + }, + }, + divider: { + margin: theme.spacing(0.5), + }, +})); + +export default observer(() => { + const { editorStore } = useRootStore(); + const { classes, cx } = useStyles(); + return ( + <> + + + + + + editorStore.toggleLineNumbers()} + size='small' + className={cx(classes.iconButton)} + aria-label='Show line numbers' + value='show-line-numbers' + > + + + + ); +}); diff --git a/language-web/src/main/js/editor/EditorStore.jsx b/language-web/src/main/js/editor/EditorStore.jsx deleted file mode 100644 index b6f9bc0a..00000000 --- a/language-web/src/main/js/editor/EditorStore.jsx +++ /dev/null @@ -1,87 +0,0 @@ -import CodeMirror from 'codemirror'; -import { createAtom, makeAutoObservable, observable } from 'mobx'; - -export default class EditorStore { - atom; - /** @type {CodeMirror} */ - editor = null; - /** @type {string} */ - value = ''; - /** @type {boolean} */ - showLineNumbers = false; - /** @type {boolean} */ - showLigatures = true; - - constructor() { - this.atom = createAtom('EditorStore'); - makeAutoObservable(this, { - atom: false, - editor: observable.ref, - }); - } - - /** - * Attaches a new CodeMirror instance. - * - * The store will node subscribe to any CodeMirror events. Instead, - * the editor component should subscribe to them and relay them to the store. - * - * @param {CodeMirror} newEditor The new CodeMirror instance - */ - updateEditor(newEditor) { - this.editor = newEditor; - } - - /** - * Updates the contents of the editor. - * - * @param {string} newValue The new contents of the editor - */ - updateValue(newValue) { - this.value = newValue; - } - - reportChanged() { - this.atom.reportChanged(); - } - - /** - * @returns {boolean} `true` if there is history to undo - */ - get canUndo() { - this.atom.reportObserved(); - if (!this.editor) { - return false; - } - const { undo: undoSize } = this.editor.historySize(); - return undoSize > 0; - } - - undo() { - this.editor.undo(); - } - - /** - * @returns {boolean} `true` if there is history to redo - */ - get canRedo() { - this.atom.reportObserved(); - if (!this.editor) { - return false; - } - const { redo: redoSize } = this.editor.historySize(); - return redoSize > 0; - } - - redo() { - this.editor.redo(); - } - - toggleLineNumbers() { - this.showLineNumbers = !this.showLineNumbers; - } - - toggleLigatures() { - this.showLigatures = !this.showLigatures; - } -} diff --git a/language-web/src/main/js/editor/EditorStore.ts b/language-web/src/main/js/editor/EditorStore.ts new file mode 100644 index 00000000..167e1ade --- /dev/null +++ b/language-web/src/main/js/editor/EditorStore.ts @@ -0,0 +1,127 @@ +import { Editor, EditorConfiguration } from 'codemirror'; +import { + createAtom, + makeAutoObservable, + observable, +} from 'mobx'; +import 'mode-problem'; +import { + IXtextOptions, + IXtextServices, + createServices, + removeServices, +} from 'xtext/xtext-codemirror'; + +const xtextLang = 'problem'; + +const xtextOptions: IXtextOptions = { + xtextLang, + enableFormattingAction: true, +}; + +const codeMirrorGlobalOptions: EditorConfiguration = { + mode: `xtext/${xtextLang}`, + indentUnit: 2, + theme: 'material-darker', +}; + +export default class EditorStore { + _atom; + editor?: Editor; + xtextServices?: IXtextServices; + value = ''; + showLineNumbers = false; + + constructor() { + this._atom = createAtom('EditorStore'); + makeAutoObservable(this, { + _atom: false, + editor: observable.ref, + xtextServices: observable.ref, + }); + } + + /** + * Attaches a new CodeMirror instance and creates Xtext services. + * + * The store will not subscribe to any CodeMirror events. Instead, + * the editor component should subscribe to them and relay them to the store. + * + * @param newEditor The new CodeMirror instance + */ + editorDidMount(newEditor: Editor) { + if (this.editor) { + throw new Error('CoreMirror editor mounted before unmounting'); + } + this.editor = newEditor; + this.xtextServices = createServices(newEditor, xtextOptions); + } + + editorWillUnmount() { + if (this.editor) { + removeServices(this.editor); + } + this.editor = undefined; + this.xtextServices = undefined; + } + + /** + * Updates the contents of the editor. + * + * @param newValue The new contents of the editor + */ + updateValue(newValue: string) { + this.value = newValue; + } + + reportChanged() { + this._atom.reportChanged(); + } + + _observeEditorChanges() { + this._atom.reportObserved(); + } + + get codeMirrorOptions(): EditorConfiguration { + return { + ...codeMirrorGlobalOptions, + lineNumbers: this.showLineNumbers, + }; + } + + /** + * @returns `true` if there is history to undo + */ + get canUndo() { + this._observeEditorChanges(); + if (!this.editor) { + return false; + } + const { undo: undoSize } = this.editor.historySize(); + return undoSize > 0; + } + + undo() { + this.editor?.undo(); + } + + /** + * @returns `true` if there is history to redo + */ + get canRedo() { + this._observeEditorChanges(); + if (!this.editor) { + return false; + } + const { redo: redoSize } = this.editor.historySize(); + return redoSize > 0; + } + + redo() { + this.editor?.redo(); + } + + toggleLineNumbers() { + this.showLineNumbers = !this.showLineNumbers; + } +} diff --git a/language-web/src/main/js/index.jsx b/language-web/src/main/js/index.jsx deleted file mode 100644 index d73ffcdd..00000000 --- a/language-web/src/main/js/index.jsx +++ /dev/null @@ -1,79 +0,0 @@ -import { CacheProvider } from "@emotion/react"; -import React from 'react'; -import { render } from 'react-dom'; -import { ThemeProvider, createTheme } from '@material-ui/core/styles'; -import { getCache } from "tss-react/cache"; - -import App from './App'; -import CssBaseline from '@material-ui/core/CssBaseline'; -import RootStore, { RootStoreProvider } from './RootStore'; - -import '../css/index.scss'; - -const initialValue = `class Family { - contains Person[] members -} - -class Person { - Person[] children opposite parent - Person[0..1] parent opposite children - int age - TaxStatus taxStatus -} - -enum TaxStatus { - child, student, adult, retired -} - -% A child cannot have any dependents. -error invalidTaxStatus(Person p) <-> - taxStatus(p, child), children(p, _q). - -unique family. -Family(family). -members(family, anne). -members(family, bob). -members(family, ciri). -children(anne, ciri). -?children(bob, ciri). -default children(ciri, *): false. -taxStatus(anne, adult). -age(anne, 35). -bobAge: 27. -age(bob, bobAge). -!age(ciri, bobAge). - -scope Family = 1, Person += 5..10. -`; - -const rootStore = new RootStore(); -rootStore.editorStore.updateValue(initialValue); - -const theme = createTheme({ - palette: { - mode: 'dark', - background: { - default: '#212121', - paper: '#2f2f2f', - }, - primary: { - main: '#82aaff', - }, - secondary: { - main: '#ff5370', - }, - }, -}); - -const app = ( - - - - - - - - -) - -render(app, document.getElementById('app')); diff --git a/language-web/src/main/js/index.tsx b/language-web/src/main/js/index.tsx new file mode 100644 index 00000000..f59b40a9 --- /dev/null +++ b/language-web/src/main/js/index.tsx @@ -0,0 +1,79 @@ +import { CacheProvider } from "@emotion/react"; +import React from 'react'; +import { render } from 'react-dom'; +import CssBaseline from '@material-ui/core/CssBaseline'; +import { ThemeProvider, createTheme } from '@material-ui/core/styles'; +import { getCache } from "tss-react/cache"; + +import App from './App'; +import RootStore, { RootStoreProvider } from './RootStore'; + +import '../css/index.scss'; + +const initialValue = `class Family { + contains Person[] members +} + +class Person { + Person[] children opposite parent + Person[0..1] parent opposite children + int age + TaxStatus taxStatus +} + +enum TaxStatus { + child, student, adult, retired +} + +% A child cannot have any dependents. +error invalidTaxStatus(Person p) <-> + taxStatus(p, child), children(p, _q). + +unique family. +Family(family). +members(family, anne). +members(family, bob). +members(family, ciri). +children(anne, ciri). +?children(bob, ciri). +default children(ciri, *): false. +taxStatus(anne, adult). +age(anne, 35). +bobAge: 27. +age(bob, bobAge). +!age(ciri, bobAge). + +scope Family = 1, Person += 5..10. +`; + +const rootStore = new RootStore(); +rootStore.editorStore.updateValue(initialValue); + +const theme = createTheme({ + palette: { + mode: 'dark', + background: { + default: '#212121', + paper: '#2f2f2f', + }, + primary: { + main: '#82aaff', + }, + secondary: { + main: '#ff5370', + }, + }, +}); + +const app = ( + + + + + + + + +); + +render(app, document.getElementById('app')); diff --git a/language-web/src/main/js/makeStyles.js b/language-web/src/main/js/makeStyles.js deleted file mode 100644 index 1dee6c1f..00000000 --- a/language-web/src/main/js/makeStyles.js +++ /dev/null @@ -1,4 +0,0 @@ -import { createMakeStyles } from "tss-react"; -import { useTheme } from "@material-ui/core/styles"; - -export const { makeStyles } = createMakeStyles({ useTheme }); diff --git a/language-web/src/main/js/makeStyles.ts b/language-web/src/main/js/makeStyles.ts new file mode 100644 index 00000000..1dee6c1f --- /dev/null +++ b/language-web/src/main/js/makeStyles.ts @@ -0,0 +1,4 @@ +import { createMakeStyles } from "tss-react"; +import { useTheme } from "@material-ui/core/styles"; + +export const { makeStyles } = createMakeStyles({ useTheme }); diff --git a/language-web/src/main/js/xtext/xtext-codemirror.d.ts b/language-web/src/main/js/xtext/xtext-codemirror.d.ts new file mode 100644 index 00000000..fff850b8 --- /dev/null +++ b/language-web/src/main/js/xtext/xtext-codemirror.d.ts @@ -0,0 +1,43 @@ +import { Editor } from 'codemirror'; + +export function createEditor(options: IXtextOptions): IXtextCodeMirrorEditor; + +export function createServices(editor: Editor, options: IXtextOptions): IXtextServices; + +export function removeServices(editor: Editor): void; + +export interface IXtextOptions { + baseUrl?: string; + contentType?: string; + dirtyElement?: string | Element; + dirtyStatusClass?: string; + document?: Document; + enableContentAssistService?: boolean; + enableCors?: boolean; + enableFormattingAction?: boolean; + enableFormattingService?: boolean; + enableGeneratorService?: boolean; + enableHighlightingService?: boolean; + enableOccurrencesService?: boolean; + enableSaveAction?: boolean; + enableValidationService?: boolean; + loadFromServer?: boolean; + mode?: string; + parent?: string | Element; + parentClass?: string; + resourceId?: string; + selectionUpdateDelay?: number; + sendFullText?: boolean; + serviceUrl?: string; + showErrorDialogs?: boolean; + syntaxDefinition?: string; + textUpdateDelay?: number; + xtextLang?: string; +} + +export interface IXtextCodeMirrorEditor extends Editor { + xtextServices: IXtextServices; +} + +export interface IXtextServices { +} -- cgit v1.2.3-54-g00ecf