You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, the React integration for Milkdown is a bit bare-bones and unconventional. The common patterns of React like props, event handlers, hook composition, component composition, controlled/uncontrolled components are not present, instead being replaced by a Milkdown-specific abstraction with context keys. I think the React integration could be made vastly more accessible to developers by taking advantage of existing patterns and abstracting some of Milkdown's internals.
Concrete proposals
Make the Milkdown context provider optional
As it stands, it is impossible to constrain Milkdown to a single component. If I want my app to use <Editor />, I either have to make sure that there's a <MilkdownProvider> higher up in the tree or create another component, say, <EditorInternal /> that actually contains the editor, with <Editor /> playing the role of a wrapper/context provider.
Support basic events like onChange, onFocus, and onBlur out of the box as props
The event integration is a separate package, which is nice and modular, but again, not as ergonomic. In the land of React, it's fairly common to have controlled inputs, because there is hardly a time where you will not want to access the content that the user wrote. With that, I think the event listener plugin should come packaged with the React integration, and if anyone finds it to be too much of a bundle increase, for those the library can expose some internal building blocks of the React integration so that they would be able to build their own custom integration and tree-shake the rest away.
Support defaultValue and value out of the box as props
Same reasoning, these should just be native props seeing as they are essential to having an editor operating on existing data.
Support DOM props on the editor element
It's a bit unfortunate that the most basic instance of Milkdown React editor has 3 nested DOM nodes (div[data-milkdown-root] > div.milkdown > div[contenteditable]), because it makes it harder to have the editor span the entire height of its parent, i.e. be more than 1 line in height without content. This is made even harder by the <Milkdown /> component not passing through any props to its underlying DOM element, leaving no options to set a class name or any other DOM props on it. I would prefer the Milkdown component to pass everything through and also if possible, I'd love to have the topmost div[data-milkdown-root] removed.
Accept plugins through props
This could be done on the provider, passing an array of plugins, or it could be done in a hook as one of the config object's fields. I'd prefer any of those to having to chain .use() calls on an exposed Editor object.
[Bonus point] Support placeholder
This is a less essential one, but figuring out how to add a placeholder to the editor is not exactly trivial, and I'm not too happy with the code I wrote for this job. Having this abstracted away and implemented in a single recommended way would be very nice.
Proof of concept (React)
In the process of integrating Milkdown into my app, I ended up building some of the features I mentioned above. I'll share this code here in hopes of providing a headstart to potential API improvements in the core of the React integration.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Currently, the React integration for Milkdown is a bit bare-bones and unconventional. The common patterns of React like props, event handlers, hook composition, component composition, controlled/uncontrolled components are not present, instead being replaced by a Milkdown-specific abstraction with context keys. I think the React integration could be made vastly more accessible to developers by taking advantage of existing patterns and abstracting some of Milkdown's internals.
Concrete proposals
As it stands, it is impossible to constrain Milkdown to a single component. If I want my app to use
<Editor />
, I either have to make sure that there's a<MilkdownProvider>
higher up in the tree or create another component, say,<EditorInternal />
that actually contains the editor, with<Editor />
playing the role of a wrapper/context provider.onChange
,onFocus
, andonBlur
out of the box as propsThe event integration is a separate package, which is nice and modular, but again, not as ergonomic. In the land of React, it's fairly common to have controlled inputs, because there is hardly a time where you will not want to access the content that the user wrote. With that, I think the event listener plugin should come packaged with the React integration, and if anyone finds it to be too much of a bundle increase, for those the library can expose some internal building blocks of the React integration so that they would be able to build their own custom integration and tree-shake the rest away.
defaultValue
andvalue
out of the box as propsSame reasoning, these should just be native props seeing as they are essential to having an editor operating on existing data.
It's a bit unfortunate that the most basic instance of Milkdown React editor has 3 nested DOM nodes (
div[data-milkdown-root] > div.milkdown > div[contenteditable]
), because it makes it harder to have the editor span the entire height of its parent, i.e. be more than 1 line in height without content. This is made even harder by the<Milkdown />
component not passing through any props to its underlying DOM element, leaving no options to set a class name or any other DOM props on it. I would prefer the Milkdown component to pass everything through and also if possible, I'd love to have the topmostdiv[data-milkdown-root]
removed.This could be done on the provider, passing an array of plugins, or it could be done in a hook as one of the config object's fields. I'd prefer any of those to having to chain
.use()
calls on an exposed Editor object.placeholder
This is a less essential one, but figuring out how to add a placeholder to the editor is not exactly trivial, and I'm not too happy with the code I wrote for this job. Having this abstracted away and implemented in a single recommended way would be very nice.
Proof of concept (React)
In the process of integrating Milkdown into my app, I ended up building some of the features I mentioned above. I'll share this code here in hopes of providing a headstart to potential API improvements in the core of the React integration.
Beta Was this translation helpful? Give feedback.
All reactions