Skip to content

Commit

Permalink
Add an inlineOrder option for block widget decorations
Browse files Browse the repository at this point in the history
FEATURE: Block widget decorations can now be given an `inlineOrder` option to make
them appear in the same ordering as surrounding inline widgets.

Issue codemirror/dev#1165
  • Loading branch information
marijnh committed Jun 20, 2023
1 parent 45d73f6 commit c77629d
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 5 deletions.
15 changes: 10 additions & 5 deletions src/decoration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,14 @@ interface WidgetDecorationSpec {
/// values will determine their ordering—those with a lower value
/// come first. Defaults to 0. May not be more than 10000 or less
/// than -10000.
///
/// Block widgets are always drawn before inline widgets when side
/// is non-positive, and after them when side is positive,
/// regardless of the value of `side`.
side?: number
/// By default, to avoid unintended mixing of block and inline
/// widgets, block widgets with a positive `side` are always drawn
/// after all inline widgets at that position, and those with a
/// non-positive side before inline widgets. Setting this option to
/// `true` for a block widget will turn this off and cause it to be
/// rendered between the inline widgets, ordered by `side`.
inlineOrder?: boolean
/// Determines whether this is a block widgets, which will be drawn
/// between lines, or an inline widget (the default) which is drawn
/// between the surrounding text.
Expand Down Expand Up @@ -226,7 +229,9 @@ export abstract class Decoration extends RangeValue {
/// given position.
static widget(spec: WidgetDecorationSpec): Decoration {
let side = Math.max(-10000, Math.min(10000, spec.side || 0)), block = !!spec.block
side += block ? (side > 0 ? Side.BlockAfter : Side.BlockBefore) : (side > 0 ? Side.InlineAfter : Side.InlineBefore)
side += (block && !spec.inlineOrder)
? (side > 0 ? Side.BlockAfter : Side.BlockBefore)
: (side > 0 ? Side.InlineAfter : Side.InlineBefore)
return new PointDecoration(spec, side, side, block, spec.widget || null, false)
}

Expand Down
28 changes: 28 additions & 0 deletions test/webtest-draw-decoration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,34 @@ describe("EditorView decoration", () => {
]})
ist(destroyed.sort().join(), "A")
})

it("can show inline and block widgets next to each other after a position", () => {
let cm = tempView("xy", [decos(Decoration.set([
w(1, new WordWidget("A"), 1),
Decoration.widget({widget: new BlockWidget("B"), block: true, side: 2, inlineOrder: true}).range(1),
w(1, new WordWidget("C"), 3),
]))])
let [a, c] = Array.from(cm.contentDOM.querySelectorAll("strong"))
let b = cm.contentDOM.querySelector("hr")!
ist(a.parentNode, cm.contentDOM.firstChild)
ist(c.parentNode, cm.contentDOM.lastChild)
ist(b.previousSibling, a.parentNode)
ist(b.nextSibling, c.parentNode)
})

it("can show inline and block widgets next to each other before a position", () => {
let cm = tempView("xy", [decos(Decoration.set([
w(1, new WordWidget("A"), -3),
Decoration.widget({widget: new BlockWidget("B"), block: true, side: -2, inlineOrder: true}).range(1),
w(1, new WordWidget("C"), -2),
]))])
let [a, c] = Array.from(cm.contentDOM.querySelectorAll("strong"))
let b = cm.contentDOM.querySelector("hr")!
ist(a.parentNode, cm.contentDOM.firstChild)
ist(c.parentNode, cm.contentDOM.lastChild)
ist(b.previousSibling, a.parentNode)
ist(b.nextSibling, c.parentNode)
})
})

function r(from: number, to: number, spec: any = {}) { return Decoration.replace(spec).range(from, to) }
Expand Down

0 comments on commit c77629d

Please sign in to comment.