ponymessenger / use-prosemirror Goto Github PK
View Code? Open in Web Editor NEWProseMirror + React made easy
License: MIT License
ProseMirror + React made easy
License: MIT License
Can you add react 18 to peer dependencies?
It is working on React 18 fine, but npm install
returns errors without --force
.
Hello,
I'm trying to setup this dependency on a fresh create-react-app app.
`import 'prosemirror-view/style/prosemirror.css';
import React from 'react';
import {schema} from 'prosemirror-schema-basic';
import {useProseMirror, ProseMirror} from 'use-prosemirror';
export default function MyEditor() {
const [state, setState] = useProseMirror({schema});
return
I'm getting the following error on the console:
Uncaught TypeError: Cannot read properties of undefined (reading 'create')
Any idea?
Thanks.
I got a really strange behavior when i'm activating node views. I can't place the cursor anymore, so editing breaks. Could you check if you observe the same?
I'm suspecting this line in ProseMirror.tsx:
viewRef.current?.setProps(buildProps(restProps));
Maybe the nodeViews prop can only be set initially not on each rerender. But that's just a guess.
Here's my additions that lead to the problem.
class ImageView {
constructor (node) {
// The editor will use this as the node's DOM representation
this.dom = document.createElement('img')
this.dom.src = 'https://letsken.imgix.net/'+node.src
this.dom.addEventListener('click', e => {
console.log('You clicked me!')
e.preventDefault()
})
}
stopEvent () { return true }
}
const nodeViews = {
image (node) { return new ImageView(node) }
}
...
<ProseMirror ref={viewRef} state={state} onChange={handleChange} nodeViews={nodeViews} />
When passing nodeViews
as a prop to <ProseMirror />
, the editor is broken and React warns:
Warning: unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering.
This only happens when nodeViews
identity changes from render to render. The issue appears to be related to EditorView#updateStateInner()
, where nodeViews' identity changes causes the editor view to modify its "outer decoration". Judging by the code, this only happens in Chrome and related browsers.
Not sure what a proper fix for this would be.
For now, a workaround is to keep the nodeViews
prop identity stable.
Is there any way to use a subclass of EditorView
instead of EditorView
itself with use-prosemirror
? Looking through the code, it looks like EditorView
is hardcoded, but perhaps I've missed something.
If it's not supported, would you consider supporting it? I'm not sure the best way to do it, but perhaps the class could be passed in as a property. I'd be happy to help with a PR, but I like to first make sure I do it in the way you prefer (I'm not a terribly experienced JS programmer, so I may "obvious" approaches).
I'm using the use-prosemirror's ProseMirror component inside a React Stateless Functional Component (BookEditor).
const BookEditor = React.memo((props, nextProps) => {
const contentDiv = document.createElement('div');
contentDiv.innerHTML = props.textPage.content; // getting content from props's textPage
const isFirstRun = useRef(true);
useEffect(
() => {
if (isFirstRun.current) {
isFirstRun.current = false;
return;
} else {
const { view } = useProseMirrorComp;
const { state } = view;
const { schema, plugins } = state;
const doc = DOMParser.fromSchema(mySchema).parse(contentDiv);
let newState = EditorState.create({ schema: schema, doc, plugins: plugins });
view.updateState(newState);
}
},
[props.textPage],
);
// defining my custom nodes here
const editorTitleHeader = {...};
const editorTitle = {...};
schema.spec.nodes = schema.spec.nodes.append({
editorTitle,
editorTitleHeader,
});
nodes.doc.content = 'editorTitle block+';
const mySchema = new Schema({
nodes: addListNodes(schema.spec.nodes, 'paragraph block*', 'block'),
marks: schema.spec.marks,
});
const rules = [...];
const doc = DOMParser.fromSchema(mySchema).parse(contentDiv);
const [state, setState] = useProseMirror({
doc,
schema: mySchema,
plugins: [
inputRules({ rules: rules }),
columnResizing(),
tableEditing(),
keymap({
Tab: goToNextCell(1),
'Shift-Tab': goToNextCell(-1),
}),
].concat(exampleSetup({ schema, menuContent: menu })),
destroy: () => {
console.log('BookEditor : destroy!!!!!!!!! ');
},
});
return (
<div id="use-prosemirror-comp">
<ProseMirror
state={state}
dispatchTransaction={transaction => {...}}
ref={r => {
useProseMirrorComp = r;
}}
nodeViews={...}
>
<div id="content" />
</ProseMirror>
</div>
);
});
I used use-prosemirror as it's supposed to make prosemirror fit better with react.
But in such as case of using it in inside a React Stateless Functional Component, it seems not fitting well.
I'm still relatively new with react hooks..
When the Stateless Functional Component is called again for a new rendering, all the < ProseMirror > will be reinstantiated as it lies in the body of the function.
And each time that happens, a new content will be passed to it (through contentDiv which will be parsed and the state doc generated) but i noticed that the < ProseMirror > fails to update the content even when that happen (if there is no state update view.updateState(newState); inside the useEffect's isFirstRun.current == false case).
And i also think that it's not the best performance fit to reinstanciate the whole < ProseMirror > in each Stateless Functional Component re-rendering.
The Stateless Functional Component should return a content thought, that's why i can't only return the in the useEffect's isFirstRun.current == true case (which is the old componentDidMount hook equivalent). So i still have to return it in each rendering and then update its content in the useEffect's isFirstRun.current == false case (equivalent to the old componentDidUpdate).
I got a recommandation to use the use-prosemirror for react but i don't think it's a good idea.
Any thoughts about this ?
Last question : does React.memo have an effect in all this and the performance ?
Hi,
I'm trying to add Prosemirror's Upload Example to your codesandbox example.
For placeholderPlugin
, adding a decoration to DecorationSet seems to be working. But placeholderPlugin.getState(state)
seems to be always returning an empty DecorationSet.
Am I doing anything wrong? Should I use a different way other than the official one to implement image uploading?
Reproduction: https://codesandbox.io/s/use-prosemirror-basic-example-forked-6g2t0
Thanks.
Hi @dminkovsky!
I just wanted to make use of passing className='article' to <ProseMirror ..>
. The result is this structure:
Would it be possible to have the classes assigned along .ProseMirror instead of a wrapping div around?
I'd like to get class="ProseMirror article"
so I can use the same CSS for display and editing.
Thank you :)
Hi there!
I'm integrating ProseMirror with your approach using React. Along with ProseMirror I'm rendering an EditorMenu that computes and renders editor tools.
Here's my integration code:
export default function Editor (props) {
const [editorView, setEditorView] = useState(null)
const [state, setState] = useProseMirror({
doc: DOMParser.fromSchema().parse(buildHTML()),
plugins: [
keymap(buildKeymap(schema)),
keymap(baseKeymap),
history(),
dropCursor()
]
})
useEffect(() => {
setEditorView(viewRef.current.view)
}, [])
const viewRef = useRef()
return (
<div className='flex flex-col h-screen'>
<header className='p-5 bg-white shadow'>
<EditorMenu editorView={editorView} />
</header>
<main className='flex-1 overflow-y-auto p-5 article'>
<div className='max-w-4xl mx-auto py-6 sm:px-6 lg:px-8'>
<ProseMirror
ref={viewRef}
state={state}
onChange={newState => {
// HACK: Update the editor view right away, so in EditorMenu editorView.state reflects newState
viewRef.current.view.updateState(newState)
setState(newState)
}}
/>
</div>
</main>
</div>
)
}
The menu bar thus is one update cycle behind. I solved this problem by running editorView.updateState(newState) in the onChange handler explicitly. However, I wonder what an idiomatic way of doing this would be? I could pass both state and editorView to EditorMenu, but that complicates the interface a bit. I kinda like that ProseMirror and EditorMenu are part of the same render flow with useProseMirror. In my previous integration the EditorMenu was decoupled and was listening to state updates. I also wonder if there's a better way to provide editorView to EditorMenu. Would be nice not avoid using another component state + useEffect for that. I'm quite new to Function Components โ not been using React in a while. ๐ Maybe you have some ideas...
Thank you!
I'm trying to use code mirror in a nodeView, essentially following the example in ProseMirror's docs. It's actually mostly working, but I still get the "unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering." when new codemirror instance is created (really, when it's rendered for the first time, I think).
I know this has been discussed at some length in #1 and #5, but I was wondering if the advice/techniques discussed there are still relevant. That is, should I use the portal approach outlined by @dminkovsky? He also said "it would be nice to include this inside the ProseMirror component so users don't have to deal with this problem", so I also wondered if it had been included.
If it'll help if I post some code, let me know and I'll do so.
hi, how can I modify the editor layour to this:
https://prnt.sc/128byeo
instead of this?
https://prnt.sc/128c0v9
ProseMirror allows specifying that a transaction should result in the cursor scrolled into view. 1.2.0 broke this behavior.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.