mirror of
https://github.com/grafana/grafana.git
synced 2025-01-24 07:17:08 -06:00
Editor: Ignore closing brace when it was added by editor (#21172)
* Editor: Ignore closing brace when it was added by editor - brace completion gets annoying if the user still types closing brace - this change marks automatically added closing braces and when the user types a closing brace at that position, it will be overridden instead of added * Fix label suggestions * Correct brace behavior, but broken completion * Rewrite auto-match detection with annotations
This commit is contained in:
parent
74924c8284
commit
6ac53a1312
@ -18,7 +18,7 @@ describe('braces', () => {
|
||||
const value = Plain.deserialize('');
|
||||
const editor = shallow<Editor>(<Editor value={value} />);
|
||||
const event = new window.KeyboardEvent('keydown', { key: '(' });
|
||||
handler(event as Event, editor.instance() as any, nextMock);
|
||||
expect(handler(event as Event, editor.instance() as any, nextMock)).toBeTruthy();
|
||||
expect(Plain.serialize(editor.instance().value)).toEqual('()');
|
||||
});
|
||||
|
||||
@ -37,4 +37,24 @@ describe('braces', () => {
|
||||
const handled = handler(event as Event, editor.instance().moveForward(5) as any, nextMock);
|
||||
expect(handled).toBeFalsy();
|
||||
});
|
||||
|
||||
it('overrides an automatically inserted brace', () => {
|
||||
const value = Plain.deserialize('');
|
||||
const editor = shallow<Editor>(<Editor value={value} />);
|
||||
const opening = new window.KeyboardEvent('keydown', { key: '(' });
|
||||
expect(handler(opening as Event, editor.instance() as any, nextMock)).toBeTruthy();
|
||||
const closing = new window.KeyboardEvent('keydown', { key: ')' });
|
||||
expect(handler(closing as Event, editor.instance() as any, nextMock)).toBeTruthy();
|
||||
expect(Plain.serialize(editor.instance().value)).toEqual('()');
|
||||
});
|
||||
|
||||
it.skip('does not override manually inserted braces', () => {
|
||||
const value = Plain.deserialize('');
|
||||
const editor = shallow<Editor>(<Editor value={value} />);
|
||||
const event1 = new window.KeyboardEvent('keydown', { key: ')' });
|
||||
expect(handler(event1 as Event, editor.instance() as any, nextMock)).toBeFalsy();
|
||||
const event2 = new window.KeyboardEvent('keydown', { key: ')' });
|
||||
expect(handler(event2 as Event, editor.instance().moveBackward(1) as any, nextMock)).toBeFalsy();
|
||||
expect(Plain.serialize(editor.instance().value)).toEqual('))');
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Plugin } from '@grafana/slate-react';
|
||||
import { Editor as CoreEditor } from 'slate';
|
||||
import { Editor as CoreEditor, Annotation } from 'slate';
|
||||
|
||||
const BRACES: any = {
|
||||
'[': ']',
|
||||
@ -7,6 +7,8 @@ const BRACES: any = {
|
||||
'(': ')',
|
||||
};
|
||||
|
||||
const MATCH_MARK = 'brace_match';
|
||||
|
||||
export function BracesPlugin(): Plugin {
|
||||
return {
|
||||
onKeyDown(event: Event, editor: CoreEditor, next: Function) {
|
||||
@ -17,7 +19,6 @@ export function BracesPlugin(): Plugin {
|
||||
case '(':
|
||||
case '{':
|
||||
case '[': {
|
||||
keyEvent.preventDefault();
|
||||
const {
|
||||
start: { offset: startOffset, key: startKey },
|
||||
end: { offset: endOffset, key: endKey },
|
||||
@ -27,21 +28,67 @@ export function BracesPlugin(): Plugin {
|
||||
|
||||
// If text is selected, wrap selected text in parens
|
||||
if (value.selection.isExpanded) {
|
||||
keyEvent.preventDefault();
|
||||
editor
|
||||
.insertTextByKey(startKey, startOffset, keyEvent.key)
|
||||
.insertTextByKey(endKey, endOffset + 1, BRACES[keyEvent.key])
|
||||
.moveEndBackward(1);
|
||||
return true;
|
||||
} else if (
|
||||
// Insert matching brace when there is no input after caret
|
||||
focusOffset === text.length ||
|
||||
text[focusOffset] === ' ' ||
|
||||
Object.values(BRACES).includes(text[focusOffset])
|
||||
) {
|
||||
editor.insertText(`${keyEvent.key}${BRACES[keyEvent.key]}`).moveBackward(1);
|
||||
} else {
|
||||
editor.insertText(keyEvent.key);
|
||||
}
|
||||
keyEvent.preventDefault();
|
||||
const complement = BRACES[keyEvent.key];
|
||||
const matchAnnotation = {
|
||||
key: `${MATCH_MARK}-${Date.now()}`,
|
||||
type: `${MATCH_MARK}-${complement}`,
|
||||
anchor: {
|
||||
key: startKey,
|
||||
offset: startOffset,
|
||||
object: 'point',
|
||||
},
|
||||
focus: {
|
||||
key: endKey,
|
||||
offset: endOffset + 1,
|
||||
object: 'point',
|
||||
},
|
||||
object: 'annotation',
|
||||
} as Annotation;
|
||||
editor
|
||||
.insertText(keyEvent.key)
|
||||
.insertText(complement)
|
||||
.addAnnotation(matchAnnotation)
|
||||
.moveBackward(1);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ')':
|
||||
case '}':
|
||||
case ']': {
|
||||
const text = value.anchorText.text;
|
||||
const offset = value.selection.anchor.offset;
|
||||
const nextChar = text[offset];
|
||||
// Handle closing brace when it's already the next character
|
||||
const complement = keyEvent.key;
|
||||
const annotationType = `${MATCH_MARK}-${complement}`;
|
||||
const annotation = value.annotations.find(
|
||||
a => a?.type === annotationType && a.anchor.key === value.anchorText.key
|
||||
);
|
||||
if (annotation && nextChar === complement && !value.selection.isExpanded) {
|
||||
keyEvent.preventDefault();
|
||||
editor
|
||||
.moveFocusForward(1)
|
||||
.removeAnnotation(annotation)
|
||||
.moveAnchorForward(1);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Backspace': {
|
||||
|
Loading…
Reference in New Issue
Block a user