Code editor

The editor is Monaco

Monaco Editor 0.57.0 (MIT) is vendored in this repository in vendor/monaco and copied to dist/monaco/vs: the loader, the editor, its workers and the languages CSS, SCSS, HTML, JavaScript and JSON (7.4 MB in the folder, of which a page loads about 40 KB at first and about 6 MB when the first editor opens). Other languages and the TypeScript and JavaScript language service are not shipped, so JavaScript is coloured but has no completions or checks. Monaco is not part of tsunami.min.js: a page with an editor loads loader.js with its own script before the Tsunami script. The loader finds the rest next to itself, so it works from jsDelivr as well as from your own server. From another origin Monaco starts its web workers from blob URLs, which needs the CORS header that jsDelivr sends.

<script src="https://cdn.jsdelivr.net/gh/Djirasak/tsunami-framework@v0.1.3/dist/monaco/vs/loader.js"></script>
<script src="https://cdn.jsdelivr.net/gh/Djirasak/tsunami-framework@v0.1.3/dist/tsunami.min.js"></script>

If a .code-editor is on a page and the loader is not, the script throws an error that says so. The loader defines the globals require and define, as an AMD loader does. A library that ships as UMD (Chart.js, Vanilla Calendar, ...) registers itself as an AMD module when it finds define.amd and does not set its global, so load such libraries before loader.js, or not on the same page. Another AMD loader such as RequireJS cannot share the page with Monaco's.

Basic

A .code-editor box wraps a textarea that holds the code. data-language picks the language; without it the code is plain text. A label for the textarea names the editor and focuses it.

Languages

HTML, CSS, SCSS, JavaScript and JSON are coloured. The grid and the heights are the page's: the box takes its height from style.

Read only

readonly on the textarea (or disabled) shows the code but blocks typing. It can still be selected and copied.

In a form

The textarea keeps the code, so the form sends it and new FormData(form) reads it. After each edit the textarea sends a bubbling input event; here the form's oninput copies the code into the result block.

Type in the editor.

A script reads and sets the code

The element's editor property is the Monaco instance (null until it has loaded), so getValue() and setValue() are Monaco's own. Setting the code also updates the textarea and sends input.

Nothing read yet.

Several files

One box can hold several textareas, one per file. The textarea that is not hidden is the one shown; here the tabs component shows and hides them (each textarea is a tab panel). Each file keeps its cursor, scroll and undo history, and the form sends every file. Closing a tab removes its textarea and its file.

Nothing sent yet.

Options through mount()

tsunami.codeEditor.mount(el, options) starts a box and takes any Monaco editor option over the defaults. It also starts a box that does not have the class.

Features

  • Until Monaco has loaded the textarea is the editor, in a monospace field of the same height. Then the box gets data-loaded, Monaco takes its place and the textarea stays in the form, out of sight.
  • Defaults: automaticLayout on, fontSize 13, no minimap, scrollBeyondLastLine off, the framework's monospace font.
  • Monaco has one theme per page. Two themes are built from the CSS variables (surface, text, line, accent, and the ok, warning, danger and info colours for the code), and the editor switches on tsunami:themechange.
  • A box takes its height from the page (default 10rem). It has a 1px border, no shadow, and the accent border while it has focus.
  • Reset on the form puts the textareas' default text back into the editor.

Attributes

Attribute Where Description
data-language box or textarea html, css, scss, javascript or json. Plain text otherwise. A textarea's own value wins over the box's.
readonly, disabled textarea The editor is read only.
aria-label textarea or box Names the editor. A label for the textarea or an aria-labelledby works too.
hidden textarea In a box with several textareas, the file that is not shown. Toggling it switches the file.
name textarea The form field that carries the code.
data-loaded box, set by the script Monaco has started.

API

The functions live on window.tsunami.codeEditor.

Function Description
tsunami.codeEditor.mount(el, options?) Starts an editor on a box, with or without the class, and starts it again if it already has one. options are Monaco editor options.
tsunami.codeEditor.get(el) The Monaco instance, or null before it has started.
tsunami.codeEditor.destroy(el) Removes the editor and shows the textareas again with the code as it stands. Removing the box from the page does this itself.

On the element

Member Description
el.editor On the .code-editor box (not the textarea): the Monaco instance, null until it has started. It has Monaco's methods: getValue(), setValue(text), focus(), updateOptions(). They work on the file being shown.
textarea.value The code, kept up to date as it is edited. Setting it does not change the editor: call setValue().

Events

Event Detail Description
tsunami:codeeditorready { editor } From the box, bubbling, when Monaco has started.
input From the textarea of the file being edited, bubbling, after each edit. The save bar listens to it.
tsunami:themechange { theme } From the theme module; the editor switches theme.

Keyboard

These are Monaco's own.

Keys Action
Ctrl F Find in the code.
F1 Monaco's command list.
Ctrl M Tab moves focus out of the editor instead of indenting (and back).

Accessibility

  • Name every editor: aria-label on the textarea, or a label for it. A label click focuses the editor.
  • A required or invalid textarea that gets the browser's message passes the focus to the editor.
  • With several files, give each tab aria-controls pointing at its textarea, as in the example.
  • Monaco's screen reader support turns on when a screen reader is detected. Press Ctrl M so that Tab leaves the editor.