-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mismatch between "editor" and "value" concepts #2206
Comments
Perhaps we shall expose Perhaps we shall expose
Can I know where we need about |
Hmm I've been wrestling with this one myself. The mental model I have for the Editor is that it is simply the view layer. Given a bunch of props like value / schema etc., Render something to the page. The value is then just the pure state of the app: what is the current snapshot of the app's state. I think the problem is that this gives us the "view" and the "model" but it doesn't really tell us where the controller lives (in a traditional MVC architecture). So the current "controller" is a combination of change, value and the editor that don't always know how to talk to each other. This is why there is some confusion about whether to make changes you need to talk to the value or the editor. I wonder if there should be a third component like The big downside I see to this is that in React a component is generally also the controller. This might cause us to move further away from React best practices. |
I think one problem is that we expose |
I like @ericedem's suggestion. Perhaps we should consider Editor as a target environment and allow plugins to target different environments. This would also make it easier to target other environments later like react-native for plugins or even completely different frameworks than React (if someone would want to do this). Just a late night thought 🤷♂️ |
@bryanph can you give some pseudocode to explain what you mean? or explain more? |
I don't really have anything concrete to add, other than that I think of Editor purely as the view/controller layer, and that I really really like being able to work with a Value outside of the context of showing an editor. It's one of my favorite things about Slate -- with just a Value, I can create and apply operations, I can apply schemas, I can serialize / deserialize, etc. I get all the transformations I want, and just get a new Value at the end. A few things people have mentioned here that I'd appreciate:
|
@ericedem I agree with you, having a plain-JS "controller" concept is compelling. It would help the server-side story, it would probably clean up some of the existing client-side story, and it would make it more clear where the interoperability boundary is for plugins and other view layers in the future. @justinweiss I agree with you too, I'd like history to be more pluggable. And it sounds like you're talking about similar things to @ericedem as well. I think one thing I'm struggling with is where the
If we approach it from the plain-JS controller mindset, then 1. might not be as much of an issue, because instantiating a lightweight We could decide to get rid of the: value.change()... In favor of only having the: controller.change(change => ...) But that loses some of the niceties that @justinweiss is talking about. But @justinweiss I'd be curious to hear which of those are truly most important to you. I'm not sure I'd personally mind it if the schema was tied to the
And losing:
This would make it clear that these things are the domain of the controller: controller.change(change => ...)
controller.command('toggle_bold')
controller.query('is_bold') What are your thoughts on that? (Anyone!) |
Thinking about it more, Schema isn't really a property of a Value, it's a property of how you use it. If we had a Controller, it seems like the right place for those. It shouldn't be much of a problem -- If I could, in a Node app (for example), manually instantiate a controller, hand it a Value.fromJSON and a schema, run changes on it, and pull either an updated Value or a bunch of Operations back out of it, that wouldn't be much more complicated than it is today. And if we can still hand a Value a list of Operations and get a new Value out of them, there's always an out if going through the Controller isn't feasible. You just wouldn't be able to guarantee those operations would put the Value into a valid state. But if the list of operations originally came from change methods, you could assume that normalizing operations were already in that list. |
@justinweiss nice, I agree! In the OT server use case where you’re receiving the low-level “valid” operations you can operate on the value directly. And for other use cases you can instantiate a thin controller. I think it might also make it possible for us to combine the idea of the “simulator” and the “controller” potentially which would be nice for testing. |
@ianstormtaylor Yeah. In the OT case, though, you could have valid simultaneous operations put the Value into an invalid state. Imagine you have two empty paragraphs, client 1 deletes paragraph 1, and client 2 simultaneously deletes paragraph 2. Those are both valid operations on the document, but you'd end up with a Document with no nodes. So you'd probably want the Schema / Controller on that side, too, you just wouldn't need an Editor. |
I'm just going to leave a summary of my current API architecture thoughts here...
At the end you end up with a clearer delineations:
The only overlap remaining that I can see still is that "plugins" end up defining logic that lives in both the Controller and the View layers. But I'm not sure if there's a way around this. (If anyone has ideas I'm open!) How does that sound? |
Hey this sounds great, just a couple questions:
Can you clarify what these queries would be used for? Is this for grabbing a subset of the value? Would this replace access like Also, I'm trying to think through what the interface to react would look like. Would the user create an instance of Editor and pass it into the react editor? Or would the user still pass in through a similar interface to what they are doing today, and have the Component build out the Is the React component still going to be controlled like it is now? By emitting the value in a change event and passing it back in through props? Or would the React component emit the entire EditorController on every change? |
@ericedem great questions! Thanks for reading and digging in.
Sorry, this is from #2066. Basically once you add "commands" you start to realize that many things that work with commands need to ask the editors questions to know whether to perform certain logic, and you get a parallel "queries" feature for doing that. If "commands" are schema-specific functions that perform changes. Then "queries" are schema-specific functions that return information.
I'm sketching this out right now. I'd like to keep the component interface the same, since it feels pretty nice to me, and feels React-ish. Such that the However, that underlying controller is never publicly exposed to the user. So for example, the By doing that, the However, on the server-side you'd just use the What this means is that some plugins, if they happen to rely on React-specific properties of the How does that sound? |
@ianstormtaylor So what would be possible with this architecture that isn't possible currently? I'm not sure I fully understand the issue. Some thoughts:
As for what I meant with targeting an environment, this was a thought I had because plugins to me seem to do two things:
Since plugins tend to wrap functional behaviour, like a nested list or adding an image block, I thought perhaps the environment-specific code like adding event listeners could be specified in the plugin as belonging to a certain environment, like React or React native. So that when iterating through all the plugins you would potentially get support for multiple environments depending on which environments the plugin supports. However, thinking about it further, you'd probably want to keep these plugins separate, so have a But if we want to support React Native in the future we'd probably want to start naming plugins to reflect that they only work in React and not in React Native |
@bryanph thank you for taking the time to write that up! I really appreciate it. Those are great questions, I'll try to answer each one...
Good question. This would unlock a few different things:
I think that is it. But it also is about cleaning up the model distinctions that currently make the codebase confusing, and that limit it from achieving things in the future.
Written up above, but it comes down to adding "commands" and "queries" for this.
Essentially, yes. Except I'm thinking about trying to make it more transparent, such that all of the commands are exposed as first-class methods on the But I think it would be good to expose
This one is tricky. It defines what shape the document (and later ideally the selection too) can take. But it isn't necessarily part of the model so much as a constraint that is applied to the model. It leads to confusion if a value can have a Instead, if the
These are good points. I think we're not quite close enough to seeing what React Native, or what Vue support looks like to make a decision. But it could very well be that we end up separating the fields out by environment if we need to. Same for the plugin naming. Until we get closer though I think it's safe to keep them as-is. How does all that sound? |
Shall we have |
@zhujinxuan yup! Currently I've got the |
Some more thoughts, as a result of sketching some of this out with code... We have the concepts of It could also be solved by allowing plugins to answer queries, and you'd achieve the same functionality. Not necessarily that that's better, because it might be more of a hassle to write, but it's just an observation of an existing code path that could be eliminated. Further, you can actually model the existing |
Do you want to request a feature or report a bug?
Discussion.
What's the current behavior?
Just opening this up for discussion, since it's something that I think Slate hasn't really solved well so far, and leads to it being hard to decide in either direction for the API...
Right now there are two concepts vying for the "top spot" in the architecture:
value
— which holds the document, the selection, the history and the schema. This can easily be created server-side (or wherever), since it's not coupled to the view layer at all. (I'd considerchange
to be equivalent tovalue
here, since they hold all the same data.)editor
— which holds the plugins, the current value, and the schema to an extent. This is less easy to use server-side, since the editor is inherently tied to the view layer. (Although this need not always be the case.)So far, it's been unclear which is the "primary" concept. For example...
Event handlers are passed both a
change
and aneditor
to allow the user to decide which they want to use. You normally use thechange
, but sometimes, for example if you want to trigger an async change later, you need to use theeditor
.For the idea of "commands and queries" from consider adding a "commands" concept #2066, it's unclear whether these commands should live inside the schema (or similar) and be exposed as
change.command(...)
. Or whether, since they are tied to the plugins, they should be exposed aseditor.command(...)
. Both have tradeoffs.You could make the argument that
history
shouldn't really be inside thevalue
, and instead be controlled by theeditor
which is the long-lived entity—which would seem totally reasonable to me.Right now there's a confusion in that the editor's plugins create a final
schema
object that gets set on thevalue
. But the value can also be initialized with its ownschema
, which will be overwritten... and it's not clear how they interact.What's the expected behavior?
I'm not totally sure. This is something that I've wrestled with, but never found a nice mental model for being clear about the distinctions between the two. I'd love for anyone with ideas to comment! (Even if you aren't sure yourself, anything is helpful!)
I think it's helpful to have a few goals:
It would be good for "commands", "history", etc. to all be able to be modeled in server-side environments where there is no concept of the "view" layer. This doesn't necessarily mean it has to be the
value
model, but it has to be something that isn't tied to the DOM or rendering.It would be best if the top-level concept can unify the plugins, schema, history, commands, etc. in a way that makes it clear where all of this stuff stems from.
The text was updated successfully, but these errors were encountered: