Skip to content

Commit e95e90e

Browse files
authored
fix(selection): clear editor highlight when selection chip is deleted (#93)
Clicking the X on a captured selection chip removes the token from the composer input. The SelectionController noticed this and dropped the stored selection, but it forgot to clear the mock highlight shown in the editor (or preview CSS highlight). The highlight would linger because storedSelection was already null by the time any cleanup ran. Call clearHighlight() before nulling storedSelection so the CM6/CSS highlight is removed together with the chip.
1 parent 7a5df79 commit e95e90e

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

‎src/features/chat/controllers/selection-controller.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ export class SelectionController {
438438
if (this.storedToken) {
439439
if (!value.includes(this.storedToken)) {
440440
const stale = this.storedToken;
441+
this.clearHighlight();
441442
this.storedToken = null;
442443
this.storedSelection = null;
443444
this.tokenSink.unregister(stale);

‎tests/unit/features/chat/controllers/selection-controller.test.ts‎

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ describe('SelectionController', () => {
157157
expect(showSelectionHighlight).toHaveBeenCalledWith(editorView, 0, 4);
158158
});
159159

160-
it('drops the stored selection when the token is removed from the input', () => {
160+
it('drops the stored selection and clears the highlight when the token is removed from the input', () => {
161161
controller.start();
162162
jest.advanceTimersByTime(250);
163163
expect(controller.hasSelection()).toBe(true);
@@ -167,6 +167,7 @@ describe('SelectionController', () => {
167167

168168
expect(controller.hasSelection()).toBe(false);
169169
expect(tokenSink.unregister).toHaveBeenCalledWith(SOURCE_TOKEN);
170+
expect(hideSelectionHighlight).toHaveBeenCalledWith(editorView);
170171
});
171172

172173
it('collapses the editor selection on send so the chip does not come back', () => {
@@ -606,6 +607,29 @@ describe('SelectionController', () => {
606607
expect(mockHighlights.delete).toHaveBeenCalledWith('qoderian-selection');
607608
});
608609

610+
it('clears CSS highlight when the selection chip token is removed in reading mode', () => {
611+
const anchorNode = {};
612+
(global as any).document = {
613+
activeElement: null,
614+
getSelection: jest.fn().mockReturnValue(
615+
createMockDOMSelection('reading selection', anchorNode),
616+
),
617+
};
618+
const mockHighlights = { set: jest.fn(), delete: jest.fn() };
619+
(global as any).CSS = { highlights: mockHighlights };
620+
621+
controller.start();
622+
jest.advanceTimersByTime(250);
623+
expect(controller.hasSelection()).toBe(true);
624+
625+
inputEl.value = '';
626+
inputEl.dispatchEvent(new Event('input', { bubbles: true }));
627+
628+
expect(controller.hasSelection()).toBe(false);
629+
expect(tokenSink.unregister).toHaveBeenCalledWith('@notes/reading.md');
630+
expect(mockHighlights.delete).toHaveBeenCalledWith('qoderian-selection');
631+
});
632+
609633
it('skips CSS highlight for disconnected DOM ranges', () => {
610634
const anchorNode = {};
611635
const mockSel = createMockDOMSelection('reading selection', anchorNode);

0 commit comments

Comments
 (0)