Does selection.assoc play role when updating state?

I have a Decoration that is injected at a certain position:

const someMatcher = new MatchDecorator({
  regexp: someRegexp,
  decorate: (add, from, to, match, view) => {
    const widget = new SomeWidget()
    add(from, from, Decoration.replace({
      widget,
    }))
  }
})

Notice that in fact I’m not replacing the found range, but inject the widget before this range: add(from, from, ...

When I move cursor around this widget, it always occurs before the widget and never after.

And I need the cursor to be after and never before. So I’m listening for the selection change, detecting if the cursor stays at the position of the widget injection, and reseting the selection using assoc: 1 which, if I read the docs correctly, encodes the cursor position after the selected character.

EditorView.updateListener.of((viewUpdate) => {
  let selection = viewUpdate.state.selection.main
  if (selection.anchor === widgetPos && selection.head === widgetPos && selection.assoc !== 1) {
    const { state, dispatch } = viewUpdate;
    const newState = state.update({
      selection: {
        anchor: widgetPos,
        head: widgetPos,
        assoc: 1
      }
    });
    dispatch(newState);  
  }
}),

But it does nothing. Should it work or do I completely misunderstand the way assoc is meant to be used?

You’ll want to use the side option to Decoration.widget. A cursor’s assoc breaks ties on line wrap points and bidirectional jumps, but widgets have a strict side relative to the cursor, which isn’t influenced by assoc.

Awesome, thank you!