Repository navigation
Releases: zahidshowrav/blockleaf
Release list
@blockleaf/editor@0.0.6
Patch Changes
-
dfbc49d: Stop the chrome throwing when an extension it offers is not loaded.
isAvailableaskededitor.can().toggleHighlight(), buteditor.can()only
carries the commands the configured extensions registered. With
preset="minimal"— no highlight, no tables — selecting text threw
editor.can(...).toggleHighlight is not a functionwhile the toolbar was
rendering, and the cell menu threw the same way onmergeCells, so the whole
editor failed to mount. The same held for any host passing its own
extensionsarray without one of those types.Every default action now checks its mark or node is in the schema before
asking whether the command applies, through a sharedwhenMarkExists/
whenNodeExistsguard. A type the editor does not have reads as unavailable
and the button is hidden, which is whatisAvailablewas for. -
f254f17: Fix task list items rendering stacked instead of inline, and list markers
disappearing under a CSS reset.The task item rules were keyed to
li[data-type='taskItem'], an attribute
that only exists in serialised output. Tiptap builds the live item in
addNodeViewfrom the node's own attributes —data-checked,data-id— and
never applies thedata-typethatrenderHTMLmerges in. So the selector
styled every rendered page and no actual editor, and the checkbox sat above
its label rather than beside it for as long as task lists have existed. The
rules now match through the parent list,ul[data-type='taskList'] > li,
which is present in both.list-styleis now stated rather than inherited from the user agent. Every
common reset strips list markers, so bullets and numbers vanished in any app
using Tailwind's preflight or normalize — and "works without a CSS framework"
should not mean "breaks with one".Both were found by putting a task list and a bullet list in the documentation
site's live demo.
@blockleaf/renderer@0.0.1
Patch Changes
-
5da026d: Add
@blockleaf/renderer(RD-01) — a new package that turns a stored document
into React elements on a server, without the editor and without ProseMirror.import { RenderDocument } from '@blockleaf/renderer/react'; <RenderDocument doc={article.body} />;
It has no runtime dependencies and React is an optional peer, so the
sanitisers at the root entry work in a plain Node script.RenderDocument
measures 1.35 kB.BlockleafDocumentsatisfies thedocprop structurally — there is no import
from@blockleaf/editorand nothing to convert.Every element matches what the editor writes for the same node, so one
stylesheet fits both; a parity suite renders the same document through both
packages and fails if they diverge. Three differences are deliberate: the task
checkbox isdisabled, since nothing here can write a change back; an unknown
node renders its children rather than throwing, because a document written by
a newer editor must not take down the page; andsrcandhrefare
sanitised again at render time, because stored JSON predates any guarantee the
editor made about it. -
6d2770d: Add per-node and per-mark component overrides (RD-02).
<RenderDocument doc={article.body} components={{ image: MyImage, codeBlock: MyCode }} />
An override is a patch over the defaults, not a replacement mapping — naming
imagedoes not mean re-implementing paragraphs. A name the defaults do not
know works too, which is how a host renders a node type of its own.The attribute helpers the default components use are exported alongside, so an
override routing images throughnext/imagecan callimageAttributes(node)
and get a sanitisedsrcrather than re-deriving the rule.Overrides are merged per render rather than memoised, because the component
has to work in a server component, where hooks do not exist. Hoisting the
override map to module scope avoids the merge. -
a9c4af8: Add the HTML-string and plain-text exports (RD-03).
import { renderToHTML } from '@blockleaf/renderer/html'; import { extractHeadings, toPlainText } from '@blockleaf/renderer'; const body = renderToHTML(doc); // emails, RSS, OG images const excerpt = toPlainText(doc).slice(0, 200); const toc = extractHeadings(doc);
renderToHTMLmeasures 1.5 kB and needs no React at all — the./htmlentry
imports nothing. It takes the samecomponentsandmarksoverrides the
React target does, and writes the same markup: the parity suite now holds
three implementations to each other, the two targets and the editor itself.Escaping is this target's own job rather than React's, so text and attribute
values are escaped separately, and a document whose storedaltis
" onerror="alert(1)renders as an attribute rather than as a handler.toPlainTexttakes ablockSeparatorand leaves image alt text out unless
asked, since alt text reads as an interruption in an excerpt and as useful
signal in a search index.extractHeadingsreturns level, text and block id
in document order. -
b358752: Render tables as real table markup, in both targets (RD-07).
prosemirror-tables has no concept of a table section, so the editor writes
every row into<tbody>, header cells included. That is tolerable in a
surface the user is looking at and not tolerable in output:<thead>is most
of what an email client, an RSS reader or a screen reader has to go on.So a leading row made entirely of header cells becomes
<thead>, and the rest
<tbody>. A row with a mix of headers and cells is a header column, which
prosemirror-tables also allows, and is left in<tbody>rather than claiming
to label everything below it. Header cells carryscope:colin a header
row,rowfor a header cell leading a body row.Stored column widths move into
<colgroup>, where the editor also puts them.
Thecolwidthattribute the editor additionally writes on each cell is
dropped — it is not an HTML attribute, and the width is already in the
<col>.This is the only node the renderer deliberately writes differently from the
editor. Everything else is held to it by the parity suite.
@blockleaf/editor@0.0.5
Patch Changes
-
b6f7882: Add the upload adapter interface (MC-01). Hosts implement
UploadAdapterand
the editor drives it; no storage provider is baked in. The second argument is a
context object rather than a bareAbortSignalso adapters can report
determinate progress, andisUploadResultvalidates what an adapter resolves
with before it can reach the document. -
05657cb: Add drop, paste and picker entry points for uploads (MC-02). Dropping files on
the editor, pasting them from the clipboard, or callingopenUploadPicker
screens each file for type and size before it leaves the browser, then
hands it to the adapter and inserts an image where it landed.The in-flight placeholder is a widget decoration rather than a node, so
ProseMirror maps its position through every edit made while the upload runs —
an image dropped at the end of a paragraph still lands there after typing
above it — and nothing has to be stripped out of the document before saving.upload,uploadAccept,uploadMaxBytesandonUploadErrorare new options
onuseBlockleafEditorand<BlockleafEditor>. Without an adapter the
extension is not added at all, so files fall through to the browser rather
than being swallowed. -
5fa4e4c: Add upload progress, cancel and retry (MC-03). The in-flight placeholder now
shows a progress bar driven by the adapter'sonProgress, with a Cancel
button that aborts the request through the signal.Progress is indeterminate until an adapter reports a fraction —
fetchcannot
measure upload progress, so a bar claiming a percentage it does not have would
be a lie. An indeterminateprogressbaromitsaria-valuenowrather than
reporting zero.A failed upload no longer disappears. Its placeholder stays, holding the
position it has been mapping all along, and offers Retry and Dismiss — so a
retry puts the image where the user dropped it, even after editing above it.
A cancelled upload is not reported as a failure. -
a114e5d: Add the image block with alt text and alignment (MC-04). The node is
hand-rolled rather than taken from@tiptap/extension-image, andsrcis
sanitised in the schema:https:, relative paths and raster data URLs are
allowed, whilejavascript:,blob:,http:and SVG data URLs are rejected.
An unsafe<img>arriving through a paste is dropped rather than stored with
a null source.Selecting an image opens a toolbar for alignment, alt text and delete. An
empty alt is kept rather than discarded, since that is how an image is marked
decorative.The bubble menu's link editor is now one of a general panel slot, so the
toolbar's keyboard handling lives in one place. Three CSS classes were
renamed to match:blockleaf-bubble-menu__link-editor,__link-inputand
__link-errorare now__panel,__panel-inputand__panel-error.
Closing a panel now returns focus to the button that opened it, which the
link editor had never managed. -
c004dfe: Add the syntax-highlighted code block with a language picker (MC-05), as the
new opt-in subpath@blockleaf/editor/code-block.import { createExtensions } from '@blockleaf/editor/extensions'; import { withCodeBlock } from '@blockleaf/editor/code-block'; const extensions = withCodeBlock(createExtensions('standard'));
It is a subpath rather than part of the default build because
lowlightand
its grammars cost 16.53 kB and the default bundle had 15.37 kB left — shipping
it by default put the editor at 161.16 kB, over the ceiling. Importing nothing
costs nothing, and the main entry is unchanged at 144.63 kB. See F14.Seven grammars ship by default — bash, css, javascript, json, python,
typescript and xml — and hosts register more throughadditionalLanguages.
StarterKit's plain code block is untouched for anyone who does not import
the subpath, and the stored shape is identical either way.A code block whose language this host has not registered now renders
unhighlighted instead of throwing during editor construction, and keeps its
languageattribute rather than having it stripped on the next save.
@blockleaf/editor@0.0.3
Patch Changes
- Implement editing core milestone (EC-01 through EC-20):
- Headless node and mark set with discriminated unions
- Stable UUID block IDs
- Markdown input rules and keyboard shortcuts
- Paste normalisation for HTML, Word, and Google Docs
- Table node set, insert/structure commands, cell merge/split, and Tab navigation
- Opt-in Zod schema validation via
@blockleaf/editor/validate - Playwright browser smoke test harness
@blockleaf/editor@0.0.4
Patch Changes
- d4ee34a: Implement slash command menu backed by command registry with full keyboard and accessibility support (CH-01)
- e44eabb: Add the selection bubble menu with a link editor (CH-02). Six mark toggles with ARIA toolbar keyboard navigation, and an href field that mirrors the schema's sanitisation so a rejected link says why.
- 7f1cbc8: Add the drag handle and block menu (CH-03). Hand-rolled rather than using
@tiptap/extension-drag-handle, which imports yjs at module scope and costs 32.87 kB; this costs 1.83 kB and no new dependency. - 5f8e57e: Add the placeholder and configure the trailing node (CH-04). The placeholder is a hand-rolled decoration plugin — @tiptap/extensions
declares nosideEffects, which pushed the schema-only entry from 136 B to 60.77 kB. StarterKit'strailingNode` no longer appends an empty paragraph after a heading, and a saved document that needs a trailing paragraph gets one on load without reporting it as a user edit. - 5efe7d3: Make the chrome keyboard-complete and axe-clean (CH-05). Adds a
labelprop giving the editing surface an accessible name,Shift+F10andMod+Alt+Mfor the block menu,Mod+Alt+R/Mod+Alt+Cfor the table menus, and fixes a colour-contrast failure on selected menu rows. The link editor now wins focus reliably, including whenMod+Kis pressed before the toolbar has appeared. - 67a6702: Add the table grid-size picker to the slash menu (CH-06). Choosing Table now opens an 8 × 8 grid driven by pointer or arrow key, calling the
insertTablecommand from EC-13. Slash commands can carry apickerfor any command that needs an argument. - b40815c: Add in-table row and column handles (CH-07). Each opens a menu of structure operations calling the EC-14 and EC-15 commands, and asks those commands whether they can run rather than re-deriving availability.
- d1f6727: Add the in-table cell bubble menu (CH-08). A second bubble menu instance with its own plugin key and
shouldShow, offering merge, split and structure operations for a selection spanning cells. The text bubble menu stands down for a cell selection so the two never compete. - 23952c5: Fix
pnpm devleaving the sandbox unable to resolve@blockleaf/editor. The stylesheet is now copied by the bundler rather than thebuildscript, so watch mode emits it too, andcleanno longer wipesdist/when the watcher starts. The published./styles.csssubpath is unchanged.