Editor, který nesahá na to,
co sám nenapsal.

Nibble je lehký WYSIWYG editor HTML ve vanilla TypeScriptu — náhrada za TinyMCE bez licenčních stropů. Načtený dokument se uloží znak po znaku stejně, dokud se ho někdo nedotkne. Ne „skoro stejně“, ne „sémanticky ekvivalentně“. Stejně.

vanilla TS · ESM 0 závislostí ~44 kB gzip 744 testů MIT
import { Nibble } from '@nibble/core'
import { attachToolbar } from '@nibble/ui'
import { link, image, table } from '@nibble/plugins'
import '@nibble/ui/nibble.css'

const editor = await Nibble.create({
  target: '#obsah',        // selektor, prvek nebo textarea
  schema: 'legacy',        // starý obsah se nepřepisuje
  plugins: [link, image, table],
})

attachToolbar(editor, { menubar: true })

editor.on('change', ({ html }) => uloz(html))

Pluginy se předávají jako hodnoty, ne jako řetězec se jmény — bundler pak vidí, co se opravdu používá, a zbytek vyhodí. Bez balíčkovače jde celá knihovna načíst jedním importem z adresy.

Záruka, na které to celé stojí

Načtu, nesáhnu, uložím → musí být znak po znaku totéž.

Proč to není samozřejmost

Běžný editor obsah při načtení naparsuje a při uložení zase vypíše. Cestou přerovná atributy, doplní uvozovky, nahradí entity, zahodí komentář. U nového textu si toho nikdo nevšimne. U dvaceti tisíc dokumentů, do kterých deset let zasahovaly tři různé nástroje, je z toho tichá ztráta dat.

Jak to Nibble dělá

Parser si u každé oblasti nejvyšší úrovně pamatuje její původní zdroj. Serializace ho vypíše doslova — dokud se DOM té oblasti liší od snímku, který si Nibble pořídil při načtení. Jakmile do bloku uživatel zasáhne, přepne se na normální serializaci, ale jen ten blok.

Jediná výjimka: konce řádků

CRLF se převádí na LF. Prohlížeč to udělá sám v textarea.value i při parsování HTML, takže „zachovat CRLF“ by byl slib, který se nedá splnit. Je to vědomé a je to jediné, co Nibble změní vždy.

Co umí

Parita s free TinyMCE plus kus toho, co je jinde za peníze.

📝

Editace bez execCommand

Všechno jde přes beforeinput a vlastní příkazy. Bloky, seznamy se zanořováním, zarovnání, citace, výška řádku, historie s rozumnou granularitou — a jediná cesta, jak změnit obsah.

📋

Vkládání, které nepřinese svinstvo

Word, Google Docs, LibreOffice i prostý text. Rozpoznává zdroj, čistí podle něj, umí i vložení bez formátování a Markdown.

🔲

Tabulky se šířkami sloupců

Mřížkový model se sloučenými buňkami, navigace Tabem, vlastnosti tabulky i řádku a tažení šířky sloupce do <col width> — protože přesně to je v reálných datech nejčastější.

</>

Zdrojový kód, ve kterém se dá pracovat

Velké okno, zvýrazněná syntaxe, zalamování — a hlavně: kurzor skočí tam, kde jste byli v textu. Po zavření se vrátí zpátky.

⚙️

Nastavení pro uživatele

Rozvržení lišty navrhne programátor, ale poslední slovo má ten, kdo u toho sedí: zapnutí tlačítek, pořadí tažením myší, dva řádky lišty, rozměry, informační řádek. A tlačítko, které z toho vypíše hotovou konfiguraci.

🛡

Bezpečnost odděleně od tvaru

Sanitizace běží vždy — na skripty, on* atributy i javascript: odkazy. Srovnávání tvaru běží líně, jen na tom, do čeho uživatel opravdu zasáhl.

Postaveno na reálných datech, ne na dojmech

Každé rozhodnutí se měřilo proti 142 skutečným dokumentům z ostrého provozu. Několikrát to plán obrátilo naruby.

Word se nevkládá

V datech nebyl ani jeden pozůstatek po Wordu. Zato Google Docs a prostý text všude. Čištění se podle toho přerovnalo.

Videa chyběla

media byl třetí nejpoužívanější plugin v existující konfiguraci — a v původním plánu nebyl vůbec.

Sloupce, ne slučování

V 55 tabulkách je colspan dvakrát, ale <col width> devětačtyřicetkrát. Priority se otočily.

Kam dál