Toolbar active states only ever work for bold, italic and underline
Toolbar.checkState() asks isSelectionFormatted(range, action) whether each
button should carry medium-editor-button-active. That function builds exactly
one object:
const foundFormatting = {
bold: false,
italic: false,
underline: false,
}and decides from it. There is no branch for h2, h3, quote, pre,
orderedlist, unorderedlist or anchor, so every one of those buttons
returns false no matter where the caret is. A toolbar built from the default
button set — ['bold', 'italic', 'underline', 'anchor', 'h2', 'h3', 'quote'] —
can light up three of its seven buttons.
Reproducing
Mount an editor whose toolbar includes the block buttons, put a selection inside each kind of block, and read back which buttons are active:
[...toolbar.querySelectorAll('.medium-editor-button-active')].map(b => b.dataset.action)| selection is inside | active buttons |
|---|---|
<strong> | ['bold'] |
<em> | ['italic'] |
<h2> | [] |
<li> (in a <ul>) | [] |
<a> | [] |
Measured against 0.1.6, in a static toolbar (toolbar: { static: true }) and
in the default floating one, with and without updateOnEmptySelection.
The data is already there
Button carries the tag names for precisely this question, and they are
correct — h2: { tagNames: ['h2'] }, quote: { tagNames: ['blockquote'] },
unorderedlist: { tagNames: ['ul'] }, anchor: { tagNames: ['a'] }, and so
on. Toolbar.createButton() builds its buttons directly from a switch and
never constructs a Button, so that metadata is not consulted on the toolbar
path. Walking the selection's ancestors to the editable and testing
tagNames.includes(el.tagName.toLowerCase()) would answer all of them with the
table that already exists, and would subsume the three hard-coded cases rather
than sitting beside them.
Why it is worth fixing rather than documenting
The active state is the only feedback a Medium-style toolbar gives. There is no
other indication of what the caret is sitting in, so with it absent a writer
cannot tell an <h2> from a styled paragraph, or whether they are inside the
list they think they are. It also makes the buttons read as broken in a way
that is hard to pin down: quote applies correctly, it just never looks
applied, so the natural conclusion is that the click did not register and the
user clicks again — which toggles it back off.
It bites hardest on exactly the buttons that have no visual shorthand. Bold and italic are legible in the text itself; "am I in a blockquote" is not.
Smaller thing, same file path
AnchorForm ships console.log on its hot paths — handleTextboxKeyup logs
every keystroke as Textbox keyup: <key>, plus "Creating form...", "Saving
selection...", "Save button clicked", "Enter pressed - saving form". Using the
link button writes a line per character typed into a consumer's console. Happy
to split that into its own issue if you would rather keep them separate.