ProseMirror / prosemirror

The ProseMirror WYSIWYM editor
http://prosemirror.net/
MIT License
7.59k stars 335 forks source link

Feature: ability to control the wrapping order of multiple inline decorations #1411

Closed bradleyayers closed 1 year ago

bradleyayers commented 1 year ago

In our editor we sometimes have multiple inline decorations that overlap, and they compete for setting styles. Specifically, one inline decoration is for "highlights", and another is for "text selection", and both compete for settings box-shadow.

We have a patch that allows sortKey to be added to the spec, and then honored when applying decorations.

Here's our current patch:

diff --git a/dist/index.cjs b/dist/index.cjs
index f4ec8db2d5ce5e490f83e4d8636ed5f9ee0238f2..28b437e1ccc0af9fc8b692e6c59a7e1d5a5f50b0 100644
--- a/dist/index.cjs
+++ b/dist/index.cjs
@@ -1883,9 +1883,12 @@ var OuterDecoLevel = function OuterDecoLevel(nodeName) {

 OuterDecoLevel.prototype = Object.create(null);
 var noDeco = [new OuterDecoLevel()];
-
+function compareOuterDeco(a, b) {
+  return a.spec.sortKey < b.spec.sortKey ? 1 : a.spec.sortKey > b.spec.sortKey ? -1 : 0;
+}
 function computeOuterDeco(outerDeco, node, needsWrap) {
   if (outerDeco.length == 0) return noDeco;
+  outerDeco = outerDeco.length > 1 ? outerDeco.concat().sort(compareOuterDeco) : outerDeco;
   var top = needsWrap ? noDeco[0] : new OuterDecoLevel(),
       result = [top];

We then use it like this:

decorations.push(
  Decoration.inline(
    from,
    to,
    { nodeName: `dvtl-range-comment` },
    { sortKey: InlineDecorationZIndex.RANGE_COMMENT },
  ),
);

I wanted to see if this was something you think makes sense to upstream, or if there's an alternative solution.

marijnh commented 1 year ago

Doesn't the plugin order already provide a way to control the order in which decorations are applied?

bradleyayers commented 1 year ago

That would make sense, I'll close this and investigate that. Thanks!