Editor Component — Feature Inventory

Complete inventory of the author-facing features of the Merlin MyST Editor, the published component that provides Instructor Studio’s editing surface, as verified against the live code in the codermerlin.academy-pocs repository (instructor-studio/component-assemblies/myst-editor/) at POC build 213 (--poc-version: build 213 · 20260910T123348).

The component is hosted by the Studio’s application shell (js/app.js). Component features render identically in the Studio preview, the Student Lab POC and published lessons when all three resolve the component from the published-components catalog; see the index’s note on the three surfaces for what changes under a local-component override.

For the component’s programmatic surface — its public API, its events, and the Studio SDK it consumes from the host — see Formats and Contracts. For the application around it, see Studio Shell.

Contents

Editing surface and history

Context menu

Opened by right-click on the source pane. Disabled in student mode.

Edit group

Item Behavior
Undo Enabled when history is non-empty
Redo Enabled when the redo stack is non-empty
Find… Opens the find bar

Text ▸ Format submenu

AST-aware toggles with state markers (✓ applied, ◪ mixed selection), in menu order:

Item Markup
Bold **…**
Italic *…*
Inline code `…` (disabled inside code/math context)
Strikethrough ~~…~~
Math $…$ (disabled inside code/math context)
Superscript {sup}`…` MyST role
Subscript {sub}`…` MyST role
Highlight ▸ Five-colour submenu — see below
Link […](url) — prompts for the URL; toggling off keeps the text

Text ▸ Format ▸ Highlight submenu

Five per-colour MyST roles, {highlight-<color>}`…`. The role names are a published-content syntax contract and are never abbreviated.

Item Emitted role
Yellow {highlight-yellow}`…`
Cyan {highlight-cyan}`…`
Green {highlight-green}`…`
Pink {highlight-pink}`…`
Orange {highlight-orange}`…`

Text ▸ Block submenu

Item Behavior
Paragraph Strips the ATX heading prefix from the current line
Heading 1–3 Converts the current line to #/##/###
Bulleted list Toggles a - prefix across the selection’s lines
Numbered list Toggles 1.-style prefixes across the selection’s lines
Blockquote Toggles a > prefix across the selection’s lines
Code block Wraps the block in a ``` fence, or unwraps it
Display math Wraps in $$ … $$, or unwraps
Display math (numbered) Wraps in $$ … $$ (eq:label) — prompts for the label and inserts a sample {eq} reference; converts between numbered and plain

Text group commands

Item Behavior
Remove redundant whitespace Tidies the selection if it contains removable content, otherwise the whole document; a second run is a no-op. Despite the name this pass does more than whitespace — see What the tidy pass actually removes. Always enabled: its precondition is invisible characters, so a scan-driven disabled state would be indistinguishable from a broken item
Clear formatting Strips inline marks overlapping the selection in one pass — bold, italic, inline code, strikethrough, math, links and highlights. {sup}/{sub} roles are deliberately not stripped (a known gap in the component, not an oversight in this document). Disabled when the selection overlaps no clearable mark

Text ▸ Insert submenu

Disabled while a selection exists — a selection means “format”, not “insert”.

Item Behavior
Box ▸ Note / Warning Native :::{note} / :::{warning} admonition — wraps the selection or inserts a sample block
Box ▸ Exercise :::{admonition} Exercise generic admonition
Box ▸ Dropdown :::{admonition} <title> + :class: dropdown — prompts for the summary; renders as a <details> element
Horizontal rule Inserts --- as a block
Table Inserts a sample 2×2 table with a header row
Image ▸ URL… Opens the image dialog (URL, alt text, width, height, scale %, alignment)
Image ▸ Upload… Stub — alerts “Upload is coming soon — for now use the URL option.”
Figure ▸ URL… Image dialog plus caption and reference label; figures are auto-numbered and referenced with {numref}
Figure ▸ Upload… Stub, as above
Merlin Terminal ▸ Empty Inserts a bare :::{merlin-terminal} directive
Merlin Terminal ▸ Challenge Opens a picker over the lesson’s challenges and inserts a challenge-scoped terminal — see Merlin Terminal embeds

Call outs submenu

Five styled admonition types. The submenu is top-level (a sibling of Insert) so it stays enabled while a selection exists. The callout-<slug> class token is the single contract for styling, detection, and menu state.

Type Emitted MyST Accent Icon
Deep Dive :::{admonition} Deep Dive + :class: callout-deep-dive blue 🤿
Fact Box :::{admonition} Fact Box + :class: callout-fact-box teal 📌
Warning :::{warning} + :class: callout-warning gold ⚠️
Danger :::{danger} + :class: callout-danger red 🚨
Observe and Ponder :::{admonition} Observe and Ponder + :class: callout-observe-and-ponder purple 🔍

Behavior:

ĀYŌDÈ Intelligence submenu

AI text operations on the current selection (requires the Studio SDK; disabled without a selection). Results are shown in a compare modal (original ↔ proposed) with Copy, Replace, Insert Before, Insert After.

Group Operations
Content Simplify · Make More Concise · Explain More (RAG) · Increase Technical Depth (RAG) · Add Example (RAG) · Add Analogy (RAG)
Clarity Improve Grammar · Improve Flow · Clarify Terminology · Improve Accessibility
Pedagogy Adapt for Younger Students · Adapt for Older Students · Increase Student Engagement · Socratic Style
Style More Formal · More Neutral · More Conversational · More Enthusiastic
Generate Summary · Key Takeaways · Learning Objectives (RAG) · Practice Questions (RAG) · Challenge Questions (RAG) · Add term to glossary…
Custom Custom… — free-form instruction

“Add term to glossary…” generates a definition matched to the lesson’s language level and lands it in the glossary define dialog for author review before saving.

Below those twenty-five operations sits a structurally different entry:

Item Behavior
Generate / Update assessment panel ▸ Fill in the blank · Multiple choice (single) · Multiple choice (multiple)

Glossary submenu

Requires the Studio SDK; needs a non-empty selected term.

Item Behavior
Add term to glossary… Opens the define dialog (term + definition); redefines if the term exists
Link glossary terms Re-runs term-ification across all content panels

Keyboard shortcuts

These are the component’s own bindings. For the application menubar’s accelerators, see Studio Shell.

Keys Action
Ctrl/Cmd+Z Undo
Ctrl/Cmd+Shift+Z, Ctrl/Cmd+Y Redo
Ctrl/Cmd+F Open the find bar (focus the query if already open); suppresses the browser’s page search; no-op while a modal is open or in student mode
Enter / Shift+Enter (find query) Next / previous match
Enter (replace input) Replace the current match and advance
Escape (in the bar) Close the bar and refocus the editor at the current match
Ctrl/Cmd+Z / Shift+Z / Y (on the bar’s buttons) Forwarded document undo/redo — the bar’s text inputs keep their native input undo

Find and Replace

The find bar overlays the top-right of the source pane, inside the component (focus moves between the editor and the bar never leak out of the component host).

Find (row 1):

Replace (row 2):

Source markers

An always-on, metric-exact backdrop mirror behind the (transparent-text) textarea marks source the tidy pass has an opinion about. Two families of marker paint there, and they make different promises.

Whitespace markers

Marker Meaning
␠ (U+2420) A whitespace character the tidy pass would remove — trailing spaces/tabs/NBSP/Unicode spaces, whitespace-only lines, interior runs of 2+ spaces
⏎ (U+23CE) A line break the tidy pass would remove (blank-line runs beyond one, and the joins made by paragraph unwrapping)
␠␠⏎ in a distinct deeper shade A hard line break (2+ trailing spaces — a forced <br> in MyST). The tidy pass preserves these (normalizing to exactly two), so the distinct shade flags “author decision needed”

Never marked: ordinary interior spaces, soft wraps, paragraph-ending newlines, the single legitimate blank line between blocks, and anything inside protected spans (code, inline code, math, links, images, directives).

Embedded-HTML markers

Background-only spans with no glyph, since they cover multiple characters at once. The two shades make opposite promises:

Marker Meaning
mc-html (light coral) Embedded HTML the tidy pass will remove
mc-html-open (light warm yellow) An unterminated flow construct the tidy pass will not touch until the author closes or deletes it — protect-and-flag

The second shade is why there is no “after tidying, only hard breaks remain” corollary: an unterminated construct leaves its marker standing after a completed tidy pass, by design.

Mechanics

The markers are display-only — glyphs are absolutely-positioned CSS overlays, and the source, save, publish, copy and find all see the real characters. They recompute on the preview’s 160 ms debounce and share one oracle (wsEdits) with the tidy command and the host’s save-time pipeline, so they can never disagree with what saving will do. Above 10,000 decorations only backgrounds paint (no glyphs), to protect performance on pathological pastes.

What the tidy pass actually removes

The name “Remove redundant whitespace” understates the pass. One oracle backs the menu command, the marker layer and the host’s pre-save normalization pipeline, and it makes three kinds of edit:

  1. Whitespace — trailing whitespace, whitespace-only lines, interior runs of two or more spaces, blank-line runs beyond one; hard line breaks are preserved and normalized to exactly two trailing spaces.
  2. Paragraph unwrapping — a soft line break inside a paragraph is redundant, so hard-wrapped paragraphs are joined into single lines. Rendering is identical by construction (a soft break is equivalent to a space), but the saved bytes change.
  3. Embedded HTML stripping — tag tokens are removed with their human-readable inner text preserved; terminated comments, CDATA, processing instructions, declarations and closed <script>/<style> elements are removed whole; unterminated flow constructs are protected and flagged rather than stripped.

All three compose in one idempotent pass. The practical consequence for implementers: because the host runs this oracle before every save and publish, saving a hard-wrapped document or one containing inert HTML deliberately changes its bytes — and therefore its content hash — relative to what the author typed. That is intended behavior, not drift.

Glossary

The host-side SDK that drives this round trip is documented in Formats and Contracts.

Call outs and boxes

See the Call outs submenu for the five branded types and the Insert submenu for the generic boxes (Note, Warning, Exercise, Dropdown). Key invariants:

Insert and format operations

Merlin Terminal embeds

The editor can embed a live Merlin Terminal — a third published component — directly in the preview, via a :::{merlin-terminal} directive.

Authoring

Insert entry Emits
Empty :::{merlin-terminal} with no options
Challenge :::{merlin-terminal} + :challenge-shell: <challengeRef>

The Challenge picker lists the current lesson’s challenges through the host SDK, synchronously, at menu-build time; the entry is disabled when the host reports no challenges — or registers no SDK at all, which is how it presents in Student Lab and published-lesson hosts.

:challenge-shell: is a Studio-level authoring option, not a component option. The published component ignores unknown options, so the preview still shows a terminal placeholder; at publish the host rewrites it into the component’s real options. See Programs and Workbench for that rewrite.

Mounting

AI operations (ĀYŌDÈ Intelligence)

Twenty-five text operations across Content, Clarity, Pedagogy, Style, Generate and Custom, plus the three assessment-panel families (see the menu tables). Mechanics:

Host routing, endpoint selection and the review flows are documented in ĀYŌDÈ Intelligence Operations.

Preview and rendering

The pipeline is myst-parser (with strikethrough and math extensions), then three AST transforms, then myst-to-html, then post-processing:

  1. Glossary transform — {term} roles become glossary links.
  2. Highlight transform — {highlight-*} roles become classed spans.
  3. Terminal transform — {merlin-terminal} directives become renderable placeholders.

Live terminal mounts are detached immediately after the transforms, before the HTML swap.

Post-processing, in order:

Terminal placeholders are then replaced with live component mounts, and the component emits componentrendered.

Callout styling and glossary-link styling are not in this pipeline — both are static CSS keyed off classes the transforms and the class token already put in place.

The preview re-renders on a 160 ms debounce after each change.

Student mode

Activated by the host (setStudentMode() or the component view-mode dataset). The layout collapses to preview-only; the source pane, gutter, marker mirror, find bar, and context menu are hidden or inert; editing, undo, and redo are unavailable. Published-lesson viewers without the Studio SDK degrade gracefully to plain preview — the Merlin Terminal ▸ Challenge entry is among the things that simply present as disabled.