spangle
v1.3.0
Published
decorate strings using formatted ranges
Downloads
827
Readme
Spangle
Add some ✨ razzle-dazzle ✨ to strings using formatted ranges.
What do you mean "formatted ranges"?
Specifying text as a combination of a string and formatted ranges is a way to allow clients to display formatted text in whichever way they see fit. This amounts to progressive enhancement or graceful degradation, depending on your point of view.
Backwards-compatibility is built in. If a certain type of formatting is unsupported or has some issue, it can be ignored without affecting the rest of the formatting. In the worst case, you can always display a plain string of text!
Shape of the Data
Formatted text is represented by one or more blocks, each of which has plain text string plus any number of formatting ranges that specify additional inline formatting. It is designed so that the interpreter can skip any formatting data that is unrecognized or unsupported without breaking the overall output.
{
blocks: [
// Plaintext
{
type: 'text',
text: 'Hello world!',
},
// Text with inline formattin
{
type: 'text',
text: 'This is your text.',
formatting: [
{ start: 8, end: 12, type: 'emphasis' },
],
},
],
}
If you were to render this to HTML, you might have output that looks something like this:
<p>Hello world!</p>
<p>This is <em>your</em> text.</p>
Suppose you wanted to render to Markdown instead. An implementation of that might have output that looks more like this:
Hello world!
This is _your_ text.
Usage
This repository contains a JavaScript implementation for the web, but you could also write interpreters for other languages and/or platforms as well!
The primary implementation is build on unified and rehype-dom. It can both parse and format HTML using an abstract syntax tree and the browser's DOM implementation. This is likely the version you'll need to use if you're building a WYSIWYG editor or something similar.
Parsing HTML
import { parseHtml } from 'spangle';
const output = parseHtml('<p>This is <em>your</em> text.</p>');
console.log(output);
// {
// blocks: [{
// type: "text",
// text: "This is your text.",
// formatting: [{ start: 8, end: 12, type: "emphasis" }]
// }],
// }
Formatting HTML
import { formatHtml } from 'spangle';
const output = formatHtml({
blocks: [{
type: 'text',
text: 'This is your text.',
formatting: [
{ start: 8, end: 12, type: 'emphasis' },
],
}],
});
console.log(output);
// "<p>This is <em>your</em> text.</p>"
Lite Verison
If you're concerned about bundle size or only need to interpret existing spangle-formatted data, you might consider using the "Lite" implementation instead. It does not support parsing!
It's smaller because it excludes the code for parsing HTML and uses a smaller (and less accurate) AST-to-HTML string implementation. Otherwise, the API is the same, so swap the import and you'll be good to go!
import { formatHtml } from 'spangle/lib/lite';
Markdown
This repository also includes an implementation that can parse and format a non-standard version of Markdown. This is probably an easier way to create spangle-formatted data reliably than parsing HTML or writing JSON manually.
Parsing Markdown
import { parseMarkdown } from 'spangle';
const output = parseMarkdown('This is [your]{#f00} text.');
console.log(output);
// {
// blocks: [{
// type: "text",
// text: "This is your text.",
// formatting: [{ start: 8, end: 12, type: "color", color: "#f00" }]
// }],
// }
Formatting Markdown
import { formatMarkdown } from 'spangle';
const output = formatMarkdown({
blocks: [{
type: 'text',
text: 'This is your text.',
formatting: [
{ start: 8, end: 12, type: 'underline' },
],
}],
});
console.log(output);
// "This is __your__ text."
Formatting Types
Check out the constants to see the types of formatting supported.
Note: Formatting ranges include start
and end
normally, but we're omitting them for the sake
of brevity in this documentation.
* Formatting that uses non-standard Markdown is labeled with an asterisk.
Strikethrough / Delete
{ type: 'delete' }
<del>text</del>
~~text~~
Italics / Emphasis
{ type: 'emphasis' }
<em>text</em>
_text_
Inline code
{ type: 'inlineCode' }
<code>text</code>
`text`
Underlined*
{ type: 'underline' }
<span style="text-decoration: underline;">text</code>
__text__
Note: Standard markdown uses double-underscores for strong text.
Colors*
{ type: 'color', color: '#f00' }
<span style="color: #f00;">text</code>
[text]{#f00}
Note: Standard markdown does not support inline colors.
Anchor link
{ type: 'link', url: 'https://example.com' }
<a href="https://example.com">text</a>
[text](https://example.com)
Bold / Strong
{ type: 'strong' }
<strong>text</strong>
**text**