Adds web editor support to playground

This commit is contained in:
Henning Dieterichs 2024-05-02 16:46:43 +02:00 committed by Henning Dieterichs
parent 418ae49a8e
commit 27978a8064
17 changed files with 91 additions and 27 deletions

View file

@ -28,7 +28,8 @@
"react": "^17.0.2", "react": "^17.0.2",
"react-bootstrap": "^2.4.0", "react-bootstrap": "^2.4.0",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"typedoc": "^0.23.26" "typedoc": "^0.23.26",
"@vscode/web-editors": "./vscode-web-editors.tgz"
}, },
"devDependencies": { "devDependencies": {
"@types/classnames": "^2.3.1", "@types/classnames": "^2.3.1",

View file

@ -1,4 +1,4 @@
import React = require("react"); import * as React from "react";
import { home, playground, docs, monarch } from "../pages/routes"; import { home, playground, docs, monarch } from "../pages/routes";
import { Container, Navbar, Nav, NavDropdown } from "./bootstrap"; import { Container, Navbar, Nav, NavDropdown } from "./bootstrap";

View file

@ -1,4 +1,4 @@
import React = require("react"); import * as React from "react";
import { PageNav } from "./Nav"; import { PageNav } from "./Nav";
export function Page(props: { children: React.ReactNode }) { export function Page(props: { children: React.ReactNode }) {

View file

@ -1,5 +1,5 @@
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import React = require("react"); import * as React from "react";
import { IReference } from "../utils/ref"; import { IReference } from "../utils/ref";
import { Form } from "./bootstrap"; import { Form } from "./bootstrap";

View file

@ -3,6 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as packageJson from "monaco-editor/package.json"; import packageJson from "monaco-editor/package.json";
export const monacoEditorVersion = packageJson.version; export const monacoEditorVersion = packageJson.version;

View file

@ -1,7 +1,7 @@
import { Home } from "./home/Home"; import { Home } from "./home/Home";
import { PlaygroundPage } from "./playground/PlaygroundPage"; import { PlaygroundPage } from "./playground/PlaygroundPage";
import { docs, home, monarch, playground } from "./routes"; import { docs, home, monarch, playground } from "./routes";
import React = require("react"); import * as React from "react";
import { DocsPage } from "./DocsPage"; import { DocsPage } from "./DocsPage";
import { MonarchPage } from "./MonarchPage"; import { MonarchPage } from "./MonarchPage";

View file

@ -5,7 +5,7 @@ import {
IHistoryModel, IHistoryModel,
ILocation, ILocation,
} from "../utils/ObservableHistory"; } from "../utils/ObservableHistory";
import React = require("react"); import * as React from "react";
export class DocsPage extends React.Component implements IHistoryModel { export class DocsPage extends React.Component implements IHistoryModel {
private _lastIFrame: HTMLIFrameElement | null = null; private _lastIFrame: HTMLIFrameElement | null = null;

View file

@ -1,4 +1,4 @@
import React = require("react"); import * as React from "react";
import { Page } from "../components/Page"; import { Page } from "../components/Page";
export class MonarchPage extends React.Component<{}, {}> { export class MonarchPage extends React.Component<{}, {}> {

View file

@ -8,7 +8,7 @@ import {
ControlledMonacoEditor, ControlledMonacoEditor,
} from "../../components/monaco/MonacoEditor"; } from "../../components/monaco/MonacoEditor";
import { ObservablePromise } from "../../utils/ObservablePromise"; import { ObservablePromise } from "../../utils/ObservablePromise";
import React = require("react"); import * as React from "react";
import { ref } from "../../utils/ref"; import { ref } from "../../utils/ref";
import { monacoEditorVersion } from "../../monacoEditorVersion"; import { monacoEditorVersion } from "../../monacoEditorVersion";

View file

@ -38,13 +38,18 @@ export class LocationModel implements IHistoryModel {
*/ */
@observable historyId: number = 0; @observable historyId: number = 0;
constructor(private readonly model: PlaygroundModel) { constructor(
this.dispose.track( private readonly model: PlaygroundModel,
new HistoryController((initialLocation) => { createHistoryController = true
this.updateLocation(initialLocation); ) {
return this; if (createHistoryController) {
}) this.dispose.track(
); new HistoryController((initialLocation) => {
this.updateLocation(initialLocation);
return this;
})
);
}
} }
get location(): ILocation { get location(): ILocation {

View file

@ -30,6 +30,7 @@ import {
} from "./SettingsModel"; } from "./SettingsModel";
import { BisectModel } from "./BisectModel"; import { BisectModel } from "./BisectModel";
import { LocationModel } from "./LocationModel"; import { LocationModel } from "./LocationModel";
import { createJsonWebEditorClient, vObj, vString } from "@vscode/web-editors";
export class PlaygroundModel { export class PlaygroundModel {
public readonly dispose = Disposable.fn(); public readonly dispose = Disposable.fn();
@ -47,7 +48,25 @@ export class PlaygroundModel {
@observable @observable
public reloadKey = 0; public reloadKey = 0;
public readonly historyModel = new LocationModel(this); private readonly webEditorClient = createJsonWebEditorClient(
vObj({
js: vString(),
html: vString(),
css: vString(),
}),
(data) => {
runInAction(() => {
this.html = data.html;
this.js = data.js;
this.css = data.css;
});
}
);
public readonly historyModel = new LocationModel(
this,
this.webEditorClient === undefined
);
public reload(): void { public reload(): void {
this.reloadKey++; this.reloadKey++;
@ -163,6 +182,17 @@ export class PlaygroundModel {
constructor() { constructor() {
let lastState: IPreviewState | undefined = undefined; let lastState: IPreviewState | undefined = undefined;
this.webEditorClient?.onDidConnect.then(() => {
autorun(() => {
const state = this.playgroundProject;
this.webEditorClient!.updateContent({
js: state.js,
html: state.html,
css: state.css,
});
});
});
this.dispose.track({ this.dispose.track({
dispose: reaction( dispose: reaction(
() => ({ state: this.state }), () => ({ state: this.state }),

View file

@ -42,7 +42,12 @@ export class SettingsModel {
} }
constructor() { constructor() {
const settingsStr = localStorage.getItem(this.settingsKey); const settingsStr = "";
try {
localStorage.getItem(this.settingsKey);
} catch (e) {
console.error("Failed to load settings from localStorage", e);
}
if (settingsStr) { if (settingsStr) {
this._settings = JSON.parse(settingsStr); this._settings = JSON.parse(settingsStr);
} else { } else {
@ -54,7 +59,11 @@ export class SettingsModel {
setSettings(settings: Settings): void { setSettings(settings: Settings): void {
const settingsJson = JSON.stringify(toJS(settings)); const settingsJson = JSON.stringify(toJS(settings));
this._settings = JSON.parse(settingsJson); this._settings = JSON.parse(settingsJson);
localStorage.setItem(this.settingsKey, settingsJson); try {
localStorage.setItem(this.settingsKey, settingsJson);
} catch (e) {
console.error("Failed to save settings to localStorage", e);
}
} }
} }

View file

@ -1,4 +1,3 @@
import { normalizeLineEnding } from "./utils";
import { IPlaygroundProject } from "../../../shared"; import { IPlaygroundProject } from "../../../shared";
export function findLastIndex<T>( export function findLastIndex<T>(

View file

@ -2,18 +2,15 @@
"compilerOptions": { "compilerOptions": {
"target": "esnext", "target": "esnext",
"module": "commonjs", "module": "commonjs",
"moduleResolution": "node16", "moduleResolution": "Node",
"strict": true, "strict": true,
"outDir": "dist", "outDir": "dist",
"skipLibCheck": true, "skipLibCheck": true,
"rootDir": "./src",
"resolveJsonModule": true, "resolveJsonModule": true,
"newLine": "LF", "newLine": "LF",
"sourceMap": true, "sourceMap": true,
"jsx": "react", "useDefineForClassFields": false,
"experimentalDecorators": true, "noEmit": true
// to enable mobx decorators
"useDefineForClassFields": false
}, },
"include": ["src/**/*", "./node_modules/monaco-editor/monaco.d.ts"] "exclude": ["src/**/*", "./node_modules/monaco-editor/monaco.d.ts"]
} }

19
website/tsconfig.web.json Normal file
View file

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "esnext",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"outDir": "dist",
"skipLibCheck": true,
"rootDir": "./src",
"resolveJsonModule": true,
"newLine": "LF",
"sourceMap": true,
"jsx": "react",
"experimentalDecorators": true,
"useDefineForClassFields": false,
"noEmit": true
},
"include": ["src/**/*", "./node_modules/monaco-editor/monaco.d.ts"]
}

Binary file not shown.

View file

@ -487,6 +487,10 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@vscode/web-editors@./vscode-web-editors.tgz":
version "0.1.0"
resolved "./vscode-web-editors.tgz#657c1b47d50dfd1a457f660e3184fb88121f8b24"
"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": "@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5":
version "1.11.6" version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24"