diff --git a/.claude/skills/create-example/SKILL.md b/.claude/skills/create-example/SKILL.md
new file mode 100644
index 0000000000..dbf95af451
--- /dev/null
+++ b/.claude/skills/create-example/SKILL.md
@@ -0,0 +1,72 @@
+---
+name: create-example
+description: Creates a new example under the `/examples` directory.
+---
+
+This skill provides instructions on how to create a BlockNote editor example correctly.
+
+# Creating an example root directory
+
+Under the `/examples` directory, each subdirectory is a category of examples. It's name consists of a 2 digit index, followed by a dash and the category name.
+
+Each of these contains another set of subdirectories, where each one contains a single example. The naming of these is the same, but the category name is swapped for the example name.
+
+Based on the user's prompt, the most relevant category should be chosen, and a new directory for the example should be created. The index in the example directory's name should be the lowest unused one to avoid large diffs from having to reorder & rename the existing example directories. It is very unlikely that a new category directory should need to be created for the new example, but it should use the same convention.
+
+# Source & metadata files
+
+## Source files
+
+Any source files must be inside a `/src` directory at the root of the example directory. Within these, there must also be an `App.tsx` file, which default exports a React component. This component is responsible for rendering the entire example.
+
+## Metadata files
+
+There are two files containing metadata that must also be added at the root of the example directory:
+
+`.bnexample.json`
+
+Contains all of the example's configuration. Here's an annotated example (from `/examples/03-ui-components/13-custom-ui/.bnexample.json`):
+
+```
+
+"playground": true,
+
+"docs": true,
+
+"author": "matthewlipski",
+
+"tags": [
+ "Advanced",
+ "Inline Content",
+ "UI Components",
+ "Block Side Menu",
+ "Formatting Toolbar",
+ "Suggestion Menus",
+ "Slash Menu",
+ "Appearance & Styling"
+],
+
+"dependencies": {
+ "@mui/icons-material": "^5.16.1",
+ "@mui/material": "^5.16.1"
+},
+
+"pro": true
+```
+
+`README.md`
+
+A Markdown description of the example. Made of four parts:
+
+1. Heading with the example name. This does not necessarily need to be the same as the example directory name and can be more verbose.
+2. Description of the example, which should be no longer than a paragraph of three sentences.
+3. An optional "Try me out!" callout. Should be a single sentence instructing the user how to see the changes made to the editor in the example.
+4. A list of relevant docs. These are mostly internal but may also refer to e.g. dependencies used in the example.
+
+See `/examples/07-collaboration/01-partykit` for reference on the exact markup of these sections.
+
+# Generated files
+
+Once the source & metadata files are done, `vp run gen` should be executed from the project root directory to auto-generate additional files in the example directory, as well as the playground & docs.
+
+One of the generated files is `package.json` in the example directory. If the `bnexample.json` specified any dependencies, these will be included here. Therefore, `vp install` should always be executed in the project root directory after, to ensure these are installed.
diff --git a/.claude/skills/debug-skill/SKILL.md b/.claude/skills/debug-skill/SKILL.md
new file mode 100644
index 0000000000..cc47080e23
--- /dev/null
+++ b/.claude/skills/debug-skill/SKILL.md
@@ -0,0 +1,70 @@
+---
+name: debug-skill
+description: Instructions for navigating and debugging BlockNote in a browser. Shows how to open specific menus & toolbars, as well select content. Should be used when prompted to fix a bug that requires inspecting the editor's appearance or rendered HTML.
+---
+
+# General loop
+
+When fixing a bug, the following feedback loop should be used.
+
+1. Apply a code change that you think will fix the issue.
+2. Test the change in a browser environment.
+3. Take screenshots to verify that the issue is fixed.
+4. Repeat until the bug is indeed fixed.
+
+# Browser environment
+
+Before starting up a browser environment, you need to ensure the dev server is running. This can be done by checking if port 5173 is in use. If it isn't, running `vp run dev` at the project root will start the server.
+
+The Playwright CLI should be used for the browser environment. It can be used to navigate to the dev server and programmatically issue mouse clicks/keyboard inputs. If not installed, stop what you're doing and notify the user to install it.
+
+# Selecting an example
+
+After navigating to `localhost:5173`, an example must be selected. These are listed in the navbar (`mantine-AppShell-navbar` CSS class). The "Default Schema Showcase" should be selected, unless stated otherwise by the user.
+
+Each example will contain a BlockNote editor, and possibly additional elements like text fields or static toolbars.
+
+# Editor HTML structure
+
+Below is a list of elements that make up a BlockNote editor. This is helpful for mapping BlockNote concepts to what's actually visible in the browser. The nesting of the list items is representative of how the corresponding elements are nested in the rendered HTML. The elements are referenced by their main CSS class.
+
+- `bn-container`: Wrapper element for the editor.
+ - `bn-editor`: Root element for the BlockNote editor.
+ - `bn-block-group`: Root container for blocks.
+ - `bn-block-outer`: Wrapper element for a block.
+ - `bn-block`: Root element for a block.
+ - `bn-block-content`: Container element for all content rendered by the block itself. Also renders a `data-content-type` attribute which stores the block's type, and additional `data-*` for every non-default prop that the block has.
+ - `bn-inline-content`: Container element for user-editable rich text within a block. Note that not all blocks will contain this element.
+ - `bn-block-group`: Container for nested blocks. Note that if a block doesn't contain nested blocks, it won't have this element.
+ - `bn-block-column-list`: Container element for columns.
+ - `bn-block-column`: Column element containing blocks.
+
+Each element only appears once in its parent, except `bn-block-outer` and `bn-block-column-list`, which can appear multiple times.
+
+Each `bn-block-group` and `bn-block-column` also contain `bn-block-outer` elements. These are not listed as they can be nested to an arbitrary depth.
+
+Note that additional UI elements like menus and toolbars are mounted in a portal attached to the `body`.
+
+# Keyboard navigation
+
+Assume you are on a machine running macOS. You can use the following key combinations to navigate through the editor and create selections:
+
+- Left/Right Arrow: Moves the text cursor back/forward one character.
+- Up/Down Arrow: Moves the text cursor to the previous/next block.
+- Option + Left/Right Arrow: Moves the text cursor to the start/end of the current word. If already at the start/end of a word, moves it to the start/end of the previous/next one instead.
+- Cmd + Left/Right Arrow: Moves the text cursor to the start/end of the line.
+- Cmd + Up/Down Arrow: Moves the text cursor to the start/end of the document.
+
+Each of these can also be used with Shift to create/extend a selection instead of just moving the cursor.
+
+It is extremely important to note that these key combinations are only relevant for debugging and NOT for writing end-to-end tests. While Playwright is used for both, tests run in a Linux environment which has different bindings for keyboard navigation.
+
+# Opening menus & toolbars
+
+Here are the most often used UI elements, and how to find/open them.
+
+- **Formatting toolbar**: Create a selection using the keyboard and look for an element with the `bn-formatting-toolbar` CSS class. Buttons/dropdowns within it should be interacted with using the mouse instead. The `data-test` attribute will inform you what a given button or dropdown is for. Press escape to dismiss the toolbar.
+- **Side menu**: Hover a block with the mouse, i.e. a `bn-block` element, and look for an element with the `bn-side-menu` CSS class. Unless specified otherwise, it contains a button to add a block ("Add block" ARIA label) and a drag handle which opens a menu on click ("Open block menu" ARIA label). Typing in the editor or moving the mouse cursor above/below it will hide the side menu, unless the drag handle menu is open. Then, it's "frozen" until dismissed by an outside click or pressing Escape.
+- **Slash menu**: Type the "/" key while in a block and look for an element with the `bn-suggestion-menu` CSS class. It contains a list of items with the `bn-suggestion-menu-item` CSS class. While the menu is open, the up/down arrows navigate through items instead of moving the text cursor. Items can be triggered with a mouse click or pressing Enter while selected. Each item will convert the type of the current block to one of a given type, if it's empty. Otherwise, it will create a new block below with that type. The `bn-suggestion-menu-item-title` element's text content will indicate the new type. Pressing Escape closes the menu.
+- **Link toolbar**: Hover a link in a block (anchor element within a `bn-inline-content` element), or move the text selection inside it using the arrow keys, and look for an element with the `bn-link-toolbar` CSS class. Unless specified otherwise, it contains three buttons. The first has the text, "Edit link". On click, it opens a popup to edit the link text and URL. You can locate these inputs with the "Edit title" and "Edit URL" placeholders. The other two buttons are for opening the link in a new tab ("Open in new tab" ARIA label) and deleting the link ("Remove link" ARIA label). If the toolbar was opened via mouse hover, moving the mouse off of the link or toolbar will close it after half a second. Otherwise, moving the text cursor outside the link will close the toolbar. It can also be dismissed by pressing Escape.
+- **File panel**: After creating a file, image, video, or audio block, it will render a button with the text "Add file" (`bn-add-file-button` CSS class). Clicking the button will open the file panel. When the block is created using the slash menu (typically the case), the file panel will be open immediately. It always has an "Embed" tab (`data-test="embed-tab"` attribute). While this tab is selected, the file panel displays an input for the file URL ("Enter URL" placeholder) and "Embed file" button. For some examples, an "Upload" tab (`data-test="upload-tab"` attribute) will also be present. While it's selected, the file panel will display a file input (`data-test="upload-input"` attribute). After embedding/uploading a file, the block will render said file instead of displaying the "Add file" button.
diff --git a/.claude/skills/github-issues/SKILL.md b/.claude/skills/github-issues/SKILL.md
new file mode 100644
index 0000000000..c3866924a7
--- /dev/null
+++ b/.claude/skills/github-issues/SKILL.md
@@ -0,0 +1,18 @@
+---
+name: github-issues
+description: Scan the BlockNote GitHub repository for issues and PRs relevant to the current task. Use when starting work on a new feature, bug fix, or other code modification.
+---
+
+This skill searches the BlockNote GitHub repository for existing issues and PRs that are relevant to the task at hand.
+
+# When to use
+
+Use this skill when prompted to write a new feature, fix a bug, or make some other modification to the code. It should be invoked before writing any code to surface relevant context from the project's issue tracker.
+
+# Steps
+
+1. Use the GitHub CLI (`gh`) to search for issues and PRs in the repository that are relevant to the user's task. Search both open and closed issues/PRs using relevant keywords.
+2. Summarize the findings:
+ - If nothing relevant is found, report that and proceed with the task.
+ - If relevant issues or PRs are found, present a summary and prompt the user on next steps before writing code.
+3. Once the task is completed, remind the user of the relevant issues and PRs found during this initial investigation so they can be referenced or closed as appropriate.
diff --git a/.claude/skills/playwright-cli/SKILL.md b/.claude/skills/playwright-cli/SKILL.md
new file mode 100644
index 0000000000..fe30992ad9
--- /dev/null
+++ b/.claude/skills/playwright-cli/SKILL.md
@@ -0,0 +1,394 @@
+---
+name: playwright-cli
+description: Automate browser interactions, test web pages and work with Playwright tests.
+allowed-tools: Bash(playwright-cli:*) Bash(npx:*) Bash(npm:*)
+---
+
+# Browser Automation with playwright-cli
+
+## Quick start
+
+```bash
+# open new browser
+playwright-cli open
+# navigate to a page
+playwright-cli goto https://playwright.dev
+# interact with the page using refs from the snapshot
+playwright-cli click e15
+playwright-cli type "page.click"
+playwright-cli press Enter
+# take a screenshot (rarely used, as snapshot is more common)
+playwright-cli screenshot
+# close the browser
+playwright-cli close
+```
+
+## Commands
+
+### Core
+
+```bash
+playwright-cli open
+# open and navigate right away
+playwright-cli open https://example.com/
+playwright-cli goto https://playwright.dev
+playwright-cli type "search query"
+playwright-cli click e3
+playwright-cli dblclick e7
+# --submit presses Enter after filling the element
+playwright-cli fill e5 "user@example.com" --submit
+playwright-cli drag e2 e8
+# drop files or data onto an element (from outside the page)
+playwright-cli drop e4 --path=./image.png
+playwright-cli drop e4 --data="text/plain=hello world"
+playwright-cli hover e4
+playwright-cli select e9 "option-value"
+playwright-cli upload ./document.pdf
+playwright-cli check e12
+playwright-cli uncheck e12
+playwright-cli snapshot
+playwright-cli eval "document.title"
+playwright-cli eval "el => el.textContent" e5
+# get element id, class, or any attribute not visible in the snapshot
+playwright-cli eval "el => el.id" e5
+playwright-cli eval "el => el.getAttribute('data-testid')" e5
+playwright-cli dialog-accept
+playwright-cli dialog-accept "confirmation text"
+playwright-cli dialog-dismiss
+playwright-cli resize 1920 1080
+playwright-cli close
+```
+
+### Navigation
+
+```bash
+playwright-cli go-back
+playwright-cli go-forward
+playwright-cli reload
+```
+
+### Keyboard
+
+```bash
+playwright-cli press Enter
+playwright-cli press ArrowDown
+playwright-cli keydown Shift
+playwright-cli keyup Shift
+```
+
+### Mouse
+
+```bash
+playwright-cli mousemove 150 300
+playwright-cli mousedown
+playwright-cli mousedown right
+playwright-cli mouseup
+playwright-cli mouseup right
+playwright-cli mousewheel 0 100
+```
+
+### Save as
+
+Also resize large screenshots with sips (native macOS tool) if possible.
+
+Screenshots should be saved to `.claude/skills/playwright-cli/screenshots/` in the workspace root.
+
+```bash
+playwright-cli screenshot
+playwright-cli screenshot e5
+playwright-cli screenshot --filename=page.png
+playwright-cli pdf --filename=page.pdf
+```
+
+### Tabs
+
+```bash
+playwright-cli tab-list
+playwright-cli tab-new
+playwright-cli tab-new https://example.com/page
+playwright-cli tab-close
+playwright-cli tab-close 2
+playwright-cli tab-select 0
+```
+
+### Storage
+
+```bash
+playwright-cli state-save
+playwright-cli state-save auth.json
+playwright-cli state-load auth.json
+
+# Cookies
+playwright-cli cookie-list
+playwright-cli cookie-list --domain=example.com
+playwright-cli cookie-get session_id
+playwright-cli cookie-set session_id abc123
+playwright-cli cookie-set session_id abc123 --domain=example.com --httpOnly --secure
+playwright-cli cookie-delete session_id
+playwright-cli cookie-clear
+
+# LocalStorage
+playwright-cli localstorage-list
+playwright-cli localstorage-get theme
+playwright-cli localstorage-set theme dark
+playwright-cli localstorage-delete theme
+playwright-cli localstorage-clear
+
+# SessionStorage
+playwright-cli sessionstorage-list
+playwright-cli sessionstorage-get step
+playwright-cli sessionstorage-set step 3
+playwright-cli sessionstorage-delete step
+playwright-cli sessionstorage-clear
+```
+
+### Network
+
+```bash
+playwright-cli route "**/*.jpg" --status=404
+playwright-cli route "https://api.example.com/**" --body='{"mock": true}'
+playwright-cli route-list
+playwright-cli unroute "**/*.jpg"
+playwright-cli unroute
+```
+
+### DevTools
+
+```bash
+playwright-cli console
+playwright-cli console warning
+playwright-cli requests
+playwright-cli request 5
+playwright-cli run-code "async page => await page.context().grantPermissions(['geolocation'])"
+playwright-cli run-code --filename=script.js
+playwright-cli tracing-start
+playwright-cli tracing-stop
+playwright-cli video-start video.webm
+playwright-cli video-chapter "Chapter Title" --description="Details" --duration=2000
+playwright-cli video-stop
+
+# launch the dashboard for UI review / design feedback — user annotates the page, you receive the annotated screenshot, snapshot, and notes
+playwright-cli show --annotate
+
+# generate a Playwright locator for an element from its ref or selector
+playwright-cli generate-locator e5 --raw
+
+# show a persistent highlight overlay for an element, optionally with a custom style
+playwright-cli highlight e5
+playwright-cli highlight e5 --style="outline: 3px dashed red"
+# hide a single element highlight, or all page highlights when no target is given
+playwright-cli highlight e5 --hide
+playwright-cli highlight --hide
+```
+
+## Raw output
+
+The global `--raw` option strips page status, generated code, and snapshot sections from the output, returning only the result value. Use it to pipe command output into other tools. Commands that don't produce output return nothing.
+
+```bash
+playwright-cli --raw eval "JSON.stringify(performance.timing)" | jq '.loadEventEnd - .navigationStart'
+playwright-cli --raw eval "JSON.stringify([...document.querySelectorAll('a')].map(a => a.href))" > links.json
+playwright-cli --raw snapshot > before.yml
+playwright-cli click e5
+playwright-cli --raw snapshot > after.yml
+diff before.yml after.yml
+TOKEN=$(playwright-cli --raw cookie-get session_id)
+playwright-cli --raw localstorage-get theme
+```
+
+For structured output wrapping every reply as JSON, pass --json
+
+```bash
+playwright-cli list --json
+```
+
+## Open parameters
+
+```bash
+# Use specific browser when creating session
+playwright-cli open --browser=chrome
+playwright-cli open --browser=firefox
+playwright-cli open --browser=webkit
+playwright-cli open --browser=msedge
+
+# Use persistent profile (by default profile is in-memory)
+playwright-cli open --persistent
+# Use persistent profile with custom directory
+playwright-cli open --profile=/path/to/profile
+
+# Connect to browser via Playwright Extension
+playwright-cli attach --extension=chrome
+
+# Connect to a running Chrome or Edge by channel name
+playwright-cli attach --cdp=chrome
+playwright-cli attach --cdp=msedge
+
+# Connect to a running browser via CDP endpoint
+playwright-cli attach --cdp=http://localhost:9222
+
+# Start with config file
+playwright-cli open --config=my-config.json
+
+# Close the browser
+playwright-cli close
+# Detach from an attached browser (leaves the external browser running)
+playwright-cli -s=msedge detach
+# Delete user data for the default session
+playwright-cli delete-data
+```
+
+## Snapshots
+
+After each command, playwright-cli provides a snapshot of the current browser state.
+
+```bash
+> playwright-cli goto https://example.com
+### Page
+- Page URL: https://example.com/
+- Page Title: Example Domain
+### Snapshot
+[Snapshot](.playwright-cli/page-2026-02-14T19-22-42-679Z.yml)
+```
+
+You can also take a snapshot on demand using `playwright-cli snapshot` command. All the options below can be combined as needed.
+
+```bash
+# default - save to a file with timestamp-based name
+playwright-cli snapshot
+
+# save to file, use when snapshot is a part of the workflow result
+playwright-cli snapshot --filename=after-click.yaml
+
+# snapshot an element instead of the whole page
+playwright-cli snapshot "#main"
+
+# limit snapshot depth for efficiency, take a partial snapshot afterwards
+playwright-cli snapshot --depth=4
+playwright-cli snapshot e34
+
+# include each element's bounding box as [box=x,y,width,height]
+playwright-cli snapshot --boxes
+```
+
+## Targeting elements
+
+By default, use refs from the snapshot to interact with page elements.
+
+```bash
+# get snapshot with refs
+playwright-cli snapshot
+
+# interact using a ref
+playwright-cli click e15
+```
+
+You can also use css selectors or Playwright locators.
+
+```bash
+# css selector
+playwright-cli click "#main > button.submit"
+
+# role locator
+playwright-cli click "getByRole('button', { name: 'Submit' })"
+
+# test id
+playwright-cli click "getByTestId('submit-button')"
+```
+
+## Browser Sessions
+
+```bash
+# create new browser session named "mysession" with persistent profile
+playwright-cli -s=mysession open example.com --persistent
+# same with manually specified profile directory (use when requested explicitly)
+playwright-cli -s=mysession open example.com --profile=/path/to/profile
+playwright-cli -s=mysession click e6
+playwright-cli -s=mysession close # stop a named browser
+playwright-cli -s=mysession delete-data # delete user data for persistent session
+
+playwright-cli list
+# Close all browsers
+playwright-cli close-all
+# Forcefully kill all browser processes
+playwright-cli kill-all
+```
+
+## Installation
+
+If global `playwright-cli` command is not available, try a local version via `npx playwright-cli`:
+
+```bash
+npx --no-install playwright-cli --version
+```
+
+When local version is available, use `npx playwright-cli` in all commands. Otherwise, install `playwright-cli` as a global command:
+
+```bash
+npm install -g @playwright/cli@latest
+```
+
+## Example: Form submission
+
+```bash
+playwright-cli open https://example.com/form
+playwright-cli snapshot
+
+playwright-cli fill e1 "user@example.com"
+playwright-cli fill e2 "password123"
+playwright-cli click e3
+playwright-cli snapshot
+playwright-cli close
+```
+
+## Example: Multi-tab workflow
+
+```bash
+playwright-cli open https://example.com
+playwright-cli tab-new https://example.com/other
+playwright-cli tab-list
+playwright-cli tab-select 0
+playwright-cli snapshot
+playwright-cli close
+```
+
+## Example: Debugging with DevTools
+
+```bash
+playwright-cli open https://example.com
+playwright-cli click e4
+playwright-cli fill e7 "test"
+playwright-cli console
+playwright-cli requests
+playwright-cli close
+```
+
+```bash
+playwright-cli open https://example.com
+playwright-cli tracing-start
+playwright-cli click e4
+playwright-cli fill e7 "test"
+playwright-cli tracing-stop
+playwright-cli close
+```
+
+## Example: Interactive session
+
+Ask the user for UI review or design feedback. The user draws boxes on the live page and types comments; you receive the annotated screenshot, the snapshot of the marked region, and the user's notes. Use this whenever the user asks for "UI review", "design feedback", or to "ask the user what they think / want / mean":
+
+```bash
+playwright-cli open https://example.com
+playwright-cli show --annotate
+```
+
+## Specific tasks
+
+- **Running and Debugging Playwright tests** [references/playwright-tests.md](references/playwright-tests.md)
+- **Request mocking** [references/request-mocking.md](references/request-mocking.md)
+- **Running Playwright code** [references/running-code.md](references/running-code.md)
+- **Browser session management** [references/session-management.md](references/session-management.md)
+- **Spec-driven testing (plan / generate / heal)** [references/spec-driven-testing.md](references/spec-driven-testing.md)
+- **Storage state (cookies, localStorage)** [references/storage-state.md](references/storage-state.md)
+- **Test generation** [references/test-generation.md](references/test-generation.md)
+- **Tracing** [references/tracing.md](references/tracing.md)
+- **Video recording** [references/video-recording.md](references/video-recording.md)
+- **Inspecting element attributes** [references/element-attributes.md](references/element-attributes.md)
diff --git a/.claude/skills/playwright-cli/references/element-attributes.md b/.claude/skills/playwright-cli/references/element-attributes.md
new file mode 100644
index 0000000000..4e9fa6b991
--- /dev/null
+++ b/.claude/skills/playwright-cli/references/element-attributes.md
@@ -0,0 +1,23 @@
+# Inspecting Element Attributes
+
+When the snapshot doesn't show an element's `id`, `class`, `data-*` attributes, or other DOM properties, use `eval` to inspect them.
+
+## Examples
+
+```bash
+playwright-cli snapshot
+# snapshot shows a button as e7 but doesn't reveal its id or data attributes
+
+# get the element's id
+playwright-cli eval "el => el.id" e7
+
+# get all CSS classes
+playwright-cli eval "el => el.className" e7
+
+# get a specific attribute
+playwright-cli eval "el => el.getAttribute('data-testid')" e7
+playwright-cli eval "el => el.getAttribute('aria-label')" e7
+
+# get a computed style property
+playwright-cli eval "el => getComputedStyle(el).display" e7
+```
diff --git a/.claude/skills/playwright-cli/references/playwright-tests.md b/.claude/skills/playwright-cli/references/playwright-tests.md
new file mode 100644
index 0000000000..bec2ec90e4
--- /dev/null
+++ b/.claude/skills/playwright-cli/references/playwright-tests.md
@@ -0,0 +1,39 @@
+# Running Playwright Tests
+
+To run Playwright tests, use the `npx playwright test` command, or a package manager script. To avoid opening the interactive html report, use `PLAYWRIGHT_HTML_OPEN=never` environment variable.
+
+```bash
+# Run all tests
+PLAYWRIGHT_HTML_OPEN=never npx playwright test
+
+# Run all tests through a custom npm script
+PLAYWRIGHT_HTML_OPEN=never npm run special-test-command
+```
+
+# Debugging Playwright Tests
+
+To debug a failing Playwright test, run it with `--debug=cli` option. This command will pause the test at the start and print the debugging instructions.
+
+**IMPORTANT**: run the command in the background and check the output until "Debugging Instructions" is printed. Make sure to stop the command after you have finished.
+
+Once instructions containing a session name are printed, use `playwright-cli` to attach the session and explore the page.
+
+```bash
+# Run the test
+PLAYWRIGHT_HTML_OPEN=never npx playwright test --debug=cli
+# ...
+# ... debugging instructions for "tw-abcdef" session ...
+# ...
+
+# Attach to the test
+playwright-cli attach tw-abcdef
+```
+
+Keep the test running in the background while you explore and look for a fix.
+The test is paused at the start, so you should step over or pause at a particular location
+where the problem is most likely to be.
+
+Every action you perform with `playwright-cli` generates corresponding Playwright TypeScript code.
+This code appears in the output and can be copied directly into the test. Most of the time, a specific locator or an expectation should be updated, but it could also be a bug in the app. Use your judgement.
+
+After fixing the test, stop the background test run. Rerun to check that test passes.
diff --git a/.claude/skills/playwright-cli/references/request-mocking.md b/.claude/skills/playwright-cli/references/request-mocking.md
new file mode 100644
index 0000000000..9005fda67d
--- /dev/null
+++ b/.claude/skills/playwright-cli/references/request-mocking.md
@@ -0,0 +1,87 @@
+# Request Mocking
+
+Intercept, mock, modify, and block network requests.
+
+## CLI Route Commands
+
+```bash
+# Mock with custom status
+playwright-cli route "**/*.jpg" --status=404
+
+# Mock with JSON body
+playwright-cli route "**/api/users" --body='[{"id":1,"name":"Alice"}]' --content-type=application/json
+
+# Mock with custom headers
+playwright-cli route "**/api/data" --body='{"ok":true}' --header="X-Custom: value"
+
+# Remove headers from requests
+playwright-cli route "**/*" --remove-header=cookie,authorization
+
+# List active routes
+playwright-cli route-list
+
+# Remove a route or all routes
+playwright-cli unroute "**/*.jpg"
+playwright-cli unroute
+```
+
+## URL Patterns
+
+```
+**/api/users - Exact path match
+**/api/*/details - Wildcard in path
+**/*.{png,jpg,jpeg} - Match file extensions
+**/search?q=* - Match query parameters
+```
+
+## Advanced Mocking with run-code
+
+For conditional responses, request body inspection, response modification, or delays:
+
+### Conditional Response Based on Request
+
+```bash
+playwright-cli run-code "async page => {
+ await page.route('**/api/login', route => {
+ const body = route.request().postDataJSON();
+ if (body.username === 'admin') {
+ route.fulfill({ body: JSON.stringify({ token: 'mock-token' }) });
+ } else {
+ route.fulfill({ status: 401, body: JSON.stringify({ error: 'Invalid' }) });
+ }
+ });
+}"
+```
+
+### Modify Real Response
+
+```bash
+playwright-cli run-code "async page => {
+ await page.route('**/api/user', async route => {
+ const response = await route.fetch();
+ const json = await response.json();
+ json.isPremium = true;
+ await route.fulfill({ response, json });
+ });
+}"
+```
+
+### Simulate Network Failures
+
+```bash
+playwright-cli run-code "async page => {
+ await page.route('**/api/offline', route => route.abort('internetdisconnected'));
+}"
+# Options: connectionrefused, timedout, connectionreset, internetdisconnected
+```
+
+### Delayed Response
+
+```bash
+playwright-cli run-code "async page => {
+ await page.route('**/api/slow', async route => {
+ await new Promise(r => setTimeout(r, 3000));
+ route.fulfill({ body: JSON.stringify({ data: 'loaded' }) });
+ });
+}"
+```
diff --git a/.claude/skills/playwright-cli/references/running-code.md b/.claude/skills/playwright-cli/references/running-code.md
new file mode 100644
index 0000000000..06645ec124
--- /dev/null
+++ b/.claude/skills/playwright-cli/references/running-code.md
@@ -0,0 +1,240 @@
+# Running Custom Playwright Code
+
+Use `run-code` to execute arbitrary Playwright code for advanced scenarios not covered by CLI commands.
+
+## Syntax
+
+```bash
+playwright-cli run-code "async page => {
+ // Your Playwright code here
+ // Access page.context() for browser context operations
+}"
+```
+
+You can also load the function from a file:
+
+```bash
+playwright-cli run-code --filename=./my-script.js
+```
+
+The code must be a single function expression, it is wrapped in `(...)` and evaluated.
+import/export/require syntax is not supported.
+
+## Geolocation
+
+```bash
+# Grant geolocation permission and set location
+playwright-cli run-code "async page => {
+ await page.context().grantPermissions(['geolocation']);
+ await page.context().setGeolocation({ latitude: 37.7749, longitude: -122.4194 });
+}"
+
+# Set location to London
+playwright-cli run-code "async page => {
+ await page.context().grantPermissions(['geolocation']);
+ await page.context().setGeolocation({ latitude: 51.5074, longitude: -0.1278 });
+}"
+
+# Clear geolocation override
+playwright-cli run-code "async page => {
+ await page.context().clearPermissions();
+}"
+```
+
+## Permissions
+
+```bash
+# Grant multiple permissions
+playwright-cli run-code "async page => {
+ await page.context().grantPermissions([
+ 'geolocation',
+ 'notifications',
+ 'camera',
+ 'microphone'
+ ]);
+}"
+
+# Grant permissions for specific origin
+playwright-cli run-code "async page => {
+ await page.context().grantPermissions(['clipboard-read'], {
+ origin: 'https://example.com'
+ });
+}"
+```
+
+## Media Emulation
+
+```bash
+# Emulate dark color scheme
+playwright-cli run-code "async page => {
+ await page.emulateMedia({ colorScheme: 'dark' });
+}"
+
+# Emulate light color scheme
+playwright-cli run-code "async page => {
+ await page.emulateMedia({ colorScheme: 'light' });
+}"
+
+# Emulate reduced motion
+playwright-cli run-code "async page => {
+ await page.emulateMedia({ reducedMotion: 'reduce' });
+}"
+
+# Emulate print media
+playwright-cli run-code "async page => {
+ await page.emulateMedia({ media: 'print' });
+}"
+```
+
+## Wait Strategies
+
+```bash
+# Wait for network idle
+playwright-cli run-code "async page => {
+ await page.waitForLoadState('networkidle');
+}"
+
+# Wait for specific element
+playwright-cli run-code "async page => {
+ await page.locator('.loading').waitFor({ state: 'hidden' });
+}"
+
+# Wait for function to return true
+playwright-cli run-code "async page => {
+ await page.waitForFunction(() => window.appReady === true);
+}"
+
+# Wait with timeout
+playwright-cli run-code "async page => {
+ await page.locator('.result').waitFor({ timeout: 10000 });
+}"
+```
+
+## Frames and Iframes
+
+```bash
+# Work with iframe
+playwright-cli run-code "async page => {
+ const frame = page.locator('iframe#my-iframe').contentFrame();
+ await frame.locator('button').click();
+}"
+
+# Get all frames
+playwright-cli run-code "async page => {
+ const frames = page.frames();
+ return frames.map(f => f.url());
+}"
+```
+
+## File Downloads
+
+```bash
+# Handle file download
+playwright-cli run-code "async page => {
+ const downloadPromise = page.waitForEvent('download');
+ await page.getByRole('link', { name: 'Download' }).click();
+ const download = await downloadPromise;
+ await download.saveAs('./downloaded-file.pdf');
+ return download.suggestedFilename();
+}"
+```
+
+## Clipboard
+
+```bash
+# Read clipboard (requires permission)
+playwright-cli run-code "async page => {
+ await page.context().grantPermissions(['clipboard-read']);
+ return await page.evaluate(() => navigator.clipboard.readText());
+}"
+
+# Write to clipboard
+playwright-cli run-code "async page => {
+ await page.evaluate(text => navigator.clipboard.writeText(text), 'Hello clipboard!');
+}"
+```
+
+## Page Information
+
+```bash
+# Get page title
+playwright-cli run-code "async page => {
+ return await page.title();
+}"
+
+# Get current URL
+playwright-cli run-code "async page => {
+ return page.url();
+}"
+
+# Get page content
+playwright-cli run-code "async page => {
+ return await page.content();
+}"
+
+# Get viewport size
+playwright-cli run-code "async page => {
+ return page.viewportSize();
+}"
+```
+
+## JavaScript Execution
+
+```bash
+# Execute JavaScript and return result
+playwright-cli run-code "async page => {
+ return await page.evaluate(() => {
+ return {
+ userAgent: navigator.userAgent,
+ language: navigator.language,
+ cookiesEnabled: navigator.cookieEnabled
+ };
+ });
+}"
+
+# Pass arguments to evaluate
+playwright-cli run-code "async page => {
+ const multiplier = 5;
+ return await page.evaluate(m => document.querySelectorAll('li').length * m, multiplier);
+}"
+```
+
+## Error Handling
+
+```bash
+# Try-catch in run-code
+playwright-cli run-code "async page => {
+ try {
+ await page.getByRole('button', { name: 'Submit' }).click({ timeout: 1000 });
+ return 'clicked';
+ } catch (e) {
+ return 'element not found';
+ }
+}"
+```
+
+## Complex Workflows
+
+```bash
+# Login and save state
+playwright-cli run-code "async page => {
+ await page.goto('https://example.com/login');
+ await page.getByRole('textbox', { name: 'Email' }).fill('user@example.com');
+ await page.getByRole('textbox', { name: 'Password' }).fill('secret');
+ await page.getByRole('button', { name: 'Sign in' }).click();
+ await page.waitForURL('**/dashboard');
+ await page.context().storageState({ path: 'auth.json' });
+ return 'Login successful';
+}"
+
+# Scrape data from multiple pages
+playwright-cli run-code "async page => {
+ const results = [];
+ for (let i = 1; i <= 3; i++) {
+ await page.goto(\`https://example.com/page/\${i}\`);
+ const items = await page.locator('.item').allTextContents();
+ results.push(...items);
+ }
+ return results;
+}"
+```
diff --git a/.claude/skills/playwright-cli/references/session-management.md b/.claude/skills/playwright-cli/references/session-management.md
new file mode 100644
index 0000000000..287e77fb7f
--- /dev/null
+++ b/.claude/skills/playwright-cli/references/session-management.md
@@ -0,0 +1,226 @@
+# Browser Session Management
+
+Run multiple isolated browser sessions concurrently with state persistence.
+
+## Named Browser Sessions
+
+Use `-s` flag to isolate browser contexts:
+
+```bash
+# Browser 1: Authentication flow
+playwright-cli -s=auth open https://app.example.com/login
+
+# Browser 2: Public browsing (separate cookies, storage)
+playwright-cli -s=public open https://example.com
+
+# Commands are isolated by browser session
+playwright-cli -s=auth fill e1 "user@example.com"
+playwright-cli -s=public snapshot
+```
+
+## Browser Session Isolation Properties
+
+Each browser session has independent:
+
+- Cookies
+- LocalStorage / SessionStorage
+- IndexedDB
+- Cache
+- Browsing history
+- Open tabs
+
+## Browser Session Commands
+
+```bash
+# List all browser sessions
+playwright-cli list
+
+# Stop a browser session (close the browser)
+playwright-cli close # stop the default browser
+playwright-cli -s=mysession close # stop a named browser
+
+# Stop all browser sessions
+playwright-cli close-all
+
+# Forcefully kill all daemon processes (for stale/zombie processes)
+playwright-cli kill-all
+
+# Delete browser session user data (profile directory)
+playwright-cli delete-data # delete default browser data
+playwright-cli -s=mysession delete-data # delete named browser data
+```
+
+## Environment Variable
+
+Set a default browser session name via environment variable:
+
+```bash
+export PLAYWRIGHT_CLI_SESSION="mysession"
+playwright-cli open example.com # Uses "mysession" automatically
+```
+
+## Common Patterns
+
+### Concurrent Scraping
+
+```bash
+#!/bin/bash
+# Scrape multiple sites concurrently
+
+# Start all browsers
+playwright-cli -s=site1 open https://site1.com &
+playwright-cli -s=site2 open https://site2.com &
+playwright-cli -s=site3 open https://site3.com &
+wait
+
+# Take snapshots from each
+playwright-cli -s=site1 snapshot
+playwright-cli -s=site2 snapshot
+playwright-cli -s=site3 snapshot
+
+# Cleanup
+playwright-cli close-all
+```
+
+### A/B Testing Sessions
+
+```bash
+# Test different user experiences
+playwright-cli -s=variant-a open "https://app.com?variant=a"
+playwright-cli -s=variant-b open "https://app.com?variant=b"
+
+# Compare
+playwright-cli -s=variant-a screenshot
+playwright-cli -s=variant-b screenshot
+```
+
+### Persistent Profile
+
+By default, browser profile is kept in memory only. Use `--persistent` flag on `open` to persist the browser profile to disk:
+
+```bash
+# Use persistent profile (auto-generated location)
+playwright-cli open https://example.com --persistent
+
+# Use persistent profile with custom directory
+playwright-cli open https://example.com --profile=/path/to/profile
+```
+
+## Attaching to a Running Browser
+
+Use `attach` to connect to a browser that is already running, instead of launching a new one.
+
+### Attach by channel name
+
+Connect to a running Chrome or Edge instance by its channel name. The browser must have remote debugging enabled — navigate to `chrome://inspect/#remote-debugging` in the target browser and check "Allow remote debugging for this browser instance".
+
+```bash
+# Attach to Chrome
+playwright-cli attach --cdp=chrome
+
+# Attach to Chrome Canary
+playwright-cli attach --cdp=chrome-canary
+
+# Attach to Microsoft Edge
+playwright-cli attach --cdp=msedge
+
+# Attach to Edge Dev
+playwright-cli attach --cdp=msedge-dev
+```
+
+Supported channels: `chrome`, `chrome-beta`, `chrome-dev`, `chrome-canary`, `msedge`, `msedge-beta`, `msedge-dev`, `msedge-canary`.
+
+When `--session` is not provided, the session is named after the channel (e.g. `--cdp=msedge` creates a session called `msedge`), so parallel attaches to Chrome and Edge don't collide on `default`. Pass `--session= for toggle block HTML export ([#2524](https://github.com/TypeCellOS/BlockNote/pull/2524))
+- remove @hocuspocus/provider peer dependency by inlining tiptap comment types BLO-1064 ([#2564](https://github.com/TypeCellOS/BlockNote/pull/2564))
+- **core:** slash menu fails in custom blocks after space BLO-1036 ([#2553](https://github.com/TypeCellOS/BlockNote/pull/2553))
+- **i18n:** fix typo in russian translation ([#2560](https://github.com/TypeCellOS/BlockNote/pull/2560))
+
+### ❤️ Thank You
+
+- Claude Opus 4.6
+- Drone
+- Yousef
+
+## 0.47.1 (2026-03-02)
+
+### 🩹 Fixes
+
+- typeerror cannot read properties of undefined ([#2522](https://github.com/TypeCellOS/BlockNote/pull/2522))
+- handle more delete key cases ([#2126](https://github.com/TypeCellOS/BlockNote/pull/2126))
+- add delay for `data-active` in collab cursors ([#2383](https://github.com/TypeCellOS/BlockNote/pull/2383))
+- disable slash menu in table content #2408 ([#2504](https://github.com/TypeCellOS/BlockNote/pull/2504), [#2408](https://github.com/TypeCellOS/BlockNote/issues/2408))
+- **ai:** selections broken due to floating-ui focus manager ([#2527](https://github.com/TypeCellOS/BlockNote/pull/2527))
+
+### ❤️ Thank You
+
+- Matthew Lipski @matthewlipski
+- Nick Perez
+- Yousef
+
+## 0.47.0 (2026-02-23)
+
+### 🚀 Features
+
+- update suggestion menu component ([#2397](https://github.com/TypeCellOS/BlockNote/pull/2397))
+- **i18n:** add Persian (fa) localization support ([#2447](https://github.com/TypeCellOS/BlockNote/pull/2447))
+- **i18n:** add Uzbek (uz) localization support ([#2506](https://github.com/TypeCellOS/BlockNote/pull/2506))
+
+### 🩹 Fixes
+
+- prevent nested bullet list icon rendering as emoji on iOS 18+ ([#2394](https://github.com/TypeCellOS/BlockNote/pull/2394), [#2399](https://github.com/TypeCellOS/BlockNote/pull/2399))
+- ignore drag & drop from unrelated events #1968 ([#2346](https://github.com/TypeCellOS/BlockNote/pull/2346), [#1968](https://github.com/TypeCellOS/BlockNote/issues/1968))
+- disable checkbox when editor is not editable #2406 ([#2448](https://github.com/TypeCellOS/BlockNote/pull/2448), [#2406](https://github.com/TypeCellOS/BlockNote/issues/2406))
+- Backspace/enter behaviour in empty block with children ([#2451](https://github.com/TypeCellOS/BlockNote/pull/2451))
+- handle pasting into table cells better, by collapsing their content to inline #2410 ([#2449](https://github.com/TypeCellOS/BlockNote/pull/2449), [#2410](https://github.com/TypeCellOS/BlockNote/issues/2410))
+- **accessibility:** ai combobox aria-activedescendant ([#2413](https://github.com/TypeCellOS/BlockNote/pull/2413))
+- **ai:** no more scrolling to top when opening AI menu ([#2503](https://github.com/TypeCellOS/BlockNote/pull/2503))
+- **docs:** unicode char not rendered in bug template ([f13e270be](https://github.com/TypeCellOS/BlockNote/commit/f13e270be))
+
+### ❤️ Thank You
+
+- Cyril G @Ovgodd
+- Dex Devlon @bxff
+- Matthew Lipski @matthewlipski
+- MDSAM05 @MDSAM05
+- Mohammad RAHMANI @Mrahmani71
+- Nick Perez
+- Ogabek @OgabekYuldoshev
+- Wouter Vroege
+- Yousef
+
+## 0.46.2 (2026-01-27)
+
+### 🩹 Fixes
+
+- deep merge floatingUIOptions using nested spread operators ([#2310](https://github.com/TypeCellOS/BlockNote/pull/2310))
+- Visual differences between live editor and rendered exported HTML ([#2348](https://github.com/TypeCellOS/BlockNote/pull/2348))
+- `BlockNoteViewEditor` mismatched editable value ([#2357](https://github.com/TypeCellOS/BlockNote/pull/2357))
+- add `font-synthesis` for italic & bold in fonts that don't have them specified #2325 ([#2354](https://github.com/TypeCellOS/BlockNote/pull/2354), [#2325](https://github.com/TypeCellOS/BlockNote/issues/2325))
+- disable code block language selector when editor is not editable ([#2351](https://github.com/TypeCellOS/BlockNote/pull/2351))
+- table handles would crash ([#2384](https://github.com/TypeCellOS/BlockNote/pull/2384))
+- update CreateLinkButton to be able to toggle popover visibility ([#2316](https://github.com/TypeCellOS/BlockNote/pull/2316), [#2313](https://github.com/TypeCellOS/BlockNote/issues/2313))
+- add context,nestingLevel to toExternalHTML ([#2373](https://github.com/TypeCellOS/BlockNote/pull/2373))
+- **ai:** re-enable flipping the AIMenu when there is not enough space #2245 ([#2247](https://github.com/TypeCellOS/BlockNote/pull/2247), [#2245](https://github.com/TypeCellOS/BlockNote/issues/2245))
+- **link-toolbar:** prevent Enter from submitting during IME composition ([#2361](https://github.com/TypeCellOS/BlockNote/pull/2361))
+
+### ❤️ Thank You
+
+- hanios123
+- Jean-Baptiste PENRATH
+- Matthew Lipski @matthewlipski
+- Nick Perez
+- Shohei Yoshida @ysds
+- Yousef
+
+## 0.46.1 (2026-01-10)
+
+This was a version bump only, there were no code changes.
+
+## 0.46.0 (2026-01-08)
+
+### 🚀 Features
+
+- add data-nesting-level to HTML export ([#2329](https://github.com/TypeCellOS/BlockNote/pull/2329))
+- migrate to ai sdk 6 ([#2328](https://github.com/TypeCellOS/BlockNote/pull/2328))
+
+### 🩹 Fixes
+
+- emojipicker can sometimes fail to mount ([575b81cec](https://github.com/TypeCellOS/BlockNote/commit/575b81cec))
+- LinkToolbar Event Listener leak ([#2335](https://github.com/TypeCellOS/BlockNote/pull/2335))
+- when you convert a block into checkListItem via inputRule, it should transfer its content into checkListItem content ([#2331](https://github.com/TypeCellOS/BlockNote/pull/2331))
+- do not return focus back to menu ([484d7da36](https://github.com/TypeCellOS/BlockNote/commit/484d7da36))
+- arrow up on a checklist item should move to the element above BLO-362 ([#2306](https://github.com/TypeCellOS/BlockNote/pull/2306))
+- getPos race condition in React StrictMode ([#2311](https://github.com/TypeCellOS/BlockNote/pull/2311))
+- adjust input rules to be more tolerant to starting whitespace ([#2341](https://github.com/TypeCellOS/BlockNote/pull/2341))
+- **ai:** make sure ShowSelection works ([#2297](https://github.com/TypeCellOS/BlockNote/pull/2297))
+- **xl-email-exporter:** remove redundant sections in email export ([#2323](https://github.com/TypeCellOS/BlockNote/pull/2323))
+
+### ❤️ Thank You
+
+- Nick Perez
+- Nick the Sick @nperez0111
+- supernova @tmpluto
+- Yousef
+
+## 0.45.0 (2025-12-17)
+
+### 🚀 Features
+
+- **ai:** expand selections to contain words ([#2304](https://github.com/TypeCellOS/BlockNote/pull/2304))
+- **extensions:** extensions can now include other extensions for grouping into one extension ([#2284](https://github.com/TypeCellOS/BlockNote/pull/2284))
+
+### 🩹 Fixes
+
+- an invalidly specified table should not crash the editor ([#2255](https://github.com/TypeCellOS/BlockNote/pull/2255))
+- filter out invalid heading items based on the current block schema in the slash menu #2253 ([#2259](https://github.com/TypeCellOS/BlockNote/pull/2259), [#2253](https://github.com/TypeCellOS/BlockNote/issues/2253))
+- relax shiki package requirements #2279 ([#2280](https://github.com/TypeCellOS/BlockNote/pull/2280), [#2279](https://github.com/TypeCellOS/BlockNote/issues/2279))
+- filter the default tiptap extensions #2282 ([#2283](https://github.com/TypeCellOS/BlockNote/pull/2283), [#2282](https://github.com/TypeCellOS/BlockNote/issues/2282))
+- always include the cursor extension #2244 ([#2260](https://github.com/TypeCellOS/BlockNote/pull/2260), [#2244](https://github.com/TypeCellOS/BlockNote/issues/2244))
+- make `onBeforeChange` return the correct type again ([9009369b1](https://github.com/TypeCellOS/BlockNote/commit/9009369b1))
+- if there is no table block, there is no table handles to show #1055 ([#2281](https://github.com/TypeCellOS/BlockNote/pull/2281), [#1055](https://github.com/TypeCellOS/BlockNote/issues/1055))
+- pass dragHandleMenu prop to DragHandleButton ([#2254](https://github.com/TypeCellOS/BlockNote/pull/2254))
+- html diff error with whitespace ([#2230](https://github.com/TypeCellOS/BlockNote/pull/2230))
+- update regex for checklist items #2288 ([#2305](https://github.com/TypeCellOS/BlockNote/pull/2305), [#2288](https://github.com/TypeCellOS/BlockNote/issues/2288))
+- **email-exporter:** ReadableByteStreamController for safari react-email ([#2295](https://github.com/TypeCellOS/BlockNote/pull/2295))
+
+### ❤️ Thank You
+
+- Max @maqen
+- Nick Perez
+- Nick the Sick @nperez0111
+- Yousef
+
+## 0.44.2 (2025-12-09)
+
+### 🩹 Fixes
+
+- put back `onBeforeChange` method #2221 ([#2243](https://github.com/TypeCellOS/BlockNote/pull/2243), [#2221](https://github.com/TypeCellOS/BlockNote/issues/2221))
+- Improper accessing of editor DOM element ([#2234](https://github.com/TypeCellOS/BlockNote/pull/2234))
+- make validation errors recoverable by llm ([#2054](https://github.com/TypeCellOS/BlockNote/pull/2054))
+- shadowdom support and example ([#2223](https://github.com/TypeCellOS/BlockNote/pull/2223))
+- ensure numbered list start property always present ([#2241](https://github.com/TypeCellOS/BlockNote/pull/2241), [#2242](https://github.com/TypeCellOS/BlockNote/pull/2242))
+- Suggestion menu positioning ([#2232](https://github.com/TypeCellOS/BlockNote/pull/2232))
+- conditionally access the TableHandles extension from React ([#2248](https://github.com/TypeCellOS/BlockNote/pull/2248))
+- **ai:** upgrade prosemirror-suggest-changes ([#2235](https://github.com/TypeCellOS/BlockNote/pull/2235))
+
+### ❤️ Thank You
+
+- Matthew Lipski @matthewlipski
+- Nick Perez
+- wcyat @sdip15fa
+- Yousef
+
+## 0.44.1 (2025-12-08)
+
+### 🩹 Fixes
+
+- clearing selection was not being called when create link button is no longer rendered ([#2217](https://github.com/TypeCellOS/BlockNote/pull/2217))
+- AI menu not updating position on new line ([#2233](https://github.com/TypeCellOS/BlockNote/pull/2233))
+- UI elements not scrolling when editor DOM element is scrollable ([#2231](https://github.com/TypeCellOS/BlockNote/pull/2231))
+
+### ❤️ Thank You
+
+- Matthew Lipski @matthewlipski
+
+## 0.44.0 (2025-12-02)
+
+### 🚀 Features
+
+- **ai:** Abort requests ([#2213](https://github.com/TypeCellOS/BlockNote/pull/2213))
+
+### ❤️ Thank You
+
+- Yousef
+
+## 0.43.0 (2025-12-01)
+
+### 🚀 Features
+
+- Major Extensions & UI Refactor ([#2143](https://github.com/TypeCellOS/BlockNote/pull/2143))
+
+### 🩹 Fixes
+
+- allow configuring the email body's styles ([#2182](https://github.com/TypeCellOS/BlockNote/pull/2182))
+- **xl-docx-exporter:** improve OOXML interoperability ([#2206](https://github.com/TypeCellOS/BlockNote/pull/2206))
+
+### ❤️ Thank You
+
+- Nick Perez
+- Stephan Meijer @StephanMeijer
+
+## 0.42.3 (2025-11-19)
+
+### 🩹 Fixes
+
+- disallow access to the `domElement` or `isFocused` if the editor is unmounted ([#2187](https://github.com/TypeCellOS/BlockNote/pull/2187))
+
+### ❤️ Thank You
+
+- Nick Perez
+
+## 0.42.2 (2025-11-19)
+
+### 🩹 Fixes
+
+- put back mounting system ([#2183](https://github.com/TypeCellOS/BlockNote/pull/2183))
+
+### ❤️ Thank You
+
+- Nick Perez
+
+## 0.42.1 (2025-11-18)
+
+### 🩹 Fixes
+
+- do not error on invalid `backgroundColor` or `textColor` #2176 ([#2179](https://github.com/TypeCellOS/BlockNote/pull/2179), [#2176](https://github.com/TypeCellOS/BlockNote/issues/2176))
+- remove dependency array from comments re-rendering ([#2177](https://github.com/TypeCellOS/BlockNote/pull/2177))
+
+### ❤️ Thank You
+
+- Nick Perez
+
+## 0.42.0 (2025-11-11)
+
+### 🚀 Features
+
+- **yjs:** expose Y.js BlockNote conversion primitives #1866 ([#2166](https://github.com/TypeCellOS/BlockNote/pull/2166), [#1866](https://github.com/TypeCellOS/BlockNote/issues/1866))
+
+### 🩹 Fixes
+
+- Emoji picker issues ([#2092](https://github.com/TypeCellOS/BlockNote/pull/2092))
+- set a default for `blocksToFullHTML` #2100 ([#2101](https://github.com/TypeCellOS/BlockNote/pull/2101), [#2100](https://github.com/TypeCellOS/BlockNote/issues/2100))
+- correctly index blocks that have children fixes #2115 ([#2116](https://github.com/TypeCellOS/BlockNote/pull/2116), [#2115](https://github.com/TypeCellOS/BlockNote/issues/2115))
+- add more lenient parsing for code blocks, to accept newlines #2105 ([#2108](https://github.com/TypeCellOS/BlockNote/pull/2108), [#2105](https://github.com/TypeCellOS/BlockNote/issues/2105))
+- Firefox invisible text cursor after dropping blocks ([#2128](https://github.com/TypeCellOS/BlockNote/pull/2128))
+- parsing `priority` for custom inline content and styles ([#2119](https://github.com/TypeCellOS/BlockNote/pull/2119))
+- `BlockTypeSelect` item filtering based on schema ([#2112](https://github.com/TypeCellOS/BlockNote/pull/2112))
+- deleting last block in column ([#2110](https://github.com/TypeCellOS/BlockNote/pull/2110))
+- **comments:** update the styles for the cursor to be the default cursor ([#2163](https://github.com/TypeCellOS/BlockNote/pull/2163))
+- **comments:** always surface the closest mark to the current position ([#2164](https://github.com/TypeCellOS/BlockNote/pull/2164))
+- **comments:** scrolling bug when clicking comment marks ([#2165](https://github.com/TypeCellOS/BlockNote/pull/2165))
+- **react:** destroy editor instances after two ticks ([#2121](https://github.com/TypeCellOS/BlockNote/pull/2121))
+- **schema-migration:** more robust migration of background-color & text-color attributes ([#2154](https://github.com/TypeCellOS/BlockNote/pull/2154))
+- **unique-id:** do not attempt to append to y-sync plugin transactions ([#2153](https://github.com/TypeCellOS/BlockNote/pull/2153))
+
+### ❤️ Thank You
+
+- Matthew Lipski @matthewlipski
+- Nick Perez
+
+## 0.41.1 (2025-10-09)
+
+This was a version bump only, there were no code changes.
+
+## 0.41.0 (2025-10-08)
+
+### 🚀 Features
+
+- AI menu auto scrolling ([#2039](https://github.com/TypeCellOS/BlockNote/pull/2039))
+- Shortcut to delete empty table while cells are selected ([#2052](https://github.com/TypeCellOS/BlockNote/pull/2052))
+- **divider:** add a divider block ([#2014](https://github.com/TypeCellOS/BlockNote/pull/2014))
+
+### 🩹 Fixes
+
+- Code block language select value not updating properly ([#2050](https://github.com/TypeCellOS/BlockNote/pull/2050))
+- disable input rules for numbered headings #1789 ([#2032](https://github.com/TypeCellOS/BlockNote/pull/2032), [#1789](https://github.com/TypeCellOS/BlockNote/issues/1789))
+- video parsing and export for markdown ([#1955](https://github.com/TypeCellOS/BlockNote/pull/1955))
+- Reaction picker shown for users who can't react ([#2061](https://github.com/TypeCellOS/BlockNote/pull/2061))
+- Add Mantine dependency to individual examples ([#2070](https://github.com/TypeCellOS/BlockNote/pull/2070))
+- allow listening to `onChange` and other events before the underlying editor is initialized ([#2063](https://github.com/TypeCellOS/BlockNote/pull/2063))
+- toggle and check list item blocks ([#2071](https://github.com/TypeCellOS/BlockNote/pull/2071))
+- added missing fields to implementations in editor schema block specs ([#2046](https://github.com/TypeCellOS/BlockNote/pull/2046))
+
+### ❤️ Thank You
+
+- Héctor Zhuang @Hector-Zhuang
+- Matthew Lipski @matthewlipski
+- Nick Perez
+
+## 0.40.0 (2025-09-30)
+
+### 🚀 Features
+
+- Mantine v8 upgrade ([#2028](https://github.com/TypeCellOS/BlockNote/pull/2028), [#2029](https://github.com/TypeCellOS/BlockNote/issues/2029))
+- Update Mantine setup ([#2033](https://github.com/TypeCellOS/BlockNote/pull/2033))
+- **ai:** SDK 5, tool calling, custom backends ([#2007](https://github.com/TypeCellOS/BlockNote/pull/2007))
+- **core:** add the ability to autofocus on the editor element ([#2018](https://github.com/TypeCellOS/BlockNote/pull/2018))
+
+### 🩹 Fixes
+
+- Block colors menu not always showing ([#2027](https://github.com/TypeCellOS/BlockNote/pull/2027))
+- Update remianing examples to Mantine v8 ([#2031](https://github.com/TypeCellOS/BlockNote/pull/2031))
+- ShadCN example Tailwind setup ([#2042](https://github.com/TypeCellOS/BlockNote/pull/2042))
+
+### ❤️ Thank You
+
+- Matthew Lipski @matthewlipski
+- Nick Perez
+- Yousef
+
+## 0.39.1 (2025-09-19)
+
+### 🩹 Fixes
+
+- cleanup accesses to prosemirrorView to account for tiptap 3 behavior ([#2017](https://github.com/TypeCellOS/BlockNote/pull/2017))
+- **core:** input rules can handle when a new block is empty now ([#2013](https://github.com/TypeCellOS/BlockNote/pull/2013))
+
+### ❤️ Thank You
+
+- Nick Perez
+
+## 0.39.0 (2025-09-18)
+
+### 🚀 Features
+
+- move all blocks to use the custom blocks API ([#1904](https://github.com/TypeCellOS/BlockNote/pull/1904))
+- **core:** support for Tiptap V3 ([#2001](https://github.com/TypeCellOS/BlockNote/pull/2001))
+
+### ❤️ Thank You
+
+- Nick Perez
+
+## 0.38.0 (2025-09-16)
+
+### 🚀 Features
+
+- Custom schemas for comment editors ([#1976](https://github.com/TypeCellOS/BlockNote/pull/1976))
+
+### 🩹 Fixes
+
+- Suggestion menu positioning ([#1975](https://github.com/TypeCellOS/BlockNote/pull/1975))
+- doLLMRequest fails when deleting a non-existent block ([#1982](https://github.com/TypeCellOS/BlockNote/pull/1982))
+- file block resize handles not working with touch inputs ([#1981](https://github.com/TypeCellOS/BlockNote/pull/1981))
+- get pdf example working again ([a90ae4d58](https://github.com/TypeCellOS/BlockNote/commit/a90ae4d58))
+- better markdown & html paste, make methods synchronous ([#1957](https://github.com/TypeCellOS/BlockNote/pull/1957))
+- Improve setting text for custom file blocks ([#1984](https://github.com/TypeCellOS/BlockNote/pull/1984))
+- **react:** close link popover on submit in static formatting toolbar #1696 ([#1997](https://github.com/TypeCellOS/BlockNote/pull/1997), [#1696](https://github.com/TypeCellOS/BlockNote/issues/1696))
+
+### ❤️ Thank You
+
+- dsriva03 @dsriva03
+- Héctor Zhuang @Hector-Zhuang
+- Matthew Lipski @matthewlipski
+- Nick the Sick
+
+## 0.37.0 (2025-08-29)
+
+### 🚀 Features
+
+- export `ShadCNComponentsContext` ([#1965](https://github.com/TypeCellOS/BlockNote/pull/1965))
+
+### 🩹 Fixes
+
+- Typing in empty table cells ([#1973](https://github.com/TypeCellOS/BlockNote/pull/1973))
+
+### ❤️ Thank You
+
+- Héctor Zhuang @Hector-Zhuang
+- Matthew Lipski @matthewlipski
+
+## 0.36.1 (2025-08-27)
+
+### 🩹 Fixes
+
+- table column widths not being set in exported HTML ([#1947](https://github.com/TypeCellOS/BlockNote/pull/1947))
+- Minor change to formatting toolbar extension logic ([#1963](https://github.com/TypeCellOS/BlockNote/pull/1963))
+- **core:** report block moves in `getBlocksChangedByTransaction` #1924 ([#1960](https://github.com/TypeCellOS/BlockNote/pull/1960), [#1924](https://github.com/TypeCellOS/BlockNote/issues/1924))
+
+### ❤️ Thank You
+
+- Matthew Lipski @matthewlipski
+- Nick Perez
+
+## 0.36.0 (2025-08-25)
+
+### 🚀 Features
+
+- **docx:** add locale configuration for docx export ([#1937](https://github.com/TypeCellOS/BlockNote/pull/1937))
+
+### 🩹 Fixes
+
+- Editors in comments not inheriting theme ([#1890](https://github.com/TypeCellOS/BlockNote/pull/1890))
+- Minor drag & drop changes ([#1891](https://github.com/TypeCellOS/BlockNote/pull/1891))
+- Overflow on table blocks ([#1892](https://github.com/TypeCellOS/BlockNote/pull/1892))
+- Suggestion menu closing when clicking scroll bar ([#1899](https://github.com/TypeCellOS/BlockNote/pull/1899))
+- Table padding ([#1906](https://github.com/TypeCellOS/BlockNote/pull/1906))
+- Formatting toolbar getting wrong bounding box when updating React inline content ([#1908](https://github.com/TypeCellOS/BlockNote/pull/1908))
+- Vanilla blocks return true for editor.isEditable on initial render ([#1925](https://github.com/TypeCellOS/BlockNote/pull/1925))
+- table cell menu styling ([#1945](https://github.com/TypeCellOS/BlockNote/pull/1945))
+- Missing internationalization for toggle wrapper ([#1946](https://github.com/TypeCellOS/BlockNote/pull/1946))
+- parse image alt text for image blocks ([#1883](https://github.com/TypeCellOS/BlockNote/pull/1883))
+- initialize esm deps before copy extension uses it ([#1951](https://github.com/TypeCellOS/BlockNote/pull/1951))
+- error when dragging a block from one editor to another with multiple column extension ([#1950](https://github.com/TypeCellOS/BlockNote/pull/1950))
+- prevent infinite render loop when selecting all content ([#1956](https://github.com/TypeCellOS/BlockNote/pull/1956))
+- **core:** maintain text selection across table updates ([#1894](https://github.com/TypeCellOS/BlockNote/pull/1894))
+- **locales:** ko locale fix ([#1902](https://github.com/TypeCellOS/BlockNote/pull/1902))
+- **react:** add data attribute for correct react rendering ([#1954](https://github.com/TypeCellOS/BlockNote/pull/1954))
+- **xl-email-exporter:** better defaults, customize textStyles, output inline styles ([#1856](https://github.com/TypeCellOS/BlockNote/pull/1856))
+
+### ❤️ Thank You
+
+- Brad Greenlee
+- Cyril G @Ovgodd
+- Héctor Zhuang @Hector-Zhuang
+- Matthew Lipski @matthewlipski
+- Nick Perez
+- Nick the Sick
+
+## 0.35.0 (2025-07-25)
+
+### 🚀 Features
+
+- use fumadocs for website ([#1654](https://github.com/TypeCellOS/BlockNote/pull/1654))
+- llms.mdx routes ([cea93840e](https://github.com/TypeCellOS/BlockNote/commit/cea93840e))
+
+### 🩹 Fixes
+
+- insert file upload before block if it is closer to the top of the block ([#1857](https://github.com/TypeCellOS/BlockNote/pull/1857))
+- rename albert model ([3b0ba8d25](https://github.com/TypeCellOS/BlockNote/commit/3b0ba8d25))
+- resolve some minor drag & drop regressions ([#1862](https://github.com/TypeCellOS/BlockNote/pull/1862))
+- blockquote HTML parsing #1762 ([#1877](https://github.com/TypeCellOS/BlockNote/pull/1877), [#1762](https://github.com/TypeCellOS/BlockNote/issues/1762))
+
+### ❤️ Thank You
+
+- Brad Greenlee
+- Nick Perez
+- Nick the Sick
+- yousefed
+
+## 0.34.0 (2025-07-17)
+
+### 🚀 Features
+
+- support multi-column block in PDF, DOCX & ODT exporters ([#1781](https://github.com/TypeCellOS/BlockNote/pull/1781))
+- support react 19 ([f7b3466d3](https://github.com/TypeCellOS/BlockNote/commit/f7b3466d3))
+- disable conversion of headings to list items ([#1799](https://github.com/TypeCellOS/BlockNote/pull/1799))
+- report `moves` (indents and outdents) as changes when using `getChanges` #1757 ([#1786](https://github.com/TypeCellOS/BlockNote/pull/1786), [#1757](https://github.com/TypeCellOS/BlockNote/issues/1757))
+- allow inline content to be `draggable` ([#1818](https://github.com/TypeCellOS/BlockNote/pull/1818))
+- added type guards, types, and `editor` prop to custom inline content rendering ([#1736](https://github.com/TypeCellOS/BlockNote/pull/1736))
+- **block-change:** adds a new API for blocking changes to editor state, by filtering transactions ([#1750](https://github.com/TypeCellOS/BlockNote/pull/1750))
+
+### 🩹 Fixes
+
+- remove lookbehind regex for browser compat ([#1827](https://github.com/TypeCellOS/BlockNote/pull/1827))
+- `ToggleWrapper` button defaulting to `submit` type ([#1823](https://github.com/TypeCellOS/BlockNote/pull/1823))
+- disable $ref in AI schemas (html format) ([#1819](https://github.com/TypeCellOS/BlockNote/pull/1819))
+- re-evaluate side-menu on scroll ([#1830](https://github.com/TypeCellOS/BlockNote/pull/1830))
+- hide table extend buttons when not editable #1848 ([#1850](https://github.com/TypeCellOS/BlockNote/pull/1850), [#1848](https://github.com/TypeCellOS/BlockNote/issues/1848))
+- resolve several drag & drop issues ([#1845](https://github.com/TypeCellOS/BlockNote/pull/1845))
+
+### ❤️ Thank You
+
+- Arek Nawo @areknawo
+- Gonçalo Basto @gbasto
+- Héctor Zhuang @Hector-Zhuang
+- Matthew Lipski @matthewlipski
+- Nick Perez
+- Nick the Sick @nperez0111
+- Yousef
+
+## 0.33.0 (2025-07-03)
+
+### 🚀 Features
+
+- FloatingUI options prop for `BlockPositioner` ([#1801](https://github.com/TypeCellOS/BlockNote/pull/1801))
+- Support Google Gemini AI ([#1805](https://github.com/TypeCellOS/BlockNote/pull/1805))
+
+### 🩹 Fixes
+
+- support multi-character suggestions ([#1734](https://github.com/TypeCellOS/BlockNote/pull/1734))
+- switch foreground color based on selected user color dynamically #1785 ([#1787](https://github.com/TypeCellOS/BlockNote/pull/1787), [#1785](https://github.com/TypeCellOS/BlockNote/issues/1785))
+- mark react package as external in email exporter ([#1807](https://github.com/TypeCellOS/BlockNote/pull/1807))
+- Duplicate `formatConversionTest` files ([#1798](https://github.com/TypeCellOS/BlockNote/pull/1798))
+- AI empty document handling ([#1810](https://github.com/TypeCellOS/BlockNote/pull/1810))
+- `bn-inline-content` class name getting duplicated ([#1794](https://github.com/TypeCellOS/BlockNote/pull/1794))
+
+### ❤️ Thank You
+
+- Matthew Lipski @matthewlipski
+- Nick Perez
+- Yousef
+
+## 0.32.0 (2025-06-24)
+
+### 🚀 Features
+
+- toggle blocks ([#1707](https://github.com/TypeCellOS/BlockNote/pull/1707))
+- **core:** support h4, h5, and h6 ([#1634](https://github.com/TypeCellOS/BlockNote/pull/1634))
+- **xl-email-exporter:** add email exporter ([#1768](https://github.com/TypeCellOS/BlockNote/pull/1768))
+
+### 🩹 Fixes
+
+- react 19 strict mode compatibility ([#1726](https://github.com/TypeCellOS/BlockNote/pull/1726))
+- add keys to pdf exporter ([#1739](https://github.com/TypeCellOS/BlockNote/pull/1739))
+- only listten for left click on formatting toolbar ([#1774](https://github.com/TypeCellOS/BlockNote/pull/1774))
+- prevent formatting toolbar from closing if click was from inside the editor ([#1775](https://github.com/TypeCellOS/BlockNote/pull/1775))
+- **locales:** add Hebrew translations for various components ([#1779](https://github.com/TypeCellOS/BlockNote/pull/1779))
+
+### ❤️ Thank You
+
+- Aslam @Aslam97
+- Drew Johnson
+- Jonathan Marbutt @jmarbutt
+- Matthew Lipski @matthewlipski
+- Nick Perez
+- Samuel Bisberg
+- Yousef
+
+## 0.31.3 (2025-06-18)
+
+### 🩹 Fixes
+
+- AI generation with empty document ([#1740](https://github.com/TypeCellOS/BlockNote/pull/1740))
+- do not send a welcome email if magic link was used on an account older than a minute ago ([db88fe4aa](https://github.com/TypeCellOS/BlockNote/commit/db88fe4aa))
+- AI system messages should always be at start of prompt ([#1741](https://github.com/TypeCellOS/BlockNote/pull/1741))
+- Selection clicking editor padding ([#1717](https://github.com/TypeCellOS/BlockNote/pull/1717))
+- preserve marks across a shift+enter #1672 ([#1743](https://github.com/TypeCellOS/BlockNote/pull/1743), [#1672](https://github.com/TypeCellOS/BlockNote/issues/1672))
+- **ai:** undo-redo after accepting/rejecting changes will undo as expected ([#1752](https://github.com/TypeCellOS/BlockNote/pull/1752))
+- **locales:** add translations for some comment strings ([#1764](https://github.com/TypeCellOS/BlockNote/pull/1764))
+- **website:** log in bug fixes ([#1742](https://github.com/TypeCellOS/BlockNote/pull/1742))
+
+### ❤️ Thank You
+
+- Matthew Lipski @matthewlipski
+- Nick Perez
+- Nick the Sick
+- Vinicius Fernandes @ViniCleFer
+- Yousef
+
+## 0.31.2 (2025-06-05)
+
+### 🩹 Fixes
+
+- re-release ([0bc546e18](https://github.com/TypeCellOS/BlockNote/commit/0bc546e18))
+- ignore falsy values in boolean prop schema ([#1730](https://github.com/TypeCellOS/BlockNote/pull/1730))
+
+### ❤️ Thank You
+
+- Nick Perez
+- Nick the Sick
+
+## 0.31.1 (2025-05-23)
+
+### 🩹 Fixes
+
+- backwards-compat for `_extensions` ([#1708](https://github.com/TypeCellOS/BlockNote/pull/1708))
+
+### ❤️ Thank You
+
+- Nick Perez
+
+## 0.31.0 (2025-05-20)
+
+### 🩹 Fixes
+
+- Playwright flaky keyboard handler test ([#1704](https://github.com/TypeCellOS/BlockNote/pull/1704))
+
+### ❤️ Thank You
+
+- Matthew Lipski @matthewlipski
+
+## 0.30.1 (2025-05-20)
+
+### 🩹 Fixes
+
+- better type-safety ([678086d4d](https://github.com/TypeCellOS/BlockNote/commit/678086d4d))
+- do not use `editor.dispatch` ([#1698](https://github.com/TypeCellOS/BlockNote/pull/1698))
+- re-added `display: flex` to blocks without inline content ([#1702](https://github.com/TypeCellOS/BlockNote/pull/1702))
+- **react:** add missing exports ([#1689](https://github.com/TypeCellOS/BlockNote/pull/1689))
+
+### ❤️ Thank You
+
+- Matthew Lipski @matthewlipski
+- Nick Perez
+- Nick the Sick
+
+## 0.30.0 (2025-05-09)
+
+### 🚀 Features
+
+- expose `editor.prosemirrorState` again ([#1615](https://github.com/TypeCellOS/BlockNote/pull/1615))
+- add `undo` and `redo` methods to editor API ([#1592](https://github.com/TypeCellOS/BlockNote/pull/1592))
+- new auth & payment system ([#1617](https://github.com/TypeCellOS/BlockNote/pull/1617))
+- re-implement Y.js collaboration as BlockNote plugins ([#1638](https://github.com/TypeCellOS/BlockNote/pull/1638))
+- **file:** `previewWidth` prop now defaults to `undefined` ([#1664](https://github.com/TypeCellOS/BlockNote/pull/1664))
+- **locales:** add zh-TW i18n ([#1668](https://github.com/TypeCellOS/BlockNote/pull/1668))
+
+### 🩹 Fixes
+
+- Formatting toolbar regression ([#1630](https://github.com/TypeCellOS/BlockNote/pull/1630))
+- provide `blockId` to `uploadFile` in UploadTab ([#1641](https://github.com/TypeCellOS/BlockNote/pull/1641))
+- do not close the menu on content/selection change ([#1644](https://github.com/TypeCellOS/BlockNote/pull/1644))
+- keep file panel open during collaboration ([#1646](https://github.com/TypeCellOS/BlockNote/pull/1646))
+- force pasting plain text into code block ([#1663](https://github.com/TypeCellOS/BlockNote/pull/1663))
+- updating HTML parsing rules to account for `prosemirror-model@1.25.1` ([#1661](https://github.com/TypeCellOS/BlockNote/pull/1661))
+- **code-block:** handle unknown languages better ([#1626](https://github.com/TypeCellOS/BlockNote/pull/1626))
+- **locales:** add slovak i18n ([#1649](https://github.com/TypeCellOS/BlockNote/pull/1649))
+
+### ❤️ Thank You
+
+- l0st0 @l0st0
+- Lawrence Lin @linyiru
+- Matthew Lipski @matthewlipski
+- Nick Perez
+- Quentin Nativel
+
+## 0.29.1 (2025-04-17)
+
+### 🩹 Fixes
+
+- try not to always use workspace version ([7af344ea9](https://github.com/TypeCellOS/BlockNote/commit/7af344ea9))
+
+### ❤️ Thank You
+
+- Nick the Sick
+
+## 0.29.0 (2025-04-17)
+
+### 🚀 Features
+
+- `change` event allows getting a list of the block changed ([#1585](https://github.com/TypeCellOS/BlockNote/pull/1585))
+
+### 🩹 Fixes
+
+- allow opening another suggestion menu if another is triggered #1473 ([#1591](https://github.com/TypeCellOS/BlockNote/pull/1591), [#1473](https://github.com/TypeCellOS/BlockNote/issues/1473))
+- add quote to schema ([aa16b15fe](https://github.com/TypeCellOS/BlockNote/commit/aa16b15fe))
+- update y-prosemirror to fix #1462 ([#1608](https://github.com/TypeCellOS/BlockNote/pull/1608), [#1462](https://github.com/TypeCellOS/BlockNote/issues/1462))
+- dispatch suggestion menu as a separate transaction ([#1614](https://github.com/TypeCellOS/BlockNote/pull/1614))
+
+### ❤️ Thank You
+
+- Nick Perez
+- Nick the Sick
+
+## 0.28.0 (2025-04-07)
+
+### 🚀 Features
+
+- position storage ([#1529](https://github.com/TypeCellOS/BlockNote/pull/1529))
+
+### ❤️ Thank You
+
+- Nick Perez
+
+## 0.27.2 (2025-04-05)
+
+### 🩹 Fixes
+
+- minor update for publishing ([c2820fdac](https://github.com/TypeCellOS/BlockNote/commit/c2820fdac))
+
+### ❤️ Thank You
+
+- Nick the Sick
+
+## 0.27.1 (2025-04-05)
+
+### 🚀 Features
+
+- **nx-cloud:** set up nx workspace ([#1586](https://github.com/TypeCellOS/BlockNote/pull/1586))
+
+### 🩹 Fixes
+
+- update packages to use correct react versions ([ea11ebce0](https://github.com/TypeCellOS/BlockNote/commit/ea11ebce0))
+
+### ❤️ Thank You
+
+- Nick Perez
+- Nick the Sick
+
+## 0.27.0 (2025-04-04)
+
+### 🚀 Features
+
+- split out localization files for optimized bundle ([#1533](https://github.com/TypeCellOS/BlockNote/pull/1533))
+- remove shiki dep, add new @blocknote/code-block package for slim shiki build ([#1519](https://github.com/TypeCellOS/BlockNote/pull/1519))
+- Block quote ([#1563](https://github.com/TypeCellOS/BlockNote/pull/1563))
+- markdown pasting & custom paste handlers ([#1490](https://github.com/TypeCellOS/BlockNote/pull/1490))
+
+### 🩹 Fixes
+
+- Backspace in empty block deletes previous block ([#1505](https://github.com/TypeCellOS/BlockNote/pull/1505))
+- Selection when clicking past end of inline content ([#1553](https://github.com/TypeCellOS/BlockNote/pull/1553))
+- better expose setting a draghandlemenu's items #1525 ([#1526](https://github.com/TypeCellOS/BlockNote/pull/1526), [#1525](https://github.com/TypeCellOS/BlockNote/issues/1525))
+- Multi-block links ([#1565](https://github.com/TypeCellOS/BlockNote/pull/1565))
+- Hard break keyboard shortcut not working in custom blocks ([#1554](https://github.com/TypeCellOS/BlockNote/pull/1554))
+- Overlapping marks in comments ([#1564](https://github.com/TypeCellOS/BlockNote/pull/1564))
+- some more sentry fixes ([#1577](https://github.com/TypeCellOS/BlockNote/pull/1577))
+
+### ❤️ Thank You
+
+- Martinrsts @Martinrsts
+- Matthew Lipski @matthewlipski
+- Nick Perez
+
+## Previous Versions
+
+See [Github Releases](https://github.com/TypeCellOS/BlockNote/releases) for previous versions.
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 120000
index 0000000000..47dc3e3d86
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1 @@
+AGENTS.md
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 9159700782..a2e0099d73 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -23,26 +23,65 @@ An introduction into the BlockNote Prosemirror schema can be found in [packages/
To run the project, open the command line in the project's root directory and enter the following commands:
- # Install all required npm modules for lerna, and bootstrap lerna packages
- npm install
- npm run bootstrap
+```bash
+# Install all required npm modules
+pnpm install
- # Start the example project
- npm start
+# Start the example project
+pnpm start
+```
## Adding packages
- Add the dependency to the relevant `package.json` file (packages/xxx/package.json)
-- run `npm run install-new-packages`
-- Double check `package-lock.json` to make sure only the relevant packages have been affected
+- Double check `pnpm-lock.yaml` to make sure only the relevant packages have been affected
-## Packages:
+## Packages
| Package | Size | Version |
-|--------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|
+| ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| [@blocknote/core](https://github.com/TypeCellOS/BlockNote/tree/main/packages/core) |
|
|
| [@blocknote/react](https://github.com/TypeCellOS/BlockNote/tree/main/packages/react) |
|
|
| [@blocknote/ariakit](https://github.com/TypeCellOS/BlockNote/tree/main/packages/ariakit) |
|
|
| [@blocknote/mantine](https://github.com/TypeCellOS/BlockNote/tree/main/packages/mantine) |
|
|
| [@blocknote/shadcn](https://github.com/TypeCellOS/BlockNote/tree/main/packages/shadcn) |
|
|
| [@blocknote/server-util](https://github.com/TypeCellOS/BlockNote/tree/main/packages/server-util) |
|
|
+
+## Releasing
+
+This diagram illustrates the release workflow for the BlockNote monorepo.
+
+
+
+Essentially, when the maintainers have decided to release a new version of BlockNote, they will:
+
+1. Check that the `main` branch is in a releasable state:
+ - CI status of main branch is green
+ - Builds are passing
+2. Bump the package versions using the `pnpm run deploy` command. This command will:
+ 1. Based on semantic versioning, determine the next version number.
+ 2. Apply the new version number to all publishable packages within the monorepo.
+ 3. Generate a changelog for the new version.
+ 4. Commit the changes to the `main` branch.
+ 5. Create a new git tag for the new version.
+ 6. Push the changes to the `origin` remote.
+ 7. Create a new GitHub Release with the same name as the new version.
+ 8. Trigger a release workflow.
+
+The release workflow will:
+
+1. Checkout the `main` branch.
+2. Install the dependencies.
+3. Build the project.
+4. Login to npm.
+5. Publish the packages to npm.
+
+### Publishing a new package
+
+From time to time, you may need to publish a new package to npm. To do this, you cannot just deploy the package to npm, you need to:
+
+1. Run `nx release version --dry-run` and check that the version number is correct for the package.
+ - Once this is done, you can run `nx release version` to actually apply the version bump locally (staged to your local git repo).
+2. Run `nx release changelog --from
Homepage
- -
+ -
Documentation
- -
+ -
Quickstart
-
Examples
@@ -48,8 +44,6 @@ function App() {
`@blocknote/react` comes with a fully styled UI that makes it an instant, polished editor ready to use in your app.
-If you prefer to create your own UI components (menus), or don't want to use React, you can use `@blocknote/core` (_advanced_, [see docs](https://www.blocknotejs.org/docs/vanilla-js)).
-
# Features
BlockNote comes with a number of features and components to make it easy to embed a high-quality block-based editor in your app:
@@ -84,31 +78,19 @@ BlockNote comes with a number of features and components to make it easy to embe
# Feedback 🙋♂️🙋♀️
-We'd love to hear your thoughts and see your experiments, so [come and say hi on Discord](https://discord.gg/Qc2QTTH5dF) or [Matrix](https://matrix.to/#/#typecell-space:matrix.org).
+We'd love to hear your thoughts and see your experiments, so [come and say hi on Discord](https://discord.gg/Qc2QTTH5dF).
# Contributing 🙌
-See [CONTRIBUTING.md](CONTRIBUTING.md) for more info and guidance on how to run the project (TLDR: just use `npm start`).
-
-Directory structure:
-
-```
-blocknote
-├── packages/core - The core of the editor
-├── packages/react - The main library for use in React apps
-├── packages/mantine - Mantine (default) implementation of BlockNote UI
-├── packages/ariakit - AriaKit implementation of BlockNote UI
-├── packages/shadcn - ShadCN / Tailwind / Radix implementation of BlockNote UI
-├── examples - Example apps
-├── playground - App to browse the example apps (https://playground.blocknotejs.org)
-└── tests - Playwright end to end tests
-```
+See [CONTRIBUTING.md](CONTRIBUTING.md) for more info and guidance on how to run the project (TLDR: just use `pnpm start`).
The codebase is automatically tested using Vitest and Playwright.
# License 📃
-BlockNote is licensed under the [MPL 2.0 license](https://fossa.com/blog/open-source-software-licenses-101-mozilla-public-license-2-0/), which allows you to use BlockNote in commercial (and closed-source) applications. If you make changes to the BlockNote source files, you're expected to publish these changes so the wider community can benefit as well.
+BlockNote is 100% Open Source Software. The majority of BlockNote is licensed under the [MPL-2.0 license](LICENSE-MPL.txt), which allows you to use BlockNote in commercial (and closed-source) applications. If you make changes to the BlockNote source files, you're expected to publish these changes so the wider community can benefit as well. [Learn more](https://fossa.com/blog/open-source-software-licenses-101-mozilla-public-license-2-0/).
+
+The XL packages (source code in the `packages/xl-*` directories and published in NPM as `@blocknote/xl-*`) are licensed under the GPL-3.0. If you cannot comply with this license and want to use the XL libraries, you'll need a commercial license. Refer to [our website](https://www.blocknotejs.org/pricing) for more information.
# Credits ❤️
diff --git a/docs/.env.local.example b/docs/.env.local.example
index c0f2a490a6..a2dba36b4b 100644
--- a/docs/.env.local.example
+++ b/docs/.env.local.example
@@ -1,4 +1,35 @@
AUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.vercel.app/32
-AUTH_GITHUB_ID=
-AUTH_GITHUB_SECRET=
\ No newline at end of file
+# Better Auth Deployed URL
+BETTER_AUTH_URL=http://localhost:3000
+
+# ======= OPTIONAL =======
+
+# # Polar Sandbox is used in dev mode: https://sandbox.polar.sh/
+# # You may need to delete your user in their dashboard if you get a "cannot attach new external ID error"
+# POLAR_ACCESS_TOKEN=
+# POLAR_WEBHOOK_SECRET=
+
+# # In production, we use postgres
+# POSTGRES_URL=
+
+# # Email
+# SMTP_HOST=
+# SMTP_USER=
+# SMTP_PASS=
+# SMTP_PORT=
+# # Insecure if false, secure if any other value
+# SMTP_SECURE=false
+
+# # For GitHub Signin method
+# AUTH_GITHUB_ID=
+# AUTH_GITHUB_SECRET=
+
+# # The SENTRY_AUTH_TOKEN variable is picked up by the Sentry Build Plugin.
+# # It's used for authentication when uploading source maps.
+# SENTRY_AUTH_TOKEN=
+
+NEXT_PUBLIC_BLOCKNOTE_AI_SERVER_API_KEY=
+NEXT_PUBLIC_BLOCKNOTE_AI_SERVER_BASE_URL=
+
+TURNSTILE_SECRET_KEY=
\ No newline at end of file
diff --git a/docs/.eslintrc.json b/docs/.eslintrc.json
deleted file mode 100644
index 5d83a466f5..0000000000
--- a/docs/.eslintrc.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "extends": "next/core-web-vitals",
- "rules": {
- "import/extensions": 0
- }
-}
diff --git a/docs/.gitignore b/docs/.gitignore
index fd3dbb571a..c12953bff8 100644
--- a/docs/.gitignore
+++ b/docs/.gitignore
@@ -1,36 +1,32 @@
-# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
-
-# dependencies
+# deps
/node_modules
-/.pnp
-.pnp.js
-.yarn/install-state.gz
-# testing
-/coverage
+# generated content
+.source
-# next.js
+# test & build
+/coverage
/.next/
/out/
-
-# production
/build
+*.tsbuildinfo
# misc
.DS_Store
*.pem
-
-# debug
+/.pnp
+.pnp.js
npm-debug.log*
yarn-debug.log*
yarn-error.log*
-# local env files
+# others
.env*.local
-
-# vercel
.vercel
-
-# typescript
-*.tsbuildinfo
next-env.d.ts
+# Sentry Config File
+.env.sentry-build-plugin
+
+/content/examples/*/*
+/components/example/generated/
+sqlite.db
diff --git a/docs/README.md b/docs/README.md
index ec0577e219..b8e4860113 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,21 +1,105 @@
-# BlockNote Docs
+# Website Development
-This is the code for the [BlockNote documentation website](https://www.blocknotejs.org).
+This is the code for the [BlockNote documentation website](https://www.blocknotejs.org). If you're looking to work on BlockNote itself, check the [`packages`](/packages/) folder.
-If you're looking to work on BlockNote itself, check the [`packages`](/packages/) folder.
+To get started with development of the website, you can follow these steps:
-## Getting Started
+1. Initialize the DB
-First, run `npm run build` in the repository root.
+If you haven't already, you can initialize the database with the following command:
-Next, run the development server:
+```bash
+cd docs && pnpm run init-db
+```
+
+This will initialize an SQLite database at `./docs/sqlite.db`.
+
+2. Setup environment variables
+
+Copy the `.env.example` file to `.env.local` and set the environment variables.
+
+```bash
+cp .env.example .env.local
+```
+
+If you want to test logging in, or payments see more information below [in the environment variables section](#environment-variables).
+
+3. Start the development server from within the `./docs` directory.
+
+```bash
+pnpm run dev
+```
+
+This will start the development server on port 3000.
+
+## Environment Variables
+
+### Logging in
+
+To test logging in, you can set the following environment variables:
+
+```bash
+AUTH_SECRET=test
+# Github OAuth optionally
+AUTH_GITHUB_ID=test
+AUTH_GITHUB_SECRET=test
+```
+
+Note: the GITHUB_ID and GITHUB_SECRET are optional, but if you want to test logging in with Github you'll need to set them. For local development, you'll need to set the callback URL to `http://localhost:3000/api/auth/callback/github`
+
+### Payments
+
+To test payments, you can set the following environment variables:
+
+```bash
+POLAR_ACCESS_TOKEN=test
+POLAR_WEBHOOK_SECRET=test
+```
+
+For testing payments, you'll need access to the polar sandbox which needs to be configured to point a webhook to your local server. This can be configured at:
+ Every BlockNote document is a collection of blocks—headings, lists,
+ images, and more. Use the built-in blocks, customize them to fit
+ your needs, or create entirely new ones.
+
+ France, Germany, and the Netherlands partner to build{" "}
+
+ Docs
+
+ , a collaborative writing tool for thousands of public servants.{" "}
+ BlockNote is the engine.
+
+ "Building Digital Commons means better tools, data
+ sovereignty, and shared progress."
+
+ {faq.answer}
+
+ {description}
+
+ The AI-native, open source rich
+ text editor for React. Add a{" "}
+ fully customizable modern block-based editing
+ experience to your product that users will love.
+
+ Building a rich text editor is one of the hardest engineering
+ challenges on the web. It used to take months of specialized
+ work.
+
+ We believe that great tools should be{" "}
+ sovereign by default. You shouldn't have
+ to choose between a cohesive UX and owning your
+ infrastructure.
+
+ That's why we built BlockNote. A{" "}
+ batteries-included editor that gives you a
+ Notion-quality experience in minutes, while staying grounded
+ in open standards like{" "}
+
+ ProseMirror
+ {" "}
+ and Yjs.
+
+ Whether you're a startup or a public institution, you
+ deserve software that lasts. Join us to{" "}
+
+ shape the future
+
+ {" "}
+ of the open web.
+
+ Forget low-level details. Work with a strongly typed API.
+ Get modern UI components out-of-the-box.
+
+ Document editing is foundational infrastructure for the modern
+ workforce. We believe the tools we use to create and share knowledge
+ should be open, transparent, and free from lock-in. That's why
+ everything we build is open source.
+
+ {pillar.description}
+
+ "Here we could put a quote about our open source commitment."
+
+ Transparent pricing
+
+ BlockNote is 100% open source. Here's how licensing works.
+
+ The majority of BlockNote (including all blocks, real-time
+ collaboration, comments, and UI components) are liberally
+ licensed.
+
+ Free to use in any project; personal, open source, or commercial.
+
+ ✓ Free for everyone
+
+ Advanced features like AI integration,{" "}
+ PDF / Word / ODT exports, and{" "}
+ multi-column layouts.
+
+ Free for open source projects under GPL-3.0. Closed source
+ projects require a subscription.
+
+ ✓ Free for open source
+
+ {props.title}
+
+ "{testimonial.quote}"
+
+ From startups to enterprises, teams choose BlockNote to build their
+ document experiences.
+
+ BlockNote combines a premium editing experience with the flexibility
+ of open standards. Zero compromise.
+
+ Stop building rich text editors from scratch. BlockNote comes with
+ a polished, modern UI that works out of the box.
+
+ Forget low-level editor internals. We abstract away the complex
+ parts and give you a type-safe, intuitive API.
+
+
+ Upgrade
+ {" "}
+ to unlock AI support for commercial products, or partner with our
+ team for advanced integrations and support.
+
+ Try all features combined in our full-featured demo editor.
+
+ We couldn't find the page you're looking for, but here
+ are some pages that might help:
+
+ {result.url}
+
+ No similar pages found. Try searching or browsing our
+ documentation.
+
- Get started by editing
-
- Find in-depth information about Next.js features and API.
-
- Learn about Next.js in an interactive course with quizzes!
-
- Explore starter templates for Next.js.
-
- Instantly deploy your Next.js site to a shareable URL with Vercel.
-
+ Pricing
+
+ The majority of BlockNote is liberally licensed and free to use for
+ any purpose. The dual-licensed XL features (like AI) are free for
+ open source projects, but require a commercial license for
+ closed-source applications.
+
+ Trusted by teams building the future of collaboration
+
+ Building the next big thing? We love supporting early-stage
+ companies. If you're a seed-stage startup or non-profit, get in
+ touch for special pricing on our Business plan.
+
+ {tier.tagline}
+
+ ${tier.price.year.toLocaleString()} billed yearly
+
+ {tier.description}
+ {signingInState.message}
+ Build anything, block by block.
+
+
+ Three nations choose
+
+ {/* Short punchy copy */}
+
+
+ open source
+ {" "}
+ to power
+
+ their digital future.
+
+ Questions?
+
+
+ {faq.question}
+
+
+ {title}
+
+
+ Build a Notion-style{" "}
+ editor in minutes.
+
+
+ Let's build.
+
+
+ Enter BlockNote.
+
+
+ Committed to open source.
+
+ {pillar.title}
+
+
+
+ Subscribe to BlockNote XL.
+
+
+ Core Editor
+
+
+ XL Packages
+
+
+ Trusted by teams everywhere.
+
+
+ The editor you'd build, if you had the time.
+
+ {/*
+ Batteries included UX
+
+
+ Built for Developers
+
+
+ Partnerships
+
+
+ );
+ }
+
+ // Case 2: Code/Video - usually needs Chrome
+ return (
+
Whoops. What the blocks!?
+ Whoops. What the blocks!?
+
+ Try BlockNote
+
+ Whoops. What the blocks!?
+
+ Interactive Playground
+
+ Whoops. What the blocks!?
+
+ Page Not Found
+
+
+ {useFallback ? "Popular Pages" : "Similar Pages"}
+
+
+ {result.content}
+
+ app/page.tsx
-
- Docs{" "}
-
- ->
-
-
-
- Learn{" "}
-
- ->
-
-
-
- Templates{" "}
-
- ->
-
-
-
- Deploy{" "}
-
- ->
-
-
-
+ The XL packages (like AI integration, multi-column layouts, and
+ exporters) are dual-licensed and available under{" "}
+ GPL-3.0, or -
+ for closed-source projects - a commercial license as part of the
+ BlockNote Business subscription or above. See the{" "}
+
+ commercial license terms
+ {" "}
+ for the exact details.
+ >
+ ),
+ },
+ {
+ question: "When do I need a commercial license?",
+ answer: (
+ <>
+ Only when you use any of the XL packages (like AI integration,
+ multi-column layouts, and exporters) and you cannot comply with the
+ GPL-3.0 license you'll need a{" "}
+
+ commercial license
+
+ . This is likely to be the case when you're building closed-source
+ applications. The BlockNote Business subscription and above includes a
+ commercial license.
+ >
+ ),
+ },
+ {
+ question: "Why did you choose to dual-license the XL packages?",
+ answer: (
+ <>
+ We’ve built BlockNote as open source from day one and remain committed
+ to keeping the core library licensed under the MPL 2.0. That means it’s
+ free to use—even in commercial and closed-source projects.
+
+ To sustainably support ongoing development, we offer a small set of
+ advanced features (the XL packages) under a dual-license model:
+
+
+ This approach allows us to fund a full-time team while keeping 100% of
+ the code we build open source. It’s our way of balancing community
+ accessibility with long-term sustainability.
+ >
+ ),
+ },
+ {
+ question: "What kind of support is included in a license?",
+ answer: (
+ <>
+ We have you covered! All BlockNote subscriptions come with prioritized
+ support. See the{" "}
+
+ Service Level Agreement
+ {" "}
+ for the exact details.
+ >
+ ),
+ },
+ {
+ question:
+ "Is there any limit to the number of documents or users I can have?",
+ answer: `With BlockNote, there are no limits on the number of documents or users you can have.
+ You're free to run the software on your own infrastructure, and none of your data passes through our servers — your documents and users remain entirely your business.`,
+ },
+ {
+ question: "What if I have more than one SaaS or Web application?",
+ answer: (
+ <>
+ The BlockNote Commercial license (included in the Business tier and
+ above) for XL packages covers one application per license. See the{" "}
+
+ commercial license terms
+ {" "}
+ for the exact details.
+
+ If you want to use XL packages in more than one app, contact us at
+ team@blocknotejs.org; we're happy to work with you on a custom
+ license.
+ >
+ ),
+ },
+ {
+ question: "Do you offer any discounts for startups?",
+ answer: (
+ <>
+ Yes! We offer a discount for startups with less than 5 employees. See
+ the{" "}
+
+ commercial license terms
+ {" "}
+ for the exact details.
+ >
+ ),
+ },
+ {
+ question: "What payment methods do you accept?",
+ answer: `We accept all major credit cards. If you require a different payment method, please contact us.`,
+ },
+];
+
+export function FAQ() {
+ return (
+
+ 100% Open Source.
+
+
+
+ Fair Pricing.
+
+
+
+ Discounts for Startups
+
+
+ {tier.title}
+
+ {tier.tagline && (
+
+ {tier.features.map((feature, index) => (
+
+