Skip to content

Version Packages - #3233

Open
ecoscript[bot] wants to merge 1 commit into
mainfrom
changeset-release/main
Open

Version Packages#3233
ecoscript[bot] wants to merge 1 commit into
mainfrom
changeset-release/main

Conversation

@ecoscript

@ecoscript ecoscript Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

@portabletext/markdown@2.1.0

Minor Changes

  • #3240 bf560b9 Thanks @christianhg! - feat: round-trip unknown objects through json:object fences and code spans

    Custom objects now survive Markdown conversion in both directions. portableTextToMarkdown renders a block-level object as a ```json:object fence and an inline object as a json:object-tagged code span, and markdownToPortableText turns both back into the original objects, _key included, no schema required. Previously these objects came back as code blocks, and inline objects also split the block around them, so converting to Markdown and back destroyed them.

    ```json:object
    {"_type": "product", "_key": "k1", "sku": "abc-123"}
    ```
    
    AAPL is at json:object`{"_type": "stockTicker", "_key": "k2", "symbol": "AAPL"}` right now.

    Both forms parse back to the objects in the payloads, with the surrounding text intact.

    What changes in existing output and parsing:

    • Markdown output changes for unknown objects: ```json fences become ```json:object, and inline objects stay inside their line instead of breaking out.
    • The json:object language is reserved. A code block with exactly that language keeps its code but loses the language when serialized.
    • A ```json:object fence or tagged code span that doesn't contain a JSON object with a _type parses as ordinary code.
  • #3239 58d1541 Thanks @christianhg! - feat: report degraded constructs during markdown parsing

    markdownToPortableText now takes an onDegradation option for constructs the schema can't represent (an undeclared decorator, a table with no table block object, a task checkbox with no task list, and so on). One callback, called at most once, after the whole document has been walked, only when at least one construct degraded: a report object holding degradations, every Degradation in encounter order ({type: string, message: string, line?: number, snippet?: string}, exported as Degradation, with type a literal union that grows as new degradation sites report; snippet is the offending construct's text, truncated to 40 characters, present whenever there's a specific piece of source text to quote), and message, the same degradations grouped, snippeted, and sorted by line into one human-readable string.

    const blocks = markdownToPortableText('**a**', {
      schema: compileSchema(defineSchema({})),
      onDegradation: (report) => console.log(report),
    })
    // blocks: a plain span reading `a`, the `strong` formatting dropped
    // report: {
    //   degradations: [{type: 'decorator-dropped', message: 'Removed bold formatting, kept the text: the schema has no `strong` decorator', line: 1, snippet: 'a'}],
    //   message: 'Markdown could not be converted without loss:\n- line 1: Removed bold formatting, kept the text: the schema has no `strong` decorator ("a")',
    // }

    Enforce against lossy output by throwing your own error from inside the callback; the throw propagates out of markdownToPortableText:

    markdownToPortableText('**a**\n\n**b**\n\n| x |\n| - |\n| y |', {
      schema: compileSchema(defineSchema({})),
      onDegradation: ({message}) => {
        throw new Error(message)
      },
    })
    // throws Error:
    // Markdown could not be converted without loss:
    // - Removed bold formatting, kept the text: the schema has no `strong` decorator (2×: "a", "b")
    // - line 5: Table became plain text blocks, rows and columns lost: the schema has no `table` block object

    Repeated declines of the same kind collapse into one line of message instead of repeating the sentence once per occurrence; degradations stays ungrouped, one entry per occurrence. Match on type: message is human-readable and may change between releases.

    With onDegradation unset, conversion still degrades silently: a library shouldn't log on its own initiative. This removes the previous behavior of a handful of style-fallback paths calling console.warn on their own; pass a function to onDegradation to observe those losses instead.

Patch Changes

  • #3183 0da0721 Thanks @christianhg! - fix: escape markdown syntax in plain span text during serialization

    If your Portable Text contains text that happens to look like markdown, converting it to markdown and back used to corrupt it: the punctuation was read as formatting instead of text. portableTextToMarkdown now backslash-escapes such text, so it comes back as exactly the text it was.

    // span text        markdown (before)   markdown (now)      re-parses as
    '*bar*' // *bar*               \*bar\*             the text `*bar*` (was: an emphasized span reading `bar`)
    '# heading' // # heading           \# heading          the text `# heading` (was: an `h1` block)
    '[x]: y' // [x]: y              \[x]: y             the text `[x]: y` (was: nothing, the line vanished)

    This works wherever the text sits (headings, blockquotes, list items, table cells) and also when the risky characters are split across neighboring spans. The visible change in your output: markdown for text containing such punctuation gains backslashes it didn't have before. It pastes and parses like any hand-written markdown.

    Text with the code decorator is never backslash-escaped. Its backtick delimiters widen instead, so the content survives verbatim even when it contains backticks:

    // span text with the `code` decorator   markdown (before)   markdown (now)
    'a`b' // `a`b`  (broken)     ``a`b``
    '`a' // ``a`   (broken)     `` `a ``

    If you supply custom mark or block renderers: children now arrives pre-escaped. When you need the original text, read the text argument instead (the built-in code renderer does exactly that).

    Two things stay as they were. A URL with an explicit scheme (https://…) or an email address is not escaped: it keeps its text and simply becomes a link on the next parse. A www.-style address is only left alone while it contains no markdown punctuation; with it, it gets escaped like ordinary text, and the round trip keeps every character either way. And leading or trailing whitespace that markdown itself trims still trims, same as before this change.

  • #3234 452fdbe Thanks @christianhg! - fix: parse markdown soft breaks as spaces, not line breaks

    Markdown written across several source lines, the way editors and prose tools wrap text, is one paragraph that reflows. markdownToPortableText used to bake each of those wraps into the text as a literal newline, exactly as if you had written a hard break, and converting back to markdown then produced real hard breaks that weren't in your document.

    Wrapped source like this:

    This paragraph is written
    across two source lines.

    used to parse to the span text 'This paragraph is written\nacross two source lines.' (a fixed line break in the content) and now parses to 'This paragraph is written across two source lines.' (one reflowing line, which is how markdown renders it).

    Real hard breaks are unchanged: end a line with two or more spaces, or a backslash, and the span text still gets a \n:

    Line one\
    Line two

    still parses to 'Line one\nLine two'.

@portabletext/editor@8.1.3

Patch Changes

  • #3236 adb3e46 Thanks @christianhg! - fix: emit reliable patches after clearing the editor

    Deleting all content makes the editor emit an unset patch that removes the entire value. Typing again then emitted patches that assumed the value still existed. Applying those patches dropped the typed text, or threw Cannot apply deep operations on primitive values.

    The editor now first emits patches that create the value again: setIfMissing, an insert of the block, then the text changes. Deleting all content again emits unset again.

  • #3245 85fc2d7 Thanks @christianhg! - fix: match the inserted list block by identity when inheriting list properties

    Inserting keyless blocks into a list via an insert.blocks event now inherits the surrounding list's level and listItem as intended. Previously the inserted list block kept whatever level and listItem it arrived with, and with more than one keyless block in the event the insertion could abort entirely after hitting the event-chain depth limit.

  • #3235 53f24a9 Thanks @christianhg! - fix: keep numeric path segments for keyless nodes in resolved paths

    Paths returned by getNode, getChildren, and getAncestors now carry the numeric sibling index for a node without a usable _key, instead of a fabricated {_key: undefined} segment that cannot distinguish keyless siblings. Repairs and edits addressing keyless nodes now always target the right node, including keyless children nested under keyless parents, and the patches they emit address the same numeric position.

  • #3232 73dd0e3 Thanks @christianhg! - fix: mint keys for empty-string and non-string _key values, not just undefined

    A child carrying _key: '' or a non-string _key now gets a fresh key minted by normalization, the same repair a child with no _key at all already received. Previously such keys were kept as-is, leaving nodes the editor could not reliably address. When several keyless siblings arrive at once, each now receives its own distinct key instead of the first sibling absorbing every mint.

  • #3245 81a6f77 Thanks @christianhg! - fix: pass blocks returned from onPaste unparsed to the insert.blocks event

    Blocks returned from a custom onPaste (the insert result) now reach the insert.blocks behavior event exactly as returned: keys are no longer generated, unused markDefs no longer stripped, and unknown block types no longer dropped before behaviors see them. The blocks are still validated against the schema when inserted, so nothing invalid reaches the document.

    One narrow behavioral delta rides along: when the returned array puts an unknown-type block before a text block, the text block now inserts as its own block instead of merging into the block at the cursor, matching what a direct insert.blocks event already did.

  • #3232 f80ab9f Thanks @christianhg! - fix: schedule keyless children from a wholesale set for key-mint normalization

    Blocks or children that arrive without a _key through a whole-array set patch are now repaired: normalization mints a key for every keyless child and emits the corresponding set patches. Previously such children were skipped when collecting normalization work, so they stayed keyless in the editor and any edit addressing them could not target the document.

@portabletext/plugin-character-pair-decorator@9.0.8

Patch Changes

  • Updated dependencies []:
    • @portabletext/plugin-input-rule@7.0.8

@portabletext/plugin-dnd@2.0.9

Patch Changes

  • fix(deps): require @portabletext/editor@^8.1.3

@portabletext/plugin-emoji-picker@8.0.8

Patch Changes

  • Updated dependencies []:
    • @portabletext/plugin-input-rule@7.0.8

@portabletext/plugin-input-rule@7.0.8

Patch Changes

  • fix(deps): require @portabletext/editor@^8.1.3

@portabletext/plugin-list-index@2.0.7

Patch Changes

  • fix(deps): require @portabletext/editor@^8.1.3

@portabletext/plugin-markdown-shortcuts@9.0.8

Patch Changes

  • Updated dependencies []:
    • @portabletext/plugin-character-pair-decorator@9.0.8
    • @portabletext/plugin-input-rule@7.0.8

@portabletext/plugin-one-line@8.0.7

Patch Changes

  • fix(deps): require @portabletext/editor@^8.1.3

@portabletext/plugin-paste-link@5.0.7

Patch Changes

  • fix(deps): require @portabletext/editor@^8.1.3

@portabletext/plugin-sdk-value@8.1.2

Patch Changes

  • fix(deps): require @portabletext/editor@^8.1.3

@portabletext/plugin-table@2.0.7

Patch Changes

  • fix(deps): require @portabletext/editor@^8.1.3

@portabletext/plugin-typeahead-picker@7.0.8

Patch Changes

  • Updated dependencies []:
    • @portabletext/plugin-input-rule@7.0.8

@portabletext/plugin-typography@9.0.8

Patch Changes

  • Updated dependencies []:
    • @portabletext/plugin-input-rule@7.0.8

@portabletext/toolbar@9.0.8

Patch Changes

  • fix(deps): require @portabletext/editor@^8.1.3

@vercel

vercel Bot commented Sep 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
portable-text-editor-documentation Ready Ready Preview Sep 8, 2026 10:37am UTC
portable-text-example-basic Ready Ready Preview Sep 8, 2026 10:37am UTC
portable-text-playground Ready Ready Preview Sep 8, 2026 10:37am UTC

Request Review

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Bundle Stats

✅ No significant changes.

All scenario measurements (7)

🗺️ @portabletext/editor / @portabletext/editor · @portabletext/editor / @portabletext/editor/behaviors · @portabletext/editor / @portabletext/editor/plugins · @portabletext/editor / @portabletext/editor/selectors · @portabletext/editor / @portabletext/editor/traversal · @portabletext/editor / @portabletext/editor/utils · @portabletext/markdown / @portabletext/markdown · Artifacts

Scenario Kind Bundle (raw / gzip) Gzip change Import time Import change
⚪ @portabletext/editor / @portabletext/editor export 1.09 MB / 254.2 KB None 70 ms +3 ms, +4.6%
⚪ @portabletext/editor / @portabletext/editor/behaviors export 4.0 KB / 1.4 KB None 2 ms +0 ms, +6.1%
⚪ @portabletext/editor / @portabletext/editor/plugins export 5.1 KB / 1.8 KB None 7 ms +0 ms, +0.7%
⚪ @portabletext/editor / @portabletext/editor/selectors export 94.7 KB / 21.7 KB None 8 ms -0 ms, -0.4%
⚪ @portabletext/editor / @portabletext/editor/traversal export 42.8 KB / 11.2 KB None 6 ms +0 ms, +2.7%
⚪ @portabletext/editor / @portabletext/editor/utils export 33.8 KB / 9.1 KB None 6 ms +0 ms, +1.4%
⚪ @portabletext/markdown / @portabletext/markdown export 312.3 KB / 90.7 KB None 41 ms +1 ms, +1.9%

Significant means at least 1.0 KB and 1% gzip, or at least 5 ms and 10% import time.

@ecoscript
ecoscript Bot force-pushed the changeset-release/main branch from 1197689 to b526769 Compare September 7, 2026 09:41
@ecoscript
ecoscript Bot force-pushed the changeset-release/main branch from b526769 to d759b05 Compare September 7, 2026 09:44
@ecoscript
ecoscript Bot force-pushed the changeset-release/main branch from d759b05 to c9721b7 Compare September 7, 2026 10:05
@ecoscript
ecoscript Bot force-pushed the changeset-release/main branch from c9721b7 to 310ea73 Compare September 7, 2026 10:08
@ecoscript
ecoscript Bot force-pushed the changeset-release/main branch from 310ea73 to 9898fb8 Compare September 7, 2026 13:38
@ecoscript
ecoscript Bot force-pushed the changeset-release/main branch from 9898fb8 to 3f3e2e9 Compare September 8, 2026 06:13
@ecoscript
ecoscript Bot force-pushed the changeset-release/main branch from 3f3e2e9 to 4b5c1d7 Compare September 8, 2026 06:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants