From 37a539e14394053bc5b44dd72356a2b2f8b1b5ed Mon Sep 17 00:00:00 2001 From: leekelleher Date: Thu, 18 Jul 2024 17:56:15 +0100 Subject: [PATCH] `umb-code-editor`, async loading of monaco editor --- .../src/external/monaco-editor/index.ts | 15 +--- .../code-editor/code-editor-loaded.event.ts | 7 ++ .../code-editor/code-editor.controller.ts | 4 ++ .../code-editor/code-editor.element.ts | 70 ++++++++++++++++--- 4 files changed, 72 insertions(+), 24 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/templating/code-editor/code-editor-loaded.event.ts diff --git a/src/Umbraco.Web.UI.Client/src/external/monaco-editor/index.ts b/src/Umbraco.Web.UI.Client/src/external/monaco-editor/index.ts index ca2e3b1a7c..ecb84ae91a 100644 --- a/src/Umbraco.Web.UI.Client/src/external/monaco-editor/index.ts +++ b/src/Umbraco.Web.UI.Client/src/external/monaco-editor/index.ts @@ -13,20 +13,6 @@ import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker.js?worker import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker.js?worker'; /* eslint-enable */ -import { css, unsafeCSS } from '@umbraco-cms/backoffice/external/lit'; - -export const monacoEditorStyles = css` - ${unsafeCSS(styles)} -`; - -export const monacoJumpingCursorHack = css` - /* a hacky workaround this issue: https://github.com/microsoft/monaco-editor/issues/3217 - should probably be removed when the issue is fixed */ - .view-lines { - font-feature-settings: revert !important; - } -`; - const initializeWorkers = () => { self.MonacoEnvironment = { getWorker(workerId: string, label: string): Promise | Worker { @@ -50,3 +36,4 @@ const initializeWorkers = () => { initializeWorkers(); export * as monaco from 'monaco-editor'; +export { styles }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/code-editor/code-editor-loaded.event.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/code-editor/code-editor-loaded.event.ts new file mode 100644 index 0000000000..01b07ef01b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/code-editor/code-editor-loaded.event.ts @@ -0,0 +1,7 @@ +export class UmbCodeEditorLoadedEvent extends Event { + public static readonly TYPE = 'loaded'; + + public constructor() { + super(UmbCodeEditorLoadedEvent.TYPE, { bubbles: true, composed: true, cancelable: false }); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/code-editor/code-editor.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/code-editor/code-editor.controller.ts index b1a417ebc5..2553330281 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/code-editor/code-editor.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/code-editor/code-editor.controller.ts @@ -144,6 +144,7 @@ export class UmbCodeEditorController { this.#editor?.onDidChangeModel(() => { this.#host.dispatchEvent(new UmbChangeEvent()); }); + this.#editor?.onDidChangeCursorPosition((e) => { this.#position = e.position; this.#secondaryPositions = e.secondaryPositions; @@ -192,6 +193,7 @@ export class UmbCodeEditorController { readOnly: this.#host.readonly, ariaLabel: this.#host.label, }); + this.#initiateEvents(); } /** @@ -376,3 +378,5 @@ export class UmbCodeEditorController { }); } } + +export default UmbCodeEditorController; diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/code-editor/code-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/code-editor/code-editor.element.ts index c7858ecfda..e7a35e4c48 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/code-editor/code-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/code-editor/code-editor.element.ts @@ -1,12 +1,24 @@ -import { UmbCodeEditorController } from './code-editor.controller.js'; +import type { UmbCodeEditorController } from './code-editor.controller.js'; import type { CodeEditorLanguage, CodeEditorSearchOptions, UmbCodeEditorHost } from './code-editor.model.js'; import { CodeEditorTheme } from './code-editor.model.js'; +import { UmbCodeEditorLoadedEvent } from './code-editor-loaded.event.js'; import { UMB_THEME_CONTEXT } from '@umbraco-cms/backoffice/themes'; -import { monacoEditorStyles, monacoJumpingCursorHack } from '@umbraco-cms/backoffice/external/monaco-editor'; import type { PropertyValues, Ref } from '@umbraco-cms/backoffice/external/lit'; -import { css, html, createRef, ref, customElement, property } from '@umbraco-cms/backoffice/external/lit'; +import { + createRef, + css, + customElement, + html, + property, + ref, + state, + unsafeCSS, + when, +} from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +const elementName = 'umb-code-editor'; + /** * A custom element that renders a code editor. Code editor is based on the Monaco Editor library. * The element will listen to the theme context and update the theme accordingly. @@ -21,7 +33,7 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; * @fires input - Fired when the value of the editor changes. * @fires change - Fired when the entire model of editor is replaced. */ -@customElement('umb-code-editor') +@customElement(elementName) export class UmbCodeEditorElement extends UmbLitElement implements UmbCodeEditorHost { private containerRef: Ref = createRef(); @@ -88,8 +100,15 @@ export class UmbCodeEditorElement extends UmbLitElement implements UmbCodeEditor @property({ type: Boolean, attribute: 'readonly' }) readonly = false; + @state() + private _loading = true; + + @state() + private _styles?: string; + constructor() { super(); + this.consumeContext(UMB_THEME_CONTEXT, (instance) => { this.observe( instance.theme, @@ -101,8 +120,15 @@ export class UmbCodeEditorElement extends UmbLitElement implements UmbCodeEditor }); } - override firstUpdated() { - this.#editor = new UmbCodeEditorController(this); + override async firstUpdated() { + const { styles } = await import('@umbraco-cms/backoffice/external/monaco-editor'); + this._styles = styles; + + const controller = (await import('./code-editor.controller.js')).default; + this.#editor = new controller(this); + + this._loading = false; + this.dispatchEvent(new UmbCodeEditorLoadedEvent()); } protected override updated(_changedProperties: PropertyValues): void { @@ -149,16 +175,34 @@ export class UmbCodeEditorElement extends UmbLitElement implements UmbCodeEditor } override render() { - return html`
`; + return html` + ${this.#renderStyles()} + ${when(this._loading, () => html`
`)} +
+ `; + } + + #renderStyles() { + if (!this._styles) return; + return html` + + `; } static override styles = [ - monacoEditorStyles, - monacoJumpingCursorHack, css` :host { display: block; } + + #loader-container { + display: grid; + place-items: center; + min-height: calc(100dvh - 260px); + } + #editor-container { width: var(--editor-width); height: var(--editor-height, 100%); @@ -167,6 +211,12 @@ export class UmbCodeEditorElement extends UmbLitElement implements UmbCodeEditor --vscode-scrollbarSlider-background: var(--uui-color-disabled-contrast); --vscode-scrollbarSlider-hoverBackground: rgba(100, 100, 100, 0.7); --vscode-scrollbarSlider-activeBackground: rgba(0, 0, 0, 0.6); + + /* a hacky workaround this issue: https://github.com/microsoft/monaco-editor/issues/3217 + should probably be removed when the issue is fixed */ + .view-lines { + font-feature-settings: revert !important; + } } `, ]; @@ -174,6 +224,6 @@ export class UmbCodeEditorElement extends UmbLitElement implements UmbCodeEditor declare global { interface HTMLElementTagNameMap { - 'umb-code-editor': UmbCodeEditorElement; + [elementName]: UmbCodeEditorElement; } }