
Product
Introducing Socket Fix for Safe, Automated Dependency Upgrades
Automatically fix and test dependency updates with socket fix—a new CLI tool that turns CVE alerts into safe, automated upgrades.
@prosemirror-adapter/react
Advanced tools
[React](https://reactjs.org/) adapter for [ProseMirror](https://prosemirror.net/).
React adapter for ProseMirror.
You can view the example in prosemirror-adapter/examples/react.
npm install @prosemirror-adapter/react
import { ProsemirrorAdapterProvider } from '@prosemirror-adapter/react'
import { YourAwesomeEditor } from 'somewhere'
export const Component = () => {
return (
<ProsemirrorAdapterProvider>
<YourAwesomeEditor />
</ProsemirrorAdapterProvider>
)
}
In this section we will implement a node view for paragraph node.
import { useNodeViewContext } from '@prosemirror-adapter/react'
const Paragraph = () => {
const { contentRef, selected } = useNodeViewContext()
return <div style={{ outline: selected ? 'blue solid 1px' : 'none' }} role="presentation" ref={contentRef} />
}
import { useNodeViewFactory } from '@prosemirror-adapter/react'
import type { FC } from 'react'
import { useCallback, useRef } from 'react'
import { Paragraph } from './Paragraph'
export const YourAwesomeEditor: FC = () => {
const nodeViewFactory = useNodeViewFactory()
const editorRef = useCallback(
(element: HTMLDivElement) => {
if (!element || element.firstChild)
return
const editorView = new EditorView(element, {
state: YourProsemirrorEditorState,
nodeViews: {
paragraph: nodeViewFactory({
component: Paragraph,
// Optional: add some options
as: 'div',
contentAs: 'p',
}),
}
})
},
[nodeViewFactory],
)
return <div className="editor" ref={editorRef} />
}
🚀 Congratulations! You have built your first react node view with prosemirror-adapter.
In this section we will implement a mark view for links that changes color periodically.
import { useEffect, useState } from 'react'
import { useMarkViewContext } from '@prosemirror-adapter/react'
const colors = [
'#f06292', '#ba68c8', '#9575cd', '#7986cb', '#64b5f6',
'#4fc3f7', '#4dd0e1', '#4db6ac', '#81c784', '#aed581',
'#ffb74d', '#ffa726', '#ff8a65', '#d4e157', '#ffd54f',
'#ffecb3',
]
function pickRandomColor() {
return colors[Math.floor(Math.random() * colors.length)]
}
export function Link() {
const [color, setColor] = useState(colors[0])
const { mark, contentRef } = useMarkViewContext()
const href = mark.attrs.href as string
const title = mark.attrs.title as string | null
useEffect(() => {
const interval = setInterval(() => {
setColor(pickRandomColor())
}, 1000)
return () => clearInterval(interval)
}, [])
return (
<a
href={href}
ref={contentRef}
style={{ color, transition: 'color 1s ease-in-out' }}
title={title || undefined}
>
</a>
)
}
import { useMarkViewFactory } from '@prosemirror-adapter/react'
import type { FC } from 'react'
import { useCallback } from 'react'
export const YourAwesomeEditor: FC = () => {
const markViewFactory = useMarkViewFactory()
const editorRef = useCallback(
(element: HTMLDivElement) => {
if (!element || element.firstChild)
return
const editorView = new EditorView(element, {
state: EditorState.create({
schema: YourProsemirrorSchema,
plugins: [
new Plugin({
props: {
markViews: {
link: markViewFactory({
component: Link,
}),
},
},
}),
]
})
})
},
[markViewFactory],
)
return <div className="editor" ref={editorRef} />
}
🚀 Congratulations! You have built your first react mark view with prosemirror-adapter.
In this section we will implement a plugin view that will display the size of the document.
import { usePluginViewContext } from '@prosemirror-adapter/react'
const Size = () => {
const { view } = usePluginViewContext()
const size = view.state.doc.nodeSize
return <div>Size for document: {size}</div>
}
import { usePluginViewFactory } from '@prosemirror-adapter/react'
import type { FC } from 'react'
import { useCallback, useRef } from 'react'
import { Plugin } from 'prosemirror-state'
import { Paragraph } from './Paragraph'
export const YourAwesomeEditor: FC = () => {
const pluginViewFactory = usePluginViewFactory()
const editorRef = useCallback(
(element: HTMLDivElement) => {
if (!element || element.firstChild)
return
const editorView = new EditorView(element, {
state: EditorState.create({
schema: YourProsemirrorSchema,
plugins: [
new Plugin({
view: pluginViewFactory({
component: Size,
}),
}),
]
})
})
},
[pluginViewFactory],
)
return <div className="editor" ref={editorRef} />
}
🚀 Congratulations! You have built your first react plugin view with prosemirror-adapter.
In this section we will implement a widget view that will add hashes for heading when selected.
import { useWidgetViewContext } from '@prosemirror-adapter/react'
export const Hashes = () => {
const { spec } = useWidgetViewContext()
const level = spec?.level
const hashes = Array(level || 0).fill('#').join('')
return <span style={{ color: 'blue', marginRight: 6 }}>{hashes}</span>
}
import { useWidgetViewFactory } from '@prosemirror-adapter/react'
import type { FC } from 'react'
import { useCallback, useRef } from 'react'
import { Plugin } from 'prosemirror-state'
import { Hashes } from './Hashes'
export const YourAwesomeEditor: FC = () => {
const widgetViewFactory = useWidgetViewFactory()
const editorRef = useCallback(
(element: HTMLDivElement) => {
if (!element || element.firstChild)
return
const getHashWidget = widgetViewFactory({
as: 'i',
component: Hashes,
})
const editorView = new EditorView(element, {
state: EditorState.create({
schema: YourProsemirrorSchema,
plugins: [
new Plugin({
props: {
decorations(state) {
const { $from } = state.selection
const node = $from.node()
if (node.type.name !== 'heading')
return DecorationSet.empty
const widget = getHashWidget($from.before() + 1, {
side: -1,
level: node.attrs.level,
})
return DecorationSet.create(state.doc, [widget])
},
},
}),
]
})
})
},
[widgetViewFactory],
)
return <div className="editor" ref={editorRef} />
}
🚀 Congratulations! You have built your first react widget view with prosemirror-adapter.
type DOMSpec = string | HTMLElement | ((node: Node) => HTMLElement)
interface NodeViewFactoryOptions {
// Component
component: ReactComponent
// The DOM element to use as the root node of the node view.
as?: DOMSpec
// The DOM element that contains the content of the node.
contentAs?: DOMSpec
// Overrides: this part is equal to properties of [NodeView](https://prosemirror.net/docs/ref/#view.NodeView)
update?: (node: Node, decorations: readonly Decoration[], innerDecorations: DecorationSource) => boolean | void
ignoreMutation?: (mutation: ViewMutationRecord) => boolean | void
selectNode?: () => void
deselectNode?: () => void
setSelection?: (anchor: number, head: number, root: Document | ShadowRoot) => void
stopEvent?: (event: Event) => boolean
destroy?: () => void
// Called when the node view is updated.
onUpdate?: () => void
}
interface NodeViewContext {
// The DOM element that contains the content of the node.
contentRef: NodeViewContentRef
// The prosemirror editor view.
view: EditorView
// Get prosemirror position of current node view.
getPos: () => number | undefined
// Set node.attrs of current node.
setAttrs: (attrs: Attrs) => void
// The prosemirror node for current node.
node: Node
// The prosemirror decorations for current node.
decorations: readonly Decoration[]
// The prosemirror inner decorations for current node.
innerDecorations: DecorationSource
// Whether the node is selected.
selected: boolean
}
type MarkViewDOMSpec = string | HTMLElement | ((mark: Mark) => HTMLElement)
interface MarkViewFactoryOptions {
// Component
component: ReactComponent
// The DOM element to use as the root node of the mark view
as?: MarkViewDOMSpec
// The DOM element that contains the content of the mark
contentAs?: MarkViewDOMSpec
// Called when the mark view is destroyed
destroy?: () => void
}
interface MarkViewContext {
// The DOM element that contains the content of the mark
contentRef: MarkViewContentRef
// The prosemirror editor view
view: EditorView
// The prosemirror mark for current mark view
mark: Mark
// Whether the mark is inline
inline: boolean
}
interface PluginViewFactoryOptions {
// Component
component: ReactComponent
// The DOM element to use as the root node of the plugin view.
// The `viewDOM` here means `EditorState.view.dom`.
// By default, it will be `EditorState.view.dom.parentElement`.
root?: (viewDOM: HTMLElement) => HTMLElement
// Overrides: this part is equal to properties of [PluginView](https://prosemirror.net/docs/ref/#state.PluginView)
update?: (view: EditorView, prevState: EditorState) => void
destroy?: () => void
}
interface PluginViewContext {
// The prosemirror editor view.
view: EditorView
// The previously prosemirror editor state.
// Will be `undefined` when the plugin view is created.
prevState?: EditorState
}
type WidgetDecorationFactory = (pos: number, spec?: WidgetDecorationSpec) => Decoration
interface WidgetViewFactoryOptions {
// Component
component: ReactComponent
// The DOM element to use as the root node of the widget view.
as: string | HTMLElement
}
interface WidgetViewContext {
// The prosemirror editor view.
view: EditorView
// Get the position of the widget.
getPos: () => number | undefined
// Get the [spec](https://prosemirror.net/docs/ref/#view.Decoration^widget^spec) of the widget.
spec?: WidgetDecorationSpec
}
Follow our contribution guide to learn how to contribute to prosemirror-adapter.
FAQs
[React](https://reactjs.org/) adapter for [ProseMirror](https://prosemirror.net/).
The npm package @prosemirror-adapter/react receives a total of 6,019 weekly downloads. As such, @prosemirror-adapter/react popularity was classified as popular.
We found that @prosemirror-adapter/react demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Automatically fix and test dependency updates with socket fix—a new CLI tool that turns CVE alerts into safe, automated upgrades.
Security News
CISA denies CVE funding issues amid backlash over a new CVE foundation formed by board members, raising concerns about transparency and program governance.
Product
We’re excited to announce a powerful new capability in Socket: historical data and enhanced analytics.