Registry / web-framework / prosemirror-resizable-view

prosemirror-resizable-view

JSON →
library3.0.0jsnpmunverified

The `prosemirror-resizable-view` package provides a specialized `NodeView` implementation for ProseMirror that enables users to resize custom nodes directly within the editor interface. It is an integral part of the broader Remirror ecosystem and currently aligns with Remirror's stable version 3.0.0. This package itself is at version 3.0.0, benefiting from the active development cadence of the Remirror project, which includes regular patch releases for bug fixes and dependency updates. Its primary differentiator lies in abstracting the complexities of implementing resizable DOM elements within a ProseMirror `NodeView`, offering a convenient base class that handles drag events and dimension management. This significantly simplifies the development process for integrating dynamic resize functionality for various content types like images, video embeds, or custom block components. The package comes with comprehensive TypeScript type definitions, enhancing developer experience and code safety.

npm install prosemirror-resizable-view
INSTALL
IMPORT
SIG · PROSEMIRROR-RESIZA
P
prosemirror-resizable-view
web-frameworkjavascriptv3.0.0
Install
Import
Disk
Pass rate
0/ 6
Env Coverage0 / 6
glibc
1822
musl
1822
Install & Compatibility
Where this runs
tested against v? · npm install
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
node 18226 runs
build_error
glibc
node 18226 runs
build_error
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

ResizableNodeView
import { ResizableNodeView } from 'prosemirror-resizable-view';
const ResizableNodeView = require('prosemirror-resizable-view');
Primarily designed for ESM environments. While CommonJS `require` might work with transpilation, direct ESM import is recommended.
Node
import { Node as ProsemirrorNode } from 'prosemirror-model';
import { Node } from 'prosemirror-model';
`Node` is a common global type in TypeScript/JavaScript; aliasing it as `ProsemirrorNode` avoids naming conflicts.
NodeView
import { EditorView, NodeView } from 'prosemirror-view';
import { NodeView } from 'prosemirror-model';
The `NodeView` interface originates from `prosemirror-view`, not `prosemirror-model`.
EditorView
import { EditorView } from 'prosemirror-view';
import { EditorView } from '@remirror/pm';
While `@remirror/pm` re-exports ProseMirror modules, directly importing `EditorView` from `prosemirror-view` is standard practice.

This quickstart demonstrates how to create a basic ProseMirror editor with a custom `image` node, then renders this node using `ResizableImageView` to allow users to resize images within the editor. It includes schema definition, `ResizableNodeView` extension, and editor setup.

import { ResizableNodeView } from 'prosemirror-resizable-view'; import { Node as ProsemirrorNode, Schema } from 'prosemirror-model'; import { EditorView, NodeView } from 'prosemirror-view'; import { EditorState } from 'prosemirror-state'; import { baseKeymap } from 'prosemirror-commands'; import { keymap } from 'prosemirror-keymap'; // 1. Define a basic schema with an 'image' node that can have width/height attributes const mySchema = new Schema({ nodes: { doc: { content: 'block+' }, paragraph: { content: 'inline*', group: 'block' }, image: { inline: false, attrs: { src: { default: '' }, alt: { default: null }, title: { default: null }, width: { default: null }, height: { default: null }, }, group: 'block', parseDOM: [{ tag: 'img[src]', getAttrs(dom) { if (typeof dom === 'string') return {}; return { src: dom.getAttribute('src'), alt: dom.getAttribute('alt'), title: dom.getAttribute('title'), width: dom.getAttribute('width'), height: dom.getAttribute('height'), }; }, }], toDOM(node) { return [ 'img', { src: node.attrs.src, alt: node.attrs.alt, title: node.attrs.title, width: node.attrs.width, // Render initial width height: node.attrs.height, // Render initial height }, ]; }, }, text: { inline: true, group: 'inline' }, }, marks: {}, }); // 2. Helper function to create the actual DOM element for the image const createInnerImage = ({ node }: { node: ProsemirrorNode }) => { const inner = document.createElement('img'); inner.setAttribute('src', node.attrs.src); if (node.attrs.alt) inner.setAttribute('alt', node.attrs.alt); if (node.attrs.title) inner.setAttribute('title', node.attrs.title); inner.style.width = node.attrs.width ? `${node.attrs.width}px` : '100%'; inner.style.height = node.attrs.height ? `${node.attrs.height}px` : 'auto'; inner.style.minWidth = '50px'; inner.style.objectFit = 'contain'; return inner; }; // 3. Extend ResizableNodeView to create a custom resizable image view export class ResizableImageView extends ResizableNodeView implements NodeView { constructor(node: ProsemirrorNode, view: EditorView, getPos: () => number) { super({ node, view, getPos, createElement: createInnerImage, // Optional: Set aspectRatio to 'lock' to maintain aspect ratio, or 'free'. // aspectRatio: 'lock', updateSize: (width, height) => { // This callback is crucial: dispatch a transaction to update the node's attributes const tr = view.state.tr.setNodeMarkup(getPos(), undefined, { ...node.attrs, width, height, }); view.dispatch(tr); }, }); } } // 4. Set up the ProseMirror Editor const editorDiv = document.createElement('div'); editorDiv.id = 'editor'; document.body.appendChild(editorDiv); const state = EditorState.create({ schema: mySchema, doc: mySchema.nodeFromJSON({ type: 'doc', content: [ { type: 'paragraph', content: [{ type: 'text', text: 'Drag the handles to resize the image:' }], }, { type: 'image', attrs: { src: 'https://via.placeholder.com/250x180', width: 250, height: 180 }, }, { type: 'paragraph', content: [{ type: 'text', text: 'This is some text below the resizable image.' }], }, ], }), plugins: [keymap(baseKeymap)], }); const view = new EditorView(editorDiv, { state, nodeViews: { image(node, view, getPos) { return new ResizableImageView(node, view, getPos); }, }, }); // Expose view for debugging in browser console (window as any).view = view;
Debug
Known issues
breakingAs `prosemirror-resizable-view` aligns with the Remirror v3 ecosystem, projects upgrading to Remirror v3 will need to contend with its shift to Stage 3 decorators from TypeScript's experimental decorators. While this package itself may not directly expose decorators, other Remirror extensions commonly used alongside it require this update, potentially affecting TypeScript configurations.
fix
Ensure your TypeScript configuration (`tsconfig.json`) is set to support Stage 3 decorators (e.g., `"experimentalDecorators": true` and `"emitDecoratorMetadata": true` if using decorators with reflection, and potentially `"target": "es2020"` or higher).
affects: >=3.0.0
breakingRemirror v3, which this package is part of, has updated its underlying ProseMirror dependencies. This may necessitate users to verify that their core `prosemirror-*` package versions are compatible with the versions expected by the `prosemirror-resizable-view` package and its Remirror counterparts.
fix
Check the `peerDependencies` of `prosemirror-resizable-view` (or the wider Remirror ecosystem) and ensure your direct `prosemirror-*` dependencies match the specified ranges to avoid runtime errors or unexpected behavior due to API mismatches.
affects: >=3.0.0
gotchaDirectly manipulating the DOM elements of a `NodeView` (e.g., changing width/height styles) without dispatching a ProseMirror transaction will often result in the changes being overwritten by ProseMirror's rendering cycle, leading to non-persistent visual updates.
fix
Always reflect size changes in the ProseMirror node's attributes and dispatch a transaction using `view.dispatch(view.state.tr.setNodeMarkup(...))` within the `updateSize` callback of `ResizableNodeView` or similar methods.
affects: >=1.0.0
gotcha`ResizableNodeView` is an abstract class and cannot be instantiated directly. It requires extension by a custom class that implements the abstract `createElement` method to provide the actual DOM structure for the node.
fix
Create a subclass that extends `ResizableNodeView` and explicitly implements the `createElement(props: { node: ProsemirrorNode; view: EditorView; })` method to return an `HTMLElement` for your node view.
affects: >=1.0.0
gotchaImplementing functional resize handles requires careful styling (CSS) for the overlay and interaction areas. Without correct `position`, `z-index`, and `pointer-events` properties, the handles may not be visible or respond to user drag events.
fix
Ensure that the CSS for your resizable node view and its handles is correctly applied to make the resize controls interactive. Refer to the package's documentation or examples for recommended styling approaches, or use development tools to inspect event listeners.
affects: >=1.0.0
Errors
Common errors & fixes
TypeError: node.update is not a function
This error occurs when a custom `NodeView` (including one extending `ResizableNodeView`) does not correctly implement or return a value from its `update` method when the underlying ProseMirror node attributes change.
fix
Ensure your `ResizableNodeView` subclass implements an `update(node: ProsemirrorNode)` method that appropriately handles attribute changes and returns `true` if it can update the DOM in place, or `false` if ProseMirror should redraw the node view entirely.
Cannot read properties of undefined (reading 'appendChild')
This typically indicates that the `dom` or `contentDOM` property of the `NodeView` (or the element returned by `createElement`) was not properly initialized or returned a `null`/`undefined` value, preventing ProseMirror from attaching children.
fix
Verify that your `ResizableNodeView` subclass's `createElement` method always returns a valid `HTMLElement`, and that the `dom` property of the `NodeView` instance is correctly assigned to this element.
Resize handles are visible but do not respond to drag events.
This is often a CSS-related issue, where the resize handles' `pointer-events` property or their z-index prevents them from receiving mouse events, or event listeners are incorrectly attached.
fix
Inspect the CSS of the resize handles to ensure `pointer-events` are not set to `none` (unless intended) and that they are positioned above other elements. Double-check that event listeners for resizing are correctly bound to the resize handle elements.
Upgrade
Version history
3.0.0latest on npm
Audit
Dependencies
prosemirror-modelrequiredRequired for `ProsemirrorNode` which represents the editor's content nodes and is passed to the NodeView constructor.
prosemirror-viewrequiredRequired for `NodeView` and `EditorView` classes, fundamental components for rendering and interacting with ProseMirror documents.
Agent activity
4 hits · last 30 days
node
4
Resources
prosemirror-resizable-view — npm install prosemirror-resizable-view · libregistry