Skip to content

Commit 3b5b029

Browse files
committed
Enhance updateFormats to preserve editor-only formats when caret is inside an annotation. Updated function parameters to include preserveEditorOnlyFormatsFrom, ensuring annotations grow with newly typed text only when applicable. Improved event listener logic to determine annotation presence before typing.
1 parent d4bba0c commit 3b5b029

File tree

2 files changed

+50
-24
lines changed

2 files changed

+50
-24
lines changed

packages/rich-text/src/component/event-listeners/input-and-selection.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,25 @@ export default ( props ) => ( element ) => {
8888
const currentValue = createRecord();
8989
const { start, activeFormats: oldActiveFormats = [] } = record.current;
9090

91+
// Determine if the caret was inside an annotation before typing by checking
92+
// the OLD record's formats at the caret position. We only preserve annotations
93+
// when the caret was inside one before typing, so typing past the annotation
94+
// won't extend it.
95+
const oldFormatsAtCaret =
96+
record.current.formats && record.current.formats[ start ]
97+
? record.current.formats[ start ]
98+
: [];
99+
const preserveEditorOnlyFormatsFrom = oldFormatsAtCaret.filter(
100+
( format ) => format?.type === 'core/annotation'
101+
);
102+
91103
// Update the formats between the last and new caret position.
92-
// updateFormats will filter out editor-only formats (like annotations)
93-
// from activeFormats and preserve them from the formats array instead.
94104
const change = updateFormats( {
95105
value: currentValue,
96106
start,
97107
end: currentValue.start,
98108
formats: oldActiveFormats,
109+
preserveEditorOnlyFormatsFrom,
99110
} );
100111

101112
handleChange( change );

packages/rich-text/src/update-formats.js

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,22 @@ import { isFormatEqual } from './is-format-equal';
1010
* Efficiently updates all the formats from `start` (including) until `end`
1111
* (excluding) with the active formats. Mutates `value`.
1212
*
13-
* @param {Object} $1 Named paramentes.
14-
* @param {RichTextValue} $1.value Value te update.
15-
* @param {number} $1.start Index to update from.
16-
* @param {number} $1.end Index to update until.
17-
* @param {Array} $1.formats Replacement formats.
13+
* @param {Object} $1 Named parameters.
14+
* @param {RichTextValue} $1.value Value to update.
15+
* @param {number} $1.start Index to update from.
16+
* @param {number} $1.end Index to update until.
17+
* @param {Array} $1.formats Replacement formats.
18+
* @param {Array} $1.preserveEditorOnlyFormatsFrom Formats that were active at the caret before typing.
1819
*
1920
* @return {RichTextValue} Mutated value.
2021
*/
21-
export function updateFormats( { value, start, end, formats } ) {
22+
export function updateFormats( {
23+
value,
24+
start,
25+
end,
26+
formats,
27+
preserveEditorOnlyFormatsFrom = [],
28+
} ) {
2229
// Start and end may be switched in case of delete.
2330
const min = Math.min( start, end );
2431
const max = Math.max( start, end );
@@ -48,24 +55,32 @@ export function updateFormats( { value, start, end, formats } ) {
4855
return format;
4956
} );
5057

51-
// Preserve editor-only formats (like annotations) from surrounding positions
52-
// when typing, so annotations grow to include newly typed text.
53-
const annotationFormatsBefore = formatsBefore.filter(
54-
( format ) => format.type === 'core/annotation'
55-
);
56-
const annotationFormatsAfter = formatsAfter.filter(
58+
const wasInsideAnnotation = preserveEditorOnlyFormatsFrom.some(
5759
( format ) => format.type === 'core/annotation'
5860
);
59-
// Merge annotation formats from both positions, preferring formatsAfter.
60-
const annotationFormats = [
61-
...annotationFormatsAfter,
62-
...annotationFormatsBefore.filter(
63-
( format ) =>
64-
! annotationFormatsAfter.find( ( f ) =>
65-
isFormatEqual( f, format )
66-
)
67-
),
68-
];
61+
62+
// Preserve editor-only formats (like annotations) from surrounding positions
63+
// when typing, so annotations grow to include newly typed text. Only do this
64+
// when the caret was inside an annotation before typing.
65+
let annotationFormats = [];
66+
if ( wasInsideAnnotation ) {
67+
const annotationFormatsBefore = formatsBefore.filter(
68+
( format ) => format.type === 'core/annotation'
69+
);
70+
const annotationFormatsAfter = formatsAfter.filter(
71+
( format ) => format.type === 'core/annotation'
72+
);
73+
// Merge annotation formats from both positions, preferring formatsAfter.
74+
annotationFormats = [
75+
...annotationFormatsAfter,
76+
...annotationFormatsBefore.filter(
77+
( format ) =>
78+
! annotationFormatsAfter.find( ( f ) =>
79+
isFormatEqual( f, format )
80+
)
81+
),
82+
];
83+
}
6984

7085
while ( --end >= start ) {
7186
if ( value.activeFormats.length > 0 || annotationFormats.length > 0 ) {

0 commit comments

Comments
 (0)