@@ -19,6 +19,14 @@ export interface TextEqualsOptions {
19
19
loose ?: boolean
20
20
}
21
21
22
+ export type DecoratedRange = Range & {
23
+ /**
24
+ * Customize how another decoration is merged into a text node. If not specified, `Object.assign` would be used.
25
+ * It is useful for overlapping decorations with the same key but different values.
26
+ */
27
+ merge ?: ( leaf : Text , decoration : object ) => void
28
+ }
29
+
22
30
export interface TextInterface {
23
31
/**
24
32
* Check if two text nodes are equal.
@@ -54,7 +62,7 @@ export interface TextInterface {
54
62
/**
55
63
* Get the leaves for a text node given decorations.
56
64
*/
57
- decorations : ( node : Text , decorations : Range [ ] ) => Text [ ]
65
+ decorations : ( node : Text , decorations : DecoratedRange [ ] ) => Text [ ]
58
66
}
59
67
60
68
// eslint-disable-next-line no-redeclare
@@ -103,16 +111,17 @@ export const Text: TextInterface = {
103
111
return true
104
112
} ,
105
113
106
- decorations ( node : Text , decorations : Range [ ] ) : Text [ ] {
114
+ decorations ( node : Text , decorations : DecoratedRange [ ] ) : Text [ ] {
107
115
let leaves : Text [ ] = [ { ...node } ]
108
116
109
117
for ( const dec of decorations ) {
110
- const { anchor, focus, ...rest } = dec
118
+ const { anchor, focus, merge : mergeDecoration , ...rest } = dec
111
119
const [ start , end ] = Range . edges ( dec )
112
120
const next = [ ]
113
121
let leafEnd = 0
114
122
const decorationStart = start . offset
115
123
const decorationEnd = end . offset
124
+ const merge = mergeDecoration ?? Object . assign
116
125
117
126
for ( const leaf of leaves ) {
118
127
const { length } = leaf . text
@@ -121,7 +130,7 @@ export const Text: TextInterface = {
121
130
122
131
// If the range encompasses the entire leaf, add the range.
123
132
if ( decorationStart <= leafStart && leafEnd <= decorationEnd ) {
124
- Object . assign ( leaf , rest )
133
+ merge ( leaf , rest )
125
134
next . push ( leaf )
126
135
continue
127
136
}
@@ -157,7 +166,7 @@ export const Text: TextInterface = {
157
166
middle = { ...middle , text : middle . text . slice ( off ) }
158
167
}
159
168
160
- Object . assign ( middle , rest )
169
+ merge ( middle , rest )
161
170
162
171
if ( before ) {
163
172
next . push ( before )
0 commit comments