mirror of
https://github.com/microsoft/monaco-editor.git
synced 2025-12-22 08:10:11 +01:00
Merge branch 'main' into mdx
This commit is contained in:
commit
ef3a98e0a2
18 changed files with 4711 additions and 579 deletions
|
|
@ -14,6 +14,8 @@ import { exit } from "process";
|
|||
"yarn",
|
||||
[
|
||||
"tsc",
|
||||
"--target",
|
||||
"es6",
|
||||
"--noEmit",
|
||||
"--allowJs",
|
||||
"--checkJs",
|
||||
|
|
|
|||
|
|
@ -21,12 +21,24 @@ export interface IMonacoSetup {
|
|||
monacoTypesUrl: string | undefined;
|
||||
}
|
||||
|
||||
let loadMonacoPromise: Promise<typeof monaco> | undefined;
|
||||
let loading = false;
|
||||
let resolve: (value: typeof monaco) => void;
|
||||
let reject: (error: unknown) => void;
|
||||
let loadMonacoPromise = new Promise<typeof monaco>((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
|
||||
export async function waitForLoadedMonaco(): Promise<typeof monaco> {
|
||||
return loadMonacoPromise;
|
||||
}
|
||||
|
||||
export async function loadMonaco(
|
||||
setup: IMonacoSetup = prodMonacoSetup
|
||||
): Promise<typeof monaco> {
|
||||
if (!loadMonacoPromise) {
|
||||
loadMonacoPromise = _loadMonaco(setup);
|
||||
if (!loading) {
|
||||
loading = true;
|
||||
_loadMonaco(setup).then(resolve, reject);
|
||||
}
|
||||
return loadMonacoPromise;
|
||||
}
|
||||
|
|
|
|||
48
website/src/website/data/home-samples/sample.wgsl.txt
Normal file
48
website/src/website/data/home-samples/sample.wgsl.txt
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
// A fragment shader which lights textured geometry with point lights.
|
||||
// Taken from the introduction of the WebGPU Shading Lnaguage Specification
|
||||
// https://w3.org/TR/WGSL
|
||||
|
||||
// Lights from a storage buffer binding.
|
||||
struct PointLight {
|
||||
position : vec3f,
|
||||
color : vec3f,
|
||||
}
|
||||
|
||||
struct LightStorage {
|
||||
pointCount : u32,
|
||||
point : array<PointLight>,
|
||||
}
|
||||
@group(0) @binding(0) var<storage> lights : LightStorage;
|
||||
|
||||
// Texture and sampler.
|
||||
@group(1) @binding(0) var baseColorSampler : sampler;
|
||||
@group(1) @binding(1) var baseColorTexture : texture_2d<f32>;
|
||||
|
||||
// Function arguments are values from from vertex shader.
|
||||
@fragment
|
||||
fn fragmentMain(@location(0) worldPos : vec3f,
|
||||
@location(1) normal : vec3f,
|
||||
@location(2) uv : vec2f) -> @location(0) vec4f {
|
||||
// Sample the base color of the surface from a texture.
|
||||
let baseColor = textureSample(baseColorTexture, baseColorSampler, uv);
|
||||
|
||||
let N = normalize(normal);
|
||||
var surfaceColor = vec3f(0);
|
||||
|
||||
// Loop over the scene point lights.
|
||||
for (var i = 0u; i < lights.pointCount; i++) {
|
||||
let worldToLight = lights.point[i].position - worldPos;
|
||||
let dist = length(worldToLight);
|
||||
let dir = normalize(worldToLight);
|
||||
|
||||
// Determine the contribution of this light to the surface color.
|
||||
let radiance = lights.point[i].color * (1 / pow(dist, 2));
|
||||
let nDotL = max(dot(N, dir), 0);
|
||||
|
||||
// Accumulate light contribution to the surface color.
|
||||
surfaceColor += baseColor.rgb * radiance * nDotL;
|
||||
}
|
||||
|
||||
// Return the accumulated surface color.
|
||||
return vec4(surfaceColor, baseColor.a);
|
||||
}
|
||||
|
|
@ -11,10 +11,12 @@ customElements.define(
|
|||
const shadowRoot = this.attachShadow({ mode: "open" });
|
||||
|
||||
// Copy over editor styles
|
||||
const style = document.querySelector(
|
||||
"link[rel='stylesheet'][data-name='vs/editor/editor.main']"
|
||||
const styles = document.querySelectorAll(
|
||||
"link[rel='stylesheet'][data-name^='vs/']"
|
||||
);
|
||||
shadowRoot.appendChild(style.cloneNode(true));
|
||||
for (const style of styles) {
|
||||
shadowRoot.appendChild(style.cloneNode(true));
|
||||
}
|
||||
|
||||
const template = /** @type HTMLTemplateElement */ (
|
||||
document.getElementById("editor-template")
|
||||
|
|
|
|||
|
|
@ -12,7 +12,11 @@ import {
|
|||
reaction,
|
||||
runInAction,
|
||||
} from "mobx";
|
||||
import { IMonacoSetup, loadMonaco } from "../../../monaco-loader";
|
||||
import {
|
||||
IMonacoSetup,
|
||||
loadMonaco,
|
||||
waitForLoadedMonaco,
|
||||
} from "../../../monaco-loader";
|
||||
import { IPlaygroundProject, IPreviewState } from "../../../shared";
|
||||
import { monacoEditorVersion } from "../../monacoEditorVersion";
|
||||
import { Debouncer } from "../../utils/Debouncer";
|
||||
|
|
@ -56,12 +60,23 @@ export class PlaygroundModel {
|
|||
|
||||
public readonly serializer = new StateUrlSerializer(this);
|
||||
|
||||
reload(): void {
|
||||
public reload(): void {
|
||||
this.reloadKey++;
|
||||
}
|
||||
|
||||
private readonly _previewHandlers = new Set<IPreviewHandler>();
|
||||
|
||||
private _wasEverNonFullScreen = false;
|
||||
public get wasEverNonFullScreen() {
|
||||
if (this._wasEverNonFullScreen) {
|
||||
return true;
|
||||
}
|
||||
if (!this.settings.previewFullScreen) {
|
||||
this._wasEverNonFullScreen = true;
|
||||
}
|
||||
return this._wasEverNonFullScreen;
|
||||
}
|
||||
|
||||
@computed.struct
|
||||
get monacoSetup(): IMonacoSetup {
|
||||
const sourceOverride = this.serializer.sourceOverride;
|
||||
|
|
@ -125,14 +140,31 @@ export class PlaygroundModel {
|
|||
}
|
||||
}
|
||||
|
||||
private readonly debouncer = new Debouncer(250);
|
||||
private readonly debouncer = new Debouncer(700);
|
||||
|
||||
@observable
|
||||
public isDirty = false;
|
||||
|
||||
constructor() {
|
||||
let lastState = this.state;
|
||||
|
||||
this.dispose.track({
|
||||
dispose: reaction(
|
||||
() => ({ state: this.state }),
|
||||
({ state }) => {
|
||||
if (!this.settings.autoReload) {
|
||||
if (
|
||||
JSON.stringify(state.monacoSetup) ===
|
||||
JSON.stringify(lastState.monacoSetup) &&
|
||||
state.key === lastState.key
|
||||
) {
|
||||
this.isDirty = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.debouncer.run(() => {
|
||||
this.isDirty = false;
|
||||
lastState = state;
|
||||
for (const handler of this._previewHandlers) {
|
||||
handler.handlePreview(state);
|
||||
}
|
||||
|
|
@ -142,10 +174,10 @@ export class PlaygroundModel {
|
|||
),
|
||||
});
|
||||
|
||||
const observablePromise = new ObservablePromise(loadMonaco());
|
||||
const observablePromise = new ObservablePromise(waitForLoadedMonaco());
|
||||
let disposable: Disposable | undefined = undefined;
|
||||
|
||||
loadMonaco().then((m) => {
|
||||
waitForLoadedMonaco().then((m) => {
|
||||
const options =
|
||||
monaco.languages.typescript.javascriptDefaults.getCompilerOptions();
|
||||
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions(
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import { PlaygroundModel } from "./PlaygroundModel";
|
|||
import { Preview } from "./Preview";
|
||||
import { SettingsDialog } from "./SettingsDialog";
|
||||
import { Button, Col, Row, Stack } from "../../components/bootstrap";
|
||||
import { ButtonGroup } from "react-bootstrap";
|
||||
import { ButtonGroup, FormCheck } from "react-bootstrap";
|
||||
|
||||
@hotComponent(module)
|
||||
@observer
|
||||
|
|
@ -37,88 +37,122 @@ export class PlaygroundPageContent extends React.Component<
|
|||
className="h-100 g-2"
|
||||
style={{ flexWrap: "wrap-reverse" }}
|
||||
>
|
||||
<Col
|
||||
md
|
||||
className={
|
||||
model.settings.previewFullScreen ? "d-none" : ""
|
||||
}
|
||||
>
|
||||
<Vertical>
|
||||
<div style={{ flex: 1 }}>
|
||||
<LabeledEditor
|
||||
label="JavaScript"
|
||||
titleBarItems={
|
||||
<div
|
||||
className="hstack"
|
||||
style={{ marginLeft: "auto" }}
|
||||
>
|
||||
<span
|
||||
style={{ marginRight: 8 }}
|
||||
{model.wasEverNonFullScreen && (
|
||||
<Col
|
||||
md
|
||||
className={
|
||||
model.settings.previewFullScreen
|
||||
? "d-none"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
<Vertical>
|
||||
<div style={{ flex: 1 }}>
|
||||
<LabeledEditor
|
||||
label="JavaScript"
|
||||
titleBarItems={
|
||||
<div
|
||||
className="hstack"
|
||||
style={{
|
||||
marginLeft: "auto",
|
||||
}}
|
||||
>
|
||||
Example:
|
||||
</span>
|
||||
<Select<PlaygroundExample>
|
||||
values={getPlaygroundExamples().map(
|
||||
(e) => ({
|
||||
groupTitle:
|
||||
e.chapterTitle,
|
||||
items: e.examples,
|
||||
})
|
||||
)}
|
||||
value={ref(
|
||||
model,
|
||||
"selectedExample"
|
||||
)}
|
||||
getLabel={(i) => i.title}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Editor
|
||||
language={"javascript"}
|
||||
value={ref(model, "js")}
|
||||
/>
|
||||
</LabeledEditor>
|
||||
</div>
|
||||
<span
|
||||
style={{
|
||||
marginRight: 8,
|
||||
}}
|
||||
>
|
||||
Example:
|
||||
</span>
|
||||
<Select<PlaygroundExample>
|
||||
values={getPlaygroundExamples().map(
|
||||
(e) => ({
|
||||
groupTitle:
|
||||
e.chapterTitle,
|
||||
items: e.examples,
|
||||
})
|
||||
)}
|
||||
value={ref(
|
||||
model,
|
||||
"selectedExample"
|
||||
)}
|
||||
getLabel={(i) =>
|
||||
i.title
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Editor
|
||||
language={"javascript"}
|
||||
value={ref(model, "js")}
|
||||
/>
|
||||
</LabeledEditor>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<LabeledEditor label="HTML">
|
||||
<Editor
|
||||
height={{
|
||||
kind: "dynamic",
|
||||
maxHeight: 200,
|
||||
}}
|
||||
language={"html"}
|
||||
value={ref(model, "html")}
|
||||
/>
|
||||
</LabeledEditor>
|
||||
</div>
|
||||
<div>
|
||||
<LabeledEditor label="HTML">
|
||||
<Editor
|
||||
height={{
|
||||
kind: "dynamic",
|
||||
maxHeight: 200,
|
||||
}}
|
||||
language={"html"}
|
||||
value={ref(model, "html")}
|
||||
/>
|
||||
</LabeledEditor>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<LabeledEditor label="CSS">
|
||||
<Editor
|
||||
height={{
|
||||
kind: "dynamic",
|
||||
maxHeight: 200,
|
||||
}}
|
||||
language={"css"}
|
||||
value={ref(model, "css")}
|
||||
/>
|
||||
</LabeledEditor>
|
||||
</div>
|
||||
</Vertical>
|
||||
</Col>
|
||||
<div>
|
||||
<LabeledEditor label="CSS">
|
||||
<Editor
|
||||
height={{
|
||||
kind: "dynamic",
|
||||
maxHeight: 200,
|
||||
}}
|
||||
language={"css"}
|
||||
value={ref(model, "css")}
|
||||
/>
|
||||
</LabeledEditor>
|
||||
</div>
|
||||
</Vertical>
|
||||
</Col>
|
||||
)}
|
||||
<Col md>
|
||||
<LabeledEditor
|
||||
label="Preview"
|
||||
titleBarItems={
|
||||
<div
|
||||
style={{ marginLeft: "auto" }}
|
||||
className="d-flex gap-2"
|
||||
className="d-flex gap-2 align-items-center"
|
||||
>
|
||||
{model.settings.previewFullScreen || (
|
||||
<FormCheck
|
||||
label="Auto-Reload"
|
||||
className="text-nowrap"
|
||||
checked={
|
||||
model.settings.autoReload
|
||||
}
|
||||
onChange={(e) => {
|
||||
model.settings.autoReload =
|
||||
e.target.checked;
|
||||
if (
|
||||
e.target.checked &&
|
||||
model.isDirty
|
||||
) {
|
||||
model.reload();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
type="button"
|
||||
className="btn btn-light settings bi-arrow-clockwise"
|
||||
className={
|
||||
"btn settings bi-arrow-clockwise " +
|
||||
(model.isDirty
|
||||
? "btn-primary"
|
||||
: "btn-light")
|
||||
}
|
||||
style={{
|
||||
fontSize: 20,
|
||||
padding: "0px 4px",
|
||||
|
|
|
|||
|
|
@ -33,6 +33,14 @@ export class SettingsModel {
|
|||
this.setSettings({ ...this._settings, previewFullScreen: value });
|
||||
}
|
||||
|
||||
get autoReload() {
|
||||
return this._settings.autoReload ?? true;
|
||||
}
|
||||
|
||||
set autoReload(value: boolean) {
|
||||
this.setSettings({ ...this._settings, autoReload: value });
|
||||
}
|
||||
|
||||
constructor() {
|
||||
const settingsStr = localStorage.getItem(this.settingsKey);
|
||||
if (settingsStr) {
|
||||
|
|
@ -70,6 +78,7 @@ export interface Settings {
|
|||
customConfig: JsonString<IMonacoSetup>;
|
||||
|
||||
previewFullScreen: boolean;
|
||||
autoReload: boolean | undefined;
|
||||
}
|
||||
|
||||
export type JsonString<T> = string;
|
||||
|
|
@ -167,6 +176,7 @@ export function getDefaultSettings(): Settings {
|
|||
loaderPathsConfig: "",
|
||||
}),
|
||||
previewFullScreen: false,
|
||||
autoReload: true,
|
||||
};
|
||||
return defaultSettings;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue