Markdown formatting buttons for text inputs.
This is a FlaskBB maintained fork of github/markdown-toolbar-element, forked at upstream v2.2.3. See Relationship to upstream.
$ npm install --save @flaskbb/markdown-toolbar-element
import '@flaskbb/markdown-toolbar-element'<markdown-toolbar for="textarea_id">
<md-bold>bold</md-bold>
<md-header>header</md-header>
<md-italic>italic</md-italic>
<md-quote>quote</md-quote>
<md-code>code</md-code>
<md-link>link</md-link>
<md-image>image</md-image>
<md-unordered-list>unordered-list</md-unordered-list>
<md-ordered-list>ordered-list</md-ordered-list>
<md-task-list>task-list</md-task-list>
<md-mention>mention</md-mention>
<md-ref>ref</md-ref>
<button data-md-button>Custom button</button>
</markdown-toolbar>
<textarea id="textarea_id"></textarea><markdown-toolbar> comes with focus management as advised in WAI-ARIA Authoring Practices 1.1: Toolbar Design Pattern. The md-* buttons that ship with this package are automatically managed. Add a data-md-button attribute to any custom toolbar items to enroll them into focus management.
There are two ways to add a button for markup this package does not ship with.
<md-custom> covers the common case of wrapping the selection in fixed text,
without writing any JavaScript:
<markdown-toolbar for="textarea_id">
<md-custom data-md-prefix="||" data-md-placeholder="spoiler">spoiler</md-custom>
<md-custom data-md-prefix="[[" data-md-suffix="]]">wiki link</md-custom>
<md-custom data-md-insert="[TOC]">table of contents</md-custom>
</markdown-toolbar>| Attribute | Effect |
|---|---|
data-md-prefix |
Text inserted before the selection. |
data-md-suffix |
Text inserted after the selection. Defaults to data-md-prefix; set it to "" for no suffix. |
data-md-insert |
Insert this text as its own block instead of wrapping the selection. Overrides prefix/suffix. |
data-md-placeholder |
Inserted between prefix and suffix, and selected, when the button is clicked with no selection. |
Clicking a wrapping button a second time on text it already wrapped removes the
markup again, the same way <md-bold> does. All four attributes are observed,
so changing them at runtime takes effect on the next click.
Multi-line aware buttons, buttons that open a dialog, or anything else the
attributes above cannot express, subclass MarkdownButtonElement:
import {MarkdownButtonElement} from '@flaskbb/markdown-toolbar-element'
class MyPluginCalloutElement extends MarkdownButtonElement {
connectedCallback() {
super.connectedCallback()
this.markdownStyle = {prefix: '> ', multiline: true, surroundWithNewlines: true}
}
}
customElements.define('myplugin-callout', MyPluginCalloutElement)The class is also available as window.MarkdownButtonElement for scripts that
are loaded with a plain <script> tag rather than bundled.
The contract for a subclass:
- Assign
this.markdownStylebefore the element can be clicked. Doing it inconnectedCallback()is the right place; attributes are already readable there. A button with no style assigned does nothing when clicked. - Call
super.connectedCallback(). It setsrole="button"and marks the element as part of the toolbar's keyboard navigation set. If you cannot call it, putdata-md-toolbar-buttonon the element in markup instead. - Pick a tag name prefixed with your plugin or application name.
customElements.definethrows if a name is registered twice, somd-*and bare names likespoiler-buttonare collision risks.
markdownStyle accepts the Style type, which is exported for TypeScript
consumers:
| Field | Type | Effect |
|---|---|---|
prefix |
string |
Text inserted before the selection. |
suffix |
string |
Text inserted after the selection. |
blockPrefix |
string |
Replaces prefix when the selection spans multiple lines. |
blockSuffix |
string |
Replaces suffix when the selection spans multiple lines. |
multiline |
boolean |
Apply prefix/suffix to each selected line instead of the block. |
surroundWithNewlines |
boolean |
Pad the result with blank lines so it forms its own block. |
trimFirst |
boolean |
Move leading/trailing whitespace out of the wrapped text. |
prefixSpace |
boolean |
Insert a space before prefix when the preceding character is not blank. |
replaceNext |
string |
Substring of suffix that gets selected after inserting, e.g. url. |
scanFor |
string |
Regex; if the selection matches, it is put into replaceNext's place. |
orderedList |
boolean |
Renumber the selected lines as an ordered list. |
unorderedList |
boolean |
Prefix the selected lines as an unordered list. |
placeholder |
string |
Inserted and selected when the button is used with an empty selection. |
insert |
string |
Insert this text as its own block, ignoring every field above. |
A custom element whose definition never loaded (a plugin script that failed to fetch, for example) is skipped by the toolbar's keyboard navigation instead of becoming a dead stop between the other buttons.
This is a hard fork, and adapted to the own needs of FlaskBB.
Changes against upstream v2.2.3:
MarkdownButtonElement,MarkdownToolbarElement,MarkdownCustomButtonElementand theStyletype are exported, andMarkdownButtonElementis exposed onwindow.MarkdownButtonElementgained amarkdownStyleaccessor, so subclasses outside this package can configure themselves. Upstream keeps the styles in a module-privateWeakMapwith no way in.- Added the
<md-custom>element. - Added the
placeholderandinsertstyle fields. MarkdownButtonElement.connectedCallback()marks the element withdata-md-toolbar-button, which enrolls it into focus management. The built-inmd-*elements now callsuper.connectedCallback(), so they also getrole="button"- upstream never set it on them, a pre-existing accessibility gap fixed here.- Keyboard navigation skips undefined custom elements.
- Package renamed, TypeScript and CI updated.
Browsers without native custom element support require a polyfill.
- Chrome
- Firefox
- Safari
- Microsoft Edge
npm install
npm test
Distributed under the MIT license. See LICENSE for details. Originally written by GitHub, Inc.; the fork is maintained by the FlaskBB team.