remove decoration

const highlight_effect = StateEffect.define(); 
const highlight_extension = StateField.define({
  create() { return Decoration.none },
  update(value, transaction) {
    value = value.map(transaction.changes)

    for (let effect of transaction.effects) {
      if (effect.is(highlight_effect)) value = value.update({add: effect.value, sort: true})
    }

    return value
  },
  provide: f => EditorView.decorations.from(f)
});
highlight_decoration = cm6.Decoration.mark({
  class: 'red_back'
});
			  view.dispatch({
  effects: cm6.highlight_effect.of([highlight_decoration.range(cursor.value.from, cursor.value.to)])
});

I have code above and trying to remove the decoration/style, how to do so?

Thanks

2 Likes

You’ll probably want to define another state effect that removes decorations, and check for that as well in your loop over transaction.effects, calling value.update with a filter option that removes the appropriate range.

1 Like

I am also trying to understand how this is done. I adapted the code from Decorations, which works well to apply styling to a custom range. But I am having trouble removing the styling when I am done with it. Is something like this what you had in mind with regard to applying a filter update?

const addStyling = StateEffect.define({
  map: ({ from, to }, change) => ({ from: change.mapPos(from), to: change.mapPos(to) })
});
  
const removeStyling = StateEffect.define({
  map: ({ from, to }, change) => ({ from: change.mapPos(from), to: change.mapPos(to) })
});

const styleMark = Decoration.mark({class: "cm-suggestion"});

  const suggestionTheme = EditorView.baseTheme({
    "&dark span.cm-suggestion": {opacity: "0.75" }
  });

const styleField = StateField.define({
  create() {
    return Decoration.none;
  },
  update(ranges, transaction) {
    ranges = ranges.map(transaction.changes);
    for (let effect of transaction.effects) { 
      if (effect.is(addStyling)) {
        ranges = ranges.update({
          add: [styleMark.range(effect.value.from, effect.value.to)]
        });
      }
      else if (effect.is(removeStyling)) {
        ranges = ranges.update({
          filter: spec => spec.type != styleMark
        });
      }
    }
    return value;
  },
  provide: f => EditorView.decorations.from(f)
});

const styleSelection = (view, ranges = {}) => {
  if (ranges.empty) {
    ranges = view.state.selection.main;
  }
  let effects = ranges
      .filter(range => !range.empty)
      .map(({from, to}) => addStyling.of({from, to}));
    if (!effects.length) {
      return false;
    }
    if (!view.state.field(styleField, false)) {
      effects.push(StateEffect.appendConfig.of([styleField, suggestionTheme]));
    }
    view.dispatch({effects});
    return true;
}

view.dispatch({
  effects: [removeStyling.of(0, view.state.doc.length)]
});

That code puts a from and to in the removeStyling effect but then ignores them and removes all decorations from the set (since from what I can see they will all be using styleMark. Are you trying to clear it? In which case you can just set it to Decoration.none. Or are you trying to clear a specific range? If so, you’ll want to actually compare the ranges to the from and to values in the effect.

2 Likes

I do want to clear a specific range ideally. Though I am not sure how to store the range of the original effect that was used to set the style in the first place. To be clear, I am not seeking to undo the last transaction, but merely capture the range of the last transaction and remove its styling. Can I store the range in the EditorState and retrieve it later?

You can, if you define a StateField for it. But you can also iterate over the ranges in the set, if you can somehow recognize the proper one. I still have no idea what you are trying to implement so I can’t say a lot about this.

I think I figured it out. I just misunderstood the documentation. Sorry to be a bother. Basically, I was just trying to implement a styled inline suggestion that could be confirmed or rejected.