feat(pilcrow): WIP#2671
Draft
christianhg wants to merge 11 commits into
Draft
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
2 Skipped Deployments
|
|
Contributor
📦 Bundle Stats —
|
| Metric | Value | vs main (43d9acb) |
|---|---|---|
| Internal (raw) | 761.3 KB | - |
| Internal (gzip) | 146.7 KB | - |
| Bundled (raw) | 1.36 MB | - |
| Bundled (gzip) | 307.5 KB | - |
| Import time | 73ms | -2ms, -3.2% |
@portabletext/editor/behaviors
| Metric | Value | vs main (43d9acb) |
|---|---|---|
| Internal (raw) | 467 B | - |
| Internal (gzip) | 207 B | - |
| Bundled (raw) | 424 B | - |
| Bundled (gzip) | 171 B | - |
| Import time | 1ms | -0ms, -1.4% |
@portabletext/editor/plugins
| Metric | Value | vs main (43d9acb) |
|---|---|---|
| Internal (raw) | 3.8 KB | - |
| Internal (gzip) | 1006 B | - |
| Bundled (raw) | 3.6 KB | - |
| Bundled (gzip) | 936 B | - |
| Import time | 5ms | -0ms, -2.0% |
@portabletext/editor/selectors
| Metric | Value | vs main (43d9acb) |
|---|---|---|
| Internal (raw) | 79.9 KB | - |
| Internal (gzip) | 14.6 KB | - |
| Bundled (raw) | 75.9 KB | - |
| Bundled (gzip) | 13.6 KB | - |
| Import time | 6ms | -0ms, -1.0% |
@portabletext/editor/traversal
| Metric | Value | vs main (43d9acb) |
|---|---|---|
| Internal (raw) | 20.0 KB | - |
| Internal (gzip) | 4.0 KB | - |
| Bundled (raw) | 20.4 KB | - |
| Bundled (gzip) | 4.0 KB | - |
| Import time | 4ms | -0ms, -1.5% |
@portabletext/editor/utils
| Metric | Value | vs main (43d9acb) |
|---|---|---|
| Internal (raw) | 30.0 KB | - |
| Internal (gzip) | 6.1 KB | - |
| Bundled (raw) | 27.9 KB | - |
| Bundled (gzip) | 5.7 KB | - |
| Import time | 4ms | -0ms, -2.5% |
🗺️ . · ./behaviors · ./plugins · ./selectors · ./traversal · ./utils · Artifacts
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
Clean-slate pilcrow build per /specs/pilcrow.md §11.1. Schema covers all §6.1 block types with the seven schema fixes applied (top-level lists dropped, image.title not caption, link.title field, GFM-rich callout/blockquote content, code-block spellCheck:false). Plugins are pure-render (defineContainer / defineLeaf / defineTextBlock only, no InputRule, no behaviors, no context plumbing). Inline marks via legacy renderDecorator / renderAnnotation per PR #2651's pattern. Visual target: visual-prototypes/v1/index-resting.html. Single 800px ivory page on a paper-on-page surround, Crimson Pro everywhere, no two-pane shell. Starter document hand-converted to PT JSON; image.title is set manually so M0 does not wait on the @portabletext/markdown round-trip work. Out of M0 (deferred): slash menu, bubble menu, input rules, block handles, smart typography, syntax highlighting, Mermaid, find/replace, undo, save/load, round-trip, smart paste.
Adds a theme toggle to the header. Resolution: stored preference
(localStorage) wins; otherwise prefers-color-scheme follows the system.
The hook writes :root[data-theme] so theme.css can branch with
:root[data-theme='dark'] { ... }.
Tokens invert: paper, page-bg, ink palette, rule lines, tint backgrounds,
accent, selection. Type, spacing, borders, fonts all unchanged.
Header icons swap from emoji placeholders to outlined Phosphor SVGs
(sun / moon / dots-three-vertical), inlined to avoid a runtime dep.
Round 1 of visual polish after running pilcrow against pip's mockup
and Christian's walkthrough.
- task list rendering uses flex layout so the checkbox sits to the
left of the text rather than stacking above it; the bullet-disc
+ ordered-decimal selectors now match the actual list kinds
('bullet' / 'number' / 'task') instead of dead 'ul' / 'ol'.
- image, horizontal-rule, callout, and table cells/tables now thread
their selected/focused render-callback args onto the DOM as
data-selected / data-focused. theme.css adds a subtle ring on
those states using the existing --selection token.
- horizontal-rule gets a wrapper with transparent vertical padding
so its hit area is comfortable instead of one pixel tall.
- image figcaption removed; the title surfaces as <img title> per
the markdown spec for hover.
- callout glyphs swap from typographic characters (i, *, !, ...) to
outlined Phosphor SVGs (info, lightbulb, warning, warning-octagon,
warning-circle).
- table renderer emits semantic <table> / <tr> / <td> so screen
readers can navigate the structure as a table.
c3c3a23 to
7fd4d8c
Compare
Adds a non-keystroke-intercepting behavior plugin that runs pasted
plain-text payloads through markdownToPortableText so any markdown
on the clipboard (paragraphs, headings, lists, code fences, tables,
GFM callouts, horizontal rules) lands as structured blocks instead
of a single span.
The matchers tailor the parser output to pilcrow's schema:
- code: the parser emits a flat `{language, code: string}`. Pilcrow
stores code as `code-block.lines: textBlock[]` so caret nav
works line-by-line. The matcher splits the source on newlines
and synthesizes one block per line.
- table: the parser emits `cells[i].value`. Pilcrow's cell schema
uses `content`. The matcher renames the field.
- horizontalRule: pilcrow uses the dashed `horizontal-rule` type
name to mirror the markdown spec wording rather than the parser
default.
- callout: GFM alerts reuse blockquote syntax internally, so the
parser stamps `style: 'blockquote'` on every text block inside
an alert. Pilcrow's callout has its own visual frame, so the
inner blockquote frame would stack on top of it. The matcher
strips the style back to normal.
Listens for the platform save shortcut and downloads the current
document as a markdown file. The browser's native save dialog is
suppressed in favour of an in-page download triggered with a
temporary anchor element.
The serializer renderers live alongside the parser matchers in
markdown.ts so the round-trip configuration sits in one place. They
translate pilcrow's editor shape to standard markdown:
- code-block: walks lines[].children[] spans, concatenates with
newlines, wraps in a fenced block. The language attribute is
emitted on the opening fence when present.
- table: renders each cell's content inline (single line) and
joins with pipes, since markdown tables don't support multi-line
cells. A header separator is added when headerRows is set.
- image: emits standard  with optional title.
- horizontal-rule and callout: reuse the built-in renderers.
Listens for file drops and runs each text/markdown payload through the markdown deserializer so dragging a .md file onto pilcrow replaces the document with its contents. The plugin mirrors the playground's text-file-deserializer pattern: register a 'deserialize' behavior, filter the file list to text/* MIME types and the .md extension (some operating systems omit the MIME on local markdown files), read each file as text with the FileReader API, and re-dispatch the drop as a 'text/plain' deserialize event. The markdown deserializer registered earlier in the chain picks the payload up from there.
21aaa19 to
3811aa4
Compare
Selection-anchored toolbar above the current text selection. Shows only when the selection is non-collapsed, hides on collapse or when focus leaves a text block. Four decorator toggles wire into @portabletext/toolbar's useDecoratorButton: Bold, Italic, Inline code, Strike-through. The active state on each button mirrors the engine's mark state at the caret. Positioning is via position: fixed anchored to the selection's bounding rect, with an 8px tip pointing down at the selection. The menu flips below the selection when the selection sits within 36+8+8 pixels of the viewport top so the menu remains visible. The CSS mirrors the bubble variant in the visual-prototype catalogue: dark inverted palette (ink on paper background flipped to paper on ink), 4px radius, 28x26 button cells, faint white hover and active backgrounds. Phosphor outline icons match the header's outlined weight. Link annotation, the Turn-into pill, and the block-object variant are deferred to follow-up commits.
Typing a colon followed by a keyword opens a caret-anchored floating list of matching emoji. Arrow keys move through the matches, Enter or click inserts the selected emoji and closes the panel, Escape dismisses. Matching is fuzzy via fuse.js over emojilib's keyword dictionary. Exact keyword matches sort to the top via the type: 'exact' branch in EmojiMatch. The hook is provided by @portabletext/plugin-emoji-picker, which owns the keyword extraction state machine, keyboard event wiring, and insertion behaviour. The pilcrow plugin supplies the matcher function and renders the panel anchored to the editor caret rect returned by editor.dom.getSelectionRect. Activation is bounded to a typed-keyword behaviour: nothing is intercepted during normal typing, only when a colon-prefixed keyword is in flight.
Typing '/' opens a caret-anchored list of insertable blocks: the three heading levels (toggled in place via style.toggle so the current text is preserved), the three list kinds (bullet, number, task), blockquote, callout, code block, table, image, and a horizontal rule. Containers are inserted with a starter scaffold that satisfies the schema: a list starts with one empty list-item, a blockquote with one empty paragraph, a callout with tone 'note' and one paragraph, a table with one header row and one body row of two empty cells. The trigger pattern (the slash plus typed keyword) is deleted from the document after selection so the visible text reflects only the inserted content. Plumbed through @portabletext/plugin-typeahead-picker. Matching is fuzzy via fuse.js against each command's label and keyword list.
c644b15 to
dab720c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pilcrow, a Markdown-compliance editor built on PTE v7. WIP.