docs/research/systems/editor-behavior-architecture.md
This is the architectural frame for the major release. It is intentionally written before the full Typora and Milkdown audit so the repo does not drift into reference-chasing without a model.
The goal is not "make Plate behave like Typora." The goal is stronger:
Plate should move from a plugin-scattered behavior model to a profile-driven behavior engine.
That means:
Examples:
markdown_typoramarkdown_milkdownnotionbeargoogle_docsplate_defaultThe markdown-first profile is the first lane, not the final personality.
Today behavior ownership is fragmented:
Enter and reset behaviorTabTab and movementEnter and TabThat architecture is fine for local fixes and bad for editor emulation.
If Plate wants to clone major editors cleanly, behavior has to become an explicit system.
This major should prefer breaking cleanup over feature expansion.
That means:
If a proposed addition does not improve an existing broken seam, it is probably the wrong use of major-release energy.
Plate's node model should remain shared. The behavior profile decides how users reach and modify that structure.
When multiple structures could own a key event, the nearest structural owner should win first. Example order:
Do not collapse multiple container levels in one step unless a profile explicitly wants that.
If Markdown has a real structural representation, Plate should prefer that over visual-only shortcuts or local fake structure.
Plugins should provide transforms, queries, and normalization primitives. Profiles should decide which primitive wins for a given editing context.
Behavior should be organized into domains instead of spread across unrelated plugin overrides.
Owns:
EnterBackspace at block startDelete at block endTabShift+TabOwns:
Owns:
Owns:
Owns:
These should become reusable transforms, not bespoke one-off plugin tricks.
Owns:
This should be a shared editor-scoped primitive, not one flash hack per feature. TOC, footnote, and search jumps should all reuse it.
A profile should declare behavior policy by domain:
type BehaviorProfileId =
| 'markdown_typora'
| 'markdown_milkdown'
| 'notion'
| 'bear'
| 'google_docs'
| 'plate_default';
interface EditorBehaviorProfile {
id: BehaviorProfileId;
structuralKeys: StructuralKeyPolicy;
selection: SelectionPolicy;
autoformat: AutoformatPolicy;
streaming: StreamingPolicy;
}
Every behavior decision should operate on a normalized context snapshot instead of each plugin re-deriving the same state:
Resolvers should return explicit outcomes:
handledfallthroughprevent_defaulttransformselectrejectThat beats today's mix of silent overrides and implicit fallback.
For structural keys, Plate should use a single behavior pipeline:
This is the seam that should replace scattered local ownership.
Affinity should be part of behavior policy, not a separate oddball concern.
That means:
Example:
If affinity remains disconnected from the editing spec, it will keep drifting.
Autoformat should stop being "a list of trigger strings that happen to mutate nodes."
It should become behavior-aware:
Examples:
> in markdown-first mode should wrap a quote container, not retag a text
blockThe rewrite target is not "more rules." It is "the right transform selected by profile and context."
These are likely high-leverage additions:
exitContainerLevelliftContainerLevelsplitContainerAroundSelectionresetNearestStructurewrapBlocksInContainerunwrapCurrentContainerLevelThese should work across quote, list, toggle, and future container blocks where possible.
This architecture doc is the top-level frame.
Later, other profiles can layer on the same architecture with different behavior decisions.
Tests should be keyed to spec IDs, not just file-local descriptions.
Each important rule should have:
The same scenario may have different expected outputs across profiles. That is a feature, not a bug, as long as the profile owns the difference explicitly.
This major release is the right time to break behavior toward clearer standards.
Expected candidates:
Tab ownership away from broad indent behavior