Chore: Update slate and related packages (#54566)
* Chore: Update slate and related packages
This commit is contained in:
@@ -174,7 +174,7 @@ const getBaseWebpackConfig: WebpackConfigurationGetter = async (options) => {
|
||||
'@emotion/css',
|
||||
'prismjs',
|
||||
'slate-plain-serializer',
|
||||
'@grafana/slate-react',
|
||||
'slate-react',
|
||||
'react',
|
||||
'react-dom',
|
||||
'react-redux',
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
"@grafana/data": "9.2.0-pre",
|
||||
"@grafana/e2e-selectors": "9.2.0-pre",
|
||||
"@grafana/schema": "9.2.0-pre",
|
||||
"@grafana/slate-react": "0.22.10-grafana",
|
||||
"@monaco-editor/react": "4.4.5",
|
||||
"@popperjs/core": "2.11.5",
|
||||
"@react-aria/button": "3.6.1",
|
||||
@@ -97,8 +96,9 @@
|
||||
"react-use": "17.4.0",
|
||||
"react-window": "1.8.7",
|
||||
"rxjs": "7.5.6",
|
||||
"slate": "0.47.8",
|
||||
"slate-plain-serializer": "0.7.10",
|
||||
"slate": "0.47.9",
|
||||
"slate-plain-serializer": "0.7.11",
|
||||
"slate-react": "0.22.10",
|
||||
"tinycolor2": "1.4.2",
|
||||
"tslib": "2.4.0",
|
||||
"uplot": "1.6.22",
|
||||
@@ -135,7 +135,6 @@
|
||||
"@types/d3": "7.4.0",
|
||||
"@types/enzyme": "3.10.12",
|
||||
"@types/enzyme-adapter-react-16": "1.0.6",
|
||||
"@types/grafana__slate-react": "npm:@types/slate-react@0.22.5",
|
||||
"@types/hoist-non-react-statics": "3.3.1",
|
||||
"@types/is-hotkey": "0.1.7",
|
||||
"@types/jest": "28.1.6",
|
||||
@@ -155,8 +154,9 @@
|
||||
"@types/react-test-renderer": "17.0.1",
|
||||
"@types/react-transition-group": "4.4.5",
|
||||
"@types/react-window": "1.8.5",
|
||||
"@types/slate": "0.47.2",
|
||||
"@types/slate": "0.47.9",
|
||||
"@types/slate-plain-serializer": "0.7.2",
|
||||
"@types/slate-react": "0.22.9",
|
||||
"@types/testing-library__jest-dom": "5.14.5",
|
||||
"@types/testing-library__react-hooks": "^3.2.0",
|
||||
"@types/tinycolor2": "1.4.3",
|
||||
|
||||
@@ -5,9 +5,9 @@ import { Popper as ReactPopper } from 'react-popper';
|
||||
import usePrevious from 'react-use/lib/usePrevious';
|
||||
import { Value } from 'slate';
|
||||
import Plain from 'slate-plain-serializer';
|
||||
import { Editor } from 'slate-react';
|
||||
|
||||
import { DataLinkBuiltInVars, GrafanaTheme2, VariableOrigin, VariableSuggestion } from '@grafana/data';
|
||||
import { Editor } from '@grafana/slate-react';
|
||||
|
||||
import { makeValue } from '../../index';
|
||||
import { SlatePrism } from '../../slate-plugins';
|
||||
@@ -95,7 +95,7 @@ export const DataLinkInput: React.FC<DataLinkInputProps> = memo(
|
||||
// SelectionReference is used to position the variables suggestion relatively to current DOM selection
|
||||
const selectionRef = useMemo(() => new SelectionReference(), []);
|
||||
|
||||
const onKeyDown = React.useCallback((event: KeyboardEvent, next: () => any) => {
|
||||
const onKeyDown = React.useCallback((event: React.KeyboardEvent, next: () => any) => {
|
||||
if (!stateRef.current.showingSuggestions) {
|
||||
if (event.key === '=' || event.key === '$' || (event.keyCode === 32 && event.ctrlKey)) {
|
||||
return setShowingSuggestions(true);
|
||||
@@ -208,7 +208,7 @@ export const DataLinkInput: React.FC<DataLinkInputProps> = memo(
|
||||
placeholder={placeholder}
|
||||
value={stateRef.current.linkUrl}
|
||||
onChange={onUrlChange}
|
||||
onKeyDown={(event, _editor, next) => onKeyDown(event as KeyboardEvent, next)}
|
||||
onKeyDown={(event, _editor, next) => onKeyDown(event, next)}
|
||||
plugins={plugins}
|
||||
className={cx(
|
||||
styles.editor,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { shallow } from 'enzyme';
|
||||
import { mount, shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { Editor } from 'slate';
|
||||
import { Editor } from 'slate-react';
|
||||
|
||||
import { createTheme } from '@grafana/data';
|
||||
|
||||
@@ -30,7 +30,7 @@ describe('<QueryField />', () => {
|
||||
|
||||
it('should execute query on blur', () => {
|
||||
const onRun = jest.fn();
|
||||
const wrapper = shallow(
|
||||
const wrapper = mount(
|
||||
<UnThemedQueryField
|
||||
theme={createTheme()}
|
||||
query="my query"
|
||||
@@ -40,8 +40,9 @@ describe('<QueryField />', () => {
|
||||
/>
|
||||
);
|
||||
const field = wrapper.instance() as UnThemedQueryField;
|
||||
const ed = wrapper.find(Editor).instance() as Editor;
|
||||
expect(onRun.mock.calls.length).toBe(0);
|
||||
field.handleBlur(new Event('bogus'), new Editor({}), () => {});
|
||||
field.handleBlur(undefined, ed, () => {});
|
||||
expect(onRun.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
@@ -65,7 +66,7 @@ describe('<QueryField />', () => {
|
||||
it('should run custom on blur, but not necessarily execute query', () => {
|
||||
const onBlur = jest.fn();
|
||||
const onRun = jest.fn();
|
||||
const wrapper = shallow(
|
||||
const wrapper = mount(
|
||||
<UnThemedQueryField
|
||||
theme={createTheme()}
|
||||
query="my query"
|
||||
@@ -76,9 +77,10 @@ describe('<QueryField />', () => {
|
||||
/>
|
||||
);
|
||||
const field = wrapper.instance() as UnThemedQueryField;
|
||||
const ed = wrapper.find(Editor).instance() as Editor;
|
||||
expect(onBlur.mock.calls.length).toBe(0);
|
||||
expect(onRun.mock.calls.length).toBe(0);
|
||||
field.handleBlur(new Event('bogus'), new Editor({}), () => {});
|
||||
field.handleBlur(undefined, ed, () => {});
|
||||
expect(onBlur.mock.calls.length).toBe(1);
|
||||
expect(onRun.mock.calls.length).toBe(0);
|
||||
});
|
||||
|
||||
@@ -2,12 +2,12 @@ import { css, cx } from '@emotion/css';
|
||||
import classnames from 'classnames';
|
||||
import { debounce } from 'lodash';
|
||||
import React, { Context, PureComponent } from 'react';
|
||||
import { Value, Editor as CoreEditor } from 'slate';
|
||||
import { Value } from 'slate';
|
||||
import Plain from 'slate-plain-serializer';
|
||||
import { Editor, Plugin } from 'slate-react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { Editor, Plugin } from '@grafana/slate-react';
|
||||
|
||||
import {
|
||||
makeValue,
|
||||
@@ -42,7 +42,7 @@ export interface QueryFieldProps extends Themeable2 {
|
||||
onBlur?: () => void;
|
||||
onChange?: (value: string) => void;
|
||||
onRichValueChange?: (value: Value) => void;
|
||||
onClick?: (event: Event, editor: CoreEditor, next: () => any) => any;
|
||||
onClick?: (event: Event | React.MouseEvent, editor: Editor, next: () => any) => any;
|
||||
onTypeahead?: (typeahead: TypeaheadInput) => Promise<TypeaheadOutput>;
|
||||
onWillApplySuggestion?: (suggestion: string, state: SuggestionsState) => string;
|
||||
placeholder?: string;
|
||||
@@ -67,7 +67,7 @@ export interface QueryFieldState {
|
||||
* Implement props.onTypeahead to use suggestions, see PromQueryField.tsx as an example.
|
||||
*/
|
||||
export class UnThemedQueryField extends PureComponent<QueryFieldProps, QueryFieldState> {
|
||||
plugins: Plugin[];
|
||||
plugins: Array<Plugin<Editor>>;
|
||||
runOnChangeDebounced: Function;
|
||||
lastExecutedValue: Value | null = null;
|
||||
mounted = false;
|
||||
@@ -185,7 +185,7 @@ export class UnThemedQueryField extends PureComponent<QueryFieldProps, QueryFiel
|
||||
/**
|
||||
* We need to handle blur events here mainly because of dashboard panels which expect to have query executed on blur.
|
||||
*/
|
||||
handleBlur = (event: Event, editor: CoreEditor, next: Function) => {
|
||||
handleBlur = (_: React.FocusEvent | undefined, editor: Editor, next: Function) => {
|
||||
const { onBlur } = this.props;
|
||||
|
||||
if (onBlur) {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import Plain from 'slate-plain-serializer';
|
||||
|
||||
import { Editor } from '@grafana/slate-react';
|
||||
import { Editor } from 'slate-react';
|
||||
|
||||
import { BracesPlugin } from './braces';
|
||||
|
||||
@@ -14,7 +13,7 @@ describe('braces', () => {
|
||||
const value = Plain.deserialize('');
|
||||
const editor = shallow<Editor>(<Editor value={value} />);
|
||||
const event = new window.KeyboardEvent('keydown', { key: '(' });
|
||||
expect(handler(event as Event, editor.instance() as any, nextMock)).toBeTruthy();
|
||||
expect(handler(event as any, editor.instance(), nextMock)).toBeTruthy();
|
||||
expect(Plain.serialize(editor.instance().value)).toEqual('()');
|
||||
});
|
||||
|
||||
@@ -22,7 +21,8 @@ describe('braces', () => {
|
||||
const value = Plain.deserialize('time()');
|
||||
const editor = shallow<Editor>(<Editor value={value} />);
|
||||
const event = new window.KeyboardEvent('keydown', { key: 'Backspace' });
|
||||
handler(event as Event, editor.instance().moveForward(5) as any, nextMock);
|
||||
editor.instance().moveForward(5);
|
||||
handler(event as any, editor.instance(), nextMock);
|
||||
expect(Plain.serialize(editor.instance().value)).toEqual('time');
|
||||
});
|
||||
|
||||
@@ -30,7 +30,8 @@ describe('braces', () => {
|
||||
const value = Plain.deserialize('time(value)');
|
||||
const editor = shallow<Editor>(<Editor value={value} />);
|
||||
const event = new window.KeyboardEvent('keydown', { key: 'Backspace' });
|
||||
const handled = handler(event as Event, editor.instance().moveForward(5) as any, nextMock);
|
||||
editor.instance().moveForward(5);
|
||||
const handled = handler(event as any, editor.instance(), nextMock);
|
||||
expect(handled).toBeFalsy();
|
||||
});
|
||||
|
||||
@@ -38,9 +39,9 @@ describe('braces', () => {
|
||||
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();
|
||||
expect(handler(opening as any, editor.instance(), nextMock)).toBeTruthy();
|
||||
const closing = new window.KeyboardEvent('keydown', { key: ')' });
|
||||
expect(handler(closing as Event, editor.instance() as any, nextMock)).toBeTruthy();
|
||||
expect(handler(closing as any, editor.instance(), nextMock)).toBeTruthy();
|
||||
expect(Plain.serialize(editor.instance().value)).toEqual('()');
|
||||
});
|
||||
|
||||
@@ -48,9 +49,10 @@ describe('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();
|
||||
expect(handler(event1 as any, editor.instance(), nextMock)).toBeFalsy();
|
||||
const event2 = new window.KeyboardEvent('keydown', { key: ')' });
|
||||
expect(handler(event2 as Event, editor.instance().moveBackward(1) as any, nextMock)).toBeFalsy();
|
||||
editor.instance().moveBackward(1);
|
||||
expect(handler(event2 as any, editor.instance(), nextMock)).toBeFalsy();
|
||||
expect(Plain.serialize(editor.instance().value)).toEqual('))');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Editor as CoreEditor, Annotation } from 'slate';
|
||||
import { Annotation } from 'slate';
|
||||
import { Plugin } from 'slate-react';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { Plugin } from '@grafana/slate-react';
|
||||
|
||||
const BRACES: any = {
|
||||
'[': ']',
|
||||
'{': '}',
|
||||
@@ -13,11 +12,10 @@ const MATCH_MARK = 'brace_match';
|
||||
|
||||
export function BracesPlugin(): Plugin {
|
||||
return {
|
||||
onKeyDown(event: Event, editor: CoreEditor, next: Function) {
|
||||
const keyEvent = event as KeyboardEvent;
|
||||
onKeyDown(event, editor, next) {
|
||||
const { value } = editor;
|
||||
|
||||
switch (keyEvent.key) {
|
||||
switch (event.key) {
|
||||
case '(':
|
||||
case '{':
|
||||
case '[': {
|
||||
@@ -30,10 +28,10 @@ export function BracesPlugin(): Plugin {
|
||||
|
||||
// If text is selected, wrap selected text in parens
|
||||
if (value.selection.isExpanded) {
|
||||
keyEvent.preventDefault();
|
||||
event.preventDefault();
|
||||
editor
|
||||
.insertTextByKey(startKey, startOffset, keyEvent.key)
|
||||
.insertTextByKey(endKey, endOffset + 1, BRACES[keyEvent.key])
|
||||
.insertTextByKey(startKey, startOffset, event.key)
|
||||
.insertTextByKey(endKey, endOffset + 1, BRACES[event.key])
|
||||
.moveEndBackward(1);
|
||||
return true;
|
||||
} else if (
|
||||
@@ -42,8 +40,8 @@ export function BracesPlugin(): Plugin {
|
||||
text[focusOffset] === ' ' ||
|
||||
Object.values(BRACES).includes(text[focusOffset])
|
||||
) {
|
||||
keyEvent.preventDefault();
|
||||
const complement = BRACES[keyEvent.key];
|
||||
event.preventDefault();
|
||||
const complement = BRACES[event.key];
|
||||
const matchAnnotation = {
|
||||
key: `${MATCH_MARK}-${uuidv4()}`,
|
||||
type: `${MATCH_MARK}-${complement}`,
|
||||
@@ -59,7 +57,7 @@ export function BracesPlugin(): Plugin {
|
||||
},
|
||||
object: 'annotation',
|
||||
} as Annotation;
|
||||
editor.insertText(keyEvent.key).insertText(complement).addAnnotation(matchAnnotation).moveBackward(1);
|
||||
editor.insertText(event.key).insertText(complement).addAnnotation(matchAnnotation).moveBackward(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -73,13 +71,13 @@ export function BracesPlugin(): Plugin {
|
||||
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 complement = event.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();
|
||||
event.preventDefault();
|
||||
editor.moveFocusForward(1).removeAnnotation(annotation).moveAnchorForward(1);
|
||||
return true;
|
||||
}
|
||||
@@ -92,7 +90,7 @@ export function BracesPlugin(): Plugin {
|
||||
const previousChar = text[offset - 1];
|
||||
const nextChar = text[offset];
|
||||
if (BRACES[previousChar] && BRACES[previousChar] === nextChar) {
|
||||
keyEvent.preventDefault();
|
||||
event.preventDefault();
|
||||
// Remove closing brace if directly following
|
||||
editor.deleteBackward(1).deleteForward(1).focus();
|
||||
return true;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import Plain from 'slate-plain-serializer';
|
||||
|
||||
import { Editor } from '@grafana/slate-react';
|
||||
import { Editor } from 'slate-react';
|
||||
|
||||
import { ClearPlugin } from './clear';
|
||||
|
||||
@@ -16,7 +15,7 @@ describe('clear', () => {
|
||||
key: 'k',
|
||||
ctrlKey: true,
|
||||
});
|
||||
handler(event as Event, editor.instance() as any, () => {});
|
||||
handler(event as any, editor.instance(), () => {});
|
||||
expect(Plain.serialize(editor.instance().value)).toEqual('');
|
||||
});
|
||||
|
||||
@@ -27,7 +26,7 @@ describe('clear', () => {
|
||||
key: 'k',
|
||||
ctrlKey: true,
|
||||
});
|
||||
handler(event as Event, editor.instance() as any, () => {});
|
||||
handler(event as any, editor.instance(), () => {});
|
||||
expect(Plain.serialize(editor.instance().value)).toEqual('');
|
||||
});
|
||||
|
||||
@@ -38,7 +37,8 @@ describe('clear', () => {
|
||||
key: 'k',
|
||||
ctrlKey: true,
|
||||
});
|
||||
handler(event as Event, editor.instance().moveForward(4) as any, () => {});
|
||||
editor.instance().moveForward(4);
|
||||
handler(event as any, editor.instance(), () => {});
|
||||
expect(Plain.serialize(editor.instance().value)).toEqual('foo ');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
import { Editor as CoreEditor } from 'slate';
|
||||
|
||||
import { Plugin } from '@grafana/slate-react';
|
||||
import { Plugin } from 'slate-react';
|
||||
|
||||
// Clears the rest of the line after the caret
|
||||
export function ClearPlugin(): Plugin {
|
||||
return {
|
||||
onKeyDown(event: Event, editor: CoreEditor, next: Function) {
|
||||
const keyEvent = event as KeyboardEvent;
|
||||
onKeyDown(event, editor, next) {
|
||||
const value = editor.value;
|
||||
|
||||
if (value.selection.isExpanded) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (keyEvent.key === 'k' && keyEvent.ctrlKey) {
|
||||
keyEvent.preventDefault();
|
||||
if (event.key === 'k' && event.ctrlKey) {
|
||||
event.preventDefault();
|
||||
const text = value.anchorText.text;
|
||||
const offset = value.selection.anchor.offset;
|
||||
const length = text.length;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { Editor as CoreEditor } from 'slate';
|
||||
|
||||
import { Plugin } from '@grafana/slate-react';
|
||||
import { Plugin } from 'slate-react';
|
||||
|
||||
const getCopiedText = (textBlocks: string[], startOffset: number, endOffset: number) => {
|
||||
if (!textBlocks.length) {
|
||||
@@ -18,9 +16,8 @@ const removeBom = (str: string | undefined): string | undefined => {
|
||||
|
||||
export function ClipboardPlugin(): Plugin {
|
||||
const clipboardPlugin: Plugin = {
|
||||
onCopy(event: Event, editor: CoreEditor, next: () => any) {
|
||||
const clipEvent = event as ClipboardEvent;
|
||||
clipEvent.preventDefault();
|
||||
onCopy(event, editor, next) {
|
||||
event.preventDefault();
|
||||
|
||||
const { document, selection } = editor.value;
|
||||
const {
|
||||
@@ -33,18 +30,17 @@ export function ClipboardPlugin(): Plugin {
|
||||
.map((block) => block.text);
|
||||
|
||||
const copiedText = removeBom(getCopiedText(selectedBlocks, startOffset, endOffset));
|
||||
if (copiedText && clipEvent.clipboardData) {
|
||||
clipEvent.clipboardData.setData('Text', copiedText);
|
||||
if (copiedText && event.clipboardData) {
|
||||
event.clipboardData.setData('Text', copiedText);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
onPaste(event: Event, editor: CoreEditor, next: () => any) {
|
||||
const clipEvent = event as ClipboardEvent;
|
||||
clipEvent.preventDefault();
|
||||
if (clipEvent.clipboardData) {
|
||||
const pastedValue = removeBom(clipEvent.clipboardData.getData('Text'));
|
||||
onPaste(event, editor, next) {
|
||||
event.preventDefault();
|
||||
if (event.clipboardData) {
|
||||
const pastedValue = removeBom(event.clipboardData.getData('Text'));
|
||||
const lines = pastedValue?.split('\n');
|
||||
|
||||
if (lines && lines.length) {
|
||||
@@ -61,9 +57,8 @@ export function ClipboardPlugin(): Plugin {
|
||||
|
||||
return {
|
||||
...clipboardPlugin,
|
||||
onCut(event: Event, editor: CoreEditor, next: () => any) {
|
||||
const clipEvent = event as ClipboardEvent;
|
||||
clipboardPlugin.onCopy!(clipEvent, editor, next);
|
||||
onCut(event, editor, next) {
|
||||
clipboardPlugin.onCopy!(event, editor, next);
|
||||
editor.deleteAtRange(editor.value.selection);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { isKeyHotkey } from 'is-hotkey';
|
||||
import { RangeJSON, Range as SlateRange, Editor as CoreEditor } from 'slate';
|
||||
|
||||
import { Plugin } from '@grafana/slate-react';
|
||||
import React from 'react';
|
||||
import { RangeJSON, Range as SlateRange } from 'slate';
|
||||
import { Editor, Plugin } from 'slate-react';
|
||||
|
||||
const isIndentLeftHotkey = isKeyHotkey('mod+[');
|
||||
const isShiftTabHotkey = isKeyHotkey('shift+tab');
|
||||
@@ -9,7 +9,7 @@ const isIndentRightHotkey = isKeyHotkey('mod+]');
|
||||
|
||||
const SLATE_TAB = ' ';
|
||||
|
||||
const handleTabKey = (event: KeyboardEvent, editor: CoreEditor, next: Function): void => {
|
||||
const handleTabKey = (event: React.KeyboardEvent<Element>, editor: Editor, next: Function): void => {
|
||||
const {
|
||||
startBlock,
|
||||
endBlock,
|
||||
@@ -31,7 +31,7 @@ const handleTabKey = (event: KeyboardEvent, editor: CoreEditor, next: Function):
|
||||
}
|
||||
};
|
||||
|
||||
const handleIndent = (editor: CoreEditor, indentDirection: 'left' | 'right') => {
|
||||
const handleIndent = (editor: Editor, indentDirection: 'left' | 'right') => {
|
||||
const curSelection = editor.value.selection;
|
||||
const selectedBlocks = editor.value.document.getLeafBlocksAtRange(curSelection).toArray();
|
||||
|
||||
@@ -74,17 +74,16 @@ const handleIndent = (editor: CoreEditor, indentDirection: 'left' | 'right') =>
|
||||
// Clears the rest of the line after the caret
|
||||
export function IndentationPlugin(): Plugin {
|
||||
return {
|
||||
onKeyDown(event: Event, editor: CoreEditor, next: Function) {
|
||||
const keyEvent = event as KeyboardEvent;
|
||||
if (isIndentLeftHotkey(keyEvent) || isShiftTabHotkey(keyEvent)) {
|
||||
keyEvent.preventDefault();
|
||||
onKeyDown(event, editor, next) {
|
||||
if (isIndentLeftHotkey(event) || isShiftTabHotkey(event)) {
|
||||
event.preventDefault();
|
||||
handleIndent(editor, 'left');
|
||||
} else if (isIndentRightHotkey(keyEvent)) {
|
||||
keyEvent.preventDefault();
|
||||
} else if (isIndentRightHotkey(event)) {
|
||||
event.preventDefault();
|
||||
handleIndent(editor, 'right');
|
||||
} else if (keyEvent.key === 'Tab') {
|
||||
keyEvent.preventDefault();
|
||||
handleTabKey(keyEvent, editor, next);
|
||||
} else if (event.key === 'Tab') {
|
||||
event.preventDefault();
|
||||
handleTabKey(event, editor, next);
|
||||
} else {
|
||||
return next();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { Editor as CoreEditor } from 'slate';
|
||||
|
||||
import { Plugin } from '@grafana/slate-react';
|
||||
import { Plugin } from 'slate-react';
|
||||
|
||||
function getIndent(text: string) {
|
||||
let offset = text.length - text.trimLeft().length;
|
||||
@@ -16,16 +14,15 @@ function getIndent(text: string) {
|
||||
|
||||
export function NewlinePlugin(): Plugin {
|
||||
return {
|
||||
onKeyDown(event: Event, editor: CoreEditor, next: Function) {
|
||||
const keyEvent = event as KeyboardEvent;
|
||||
onKeyDown(event, editor, next) {
|
||||
const value = editor.value;
|
||||
|
||||
if (value.selection.isExpanded) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (keyEvent.key === 'Enter') {
|
||||
keyEvent.preventDefault();
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
|
||||
const { startBlock } = value;
|
||||
const currentLineText = startBlock.text;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import Plain from 'slate-plain-serializer';
|
||||
|
||||
import { Editor } from '@grafana/slate-react';
|
||||
import { Editor } from 'slate-react';
|
||||
|
||||
import { RunnerPlugin } from './runner';
|
||||
|
||||
@@ -12,10 +11,13 @@ describe('runner', () => {
|
||||
|
||||
it('should execute query when enter with shift is pressed', () => {
|
||||
const value = Plain.deserialize('');
|
||||
const editor = shallow<Editor>(<Editor value={value} />);
|
||||
const editor = shallow(<Editor value={value} />);
|
||||
handler(
|
||||
{ key: 'Enter', shiftKey: true, preventDefault: () => {} } as KeyboardEvent,
|
||||
editor.instance() as any,
|
||||
new window.KeyboardEvent('keydown', {
|
||||
key: 'Enter',
|
||||
shiftKey: true,
|
||||
}) as any,
|
||||
editor.instance() as Editor,
|
||||
() => {}
|
||||
);
|
||||
expect(mockHandler).toBeCalled();
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
import { Editor as CoreEditor } from 'slate';
|
||||
import React from 'react';
|
||||
import { Plugin } from 'slate-react';
|
||||
|
||||
import { Plugin } from '@grafana/slate-react';
|
||||
|
||||
export function RunnerPlugin({ handler }: any): Plugin {
|
||||
export function RunnerPlugin({ handler }: { handler?: (e: React.KeyboardEvent) => void }): Plugin {
|
||||
return {
|
||||
onKeyDown(event: Event, editor: CoreEditor, next: Function) {
|
||||
const keyEvent = event as KeyboardEvent;
|
||||
|
||||
onKeyDown(event, editor, next) {
|
||||
// Handle enter
|
||||
if (handler && keyEvent.key === 'Enter' && (keyEvent.shiftKey || keyEvent.ctrlKey)) {
|
||||
if (handler && event.key === 'Enter' && (event.shiftKey || event.ctrlKey)) {
|
||||
// Submit on Enter
|
||||
keyEvent.preventDefault();
|
||||
handler(keyEvent);
|
||||
event.preventDefault();
|
||||
handler(event);
|
||||
return editor;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
import { isKeyHotkey } from 'is-hotkey';
|
||||
import { Editor as CoreEditor } from 'slate';
|
||||
|
||||
import { Plugin } from '@grafana/slate-react';
|
||||
import { Plugin } from 'slate-react';
|
||||
|
||||
const isSelectLineHotkey = isKeyHotkey('mod+l');
|
||||
|
||||
// Clears the rest of the line after the caret
|
||||
export function SelectionShortcutsPlugin(): Plugin {
|
||||
return {
|
||||
onKeyDown(event: Event, editor: CoreEditor, next: () => any) {
|
||||
const keyEvent = event as KeyboardEvent;
|
||||
if (isSelectLineHotkey(keyEvent)) {
|
||||
keyEvent.preventDefault();
|
||||
onKeyDown(event, editor, next) {
|
||||
if (isSelectLineHotkey(event)) {
|
||||
event.preventDefault();
|
||||
const { focusBlock, document } = editor.value;
|
||||
|
||||
editor.moveAnchorToStartOfBlock();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import Prism, { LanguageMap } from 'prismjs';
|
||||
import { Block, Text, Decoration } from 'slate';
|
||||
|
||||
import { Plugin } from '@grafana/slate-react';
|
||||
import { Plugin } from 'slate-react';
|
||||
|
||||
import TOKEN_MARK from './TOKEN_MARK';
|
||||
import Options, { OptionsFormat } from './options';
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Record } from 'immutable';
|
||||
import React from 'react';
|
||||
import { Mark, Node, Decoration } from 'slate';
|
||||
|
||||
import { Editor } from '@grafana/slate-react';
|
||||
import { Editor } from 'slate-react';
|
||||
|
||||
import TOKEN_MARK from './TOKEN_MARK';
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { render } from 'enzyme';
|
||||
import _ from 'lodash'; // eslint-disable-line lodash/import-scope
|
||||
|
||||
import { Plugin as SlatePlugin } from '@grafana/slate-react';
|
||||
import { Plugin as SlatePlugin } from 'slate-react';
|
||||
|
||||
import { CompletionItemGroup, SuggestionsState } from '../types';
|
||||
import { SearchFunctionType } from '../utils';
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { debounce, sortBy } from 'lodash';
|
||||
import React from 'react';
|
||||
import { Editor as CoreEditor } from 'slate';
|
||||
|
||||
import { Plugin as SlatePlugin } from '@grafana/slate-react';
|
||||
import { Editor, Plugin as SlatePlugin } from 'slate-react';
|
||||
|
||||
import { Typeahead } from '../components/Typeahead/Typeahead';
|
||||
import { CompletionItem, SuggestionsState, TypeaheadInput, TypeaheadOutput } from '../types';
|
||||
@@ -15,8 +13,8 @@ export const TYPEAHEAD_DEBOUNCE = 250;
|
||||
|
||||
// Commands added to the editor by this plugin.
|
||||
interface SuggestionsPluginCommands {
|
||||
selectSuggestion: (suggestion: CompletionItem) => CoreEditor;
|
||||
applyTypeahead: (suggestion: CompletionItem) => CoreEditor;
|
||||
selectSuggestion: (suggestion: CompletionItem) => Editor;
|
||||
applyTypeahead: (suggestion: CompletionItem) => Editor;
|
||||
}
|
||||
|
||||
export function SuggestionsPlugin({
|
||||
@@ -65,16 +63,15 @@ export function SuggestionsPlugin({
|
||||
return next();
|
||||
},
|
||||
|
||||
onKeyDown: (event: Event, editor, next) => {
|
||||
const keyEvent = event as KeyboardEvent;
|
||||
onKeyDown: (event, editor, next) => {
|
||||
const currentSuggestions = state.groupedItems;
|
||||
|
||||
const hasSuggestions = currentSuggestions.length;
|
||||
|
||||
switch (keyEvent.key) {
|
||||
switch (event.key) {
|
||||
case 'Escape': {
|
||||
if (hasSuggestions) {
|
||||
keyEvent.preventDefault();
|
||||
event.preventDefault();
|
||||
|
||||
state = {
|
||||
...state,
|
||||
@@ -91,16 +88,16 @@ export function SuggestionsPlugin({
|
||||
case 'ArrowDown':
|
||||
case 'ArrowUp':
|
||||
if (hasSuggestions) {
|
||||
keyEvent.preventDefault();
|
||||
typeaheadRef.moveMenuIndex(keyEvent.key === 'ArrowDown' ? 1 : -1);
|
||||
event.preventDefault();
|
||||
typeaheadRef.moveMenuIndex(event.key === 'ArrowDown' ? 1 : -1);
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'Enter': {
|
||||
if (!(keyEvent.shiftKey || keyEvent.ctrlKey) && hasSuggestions) {
|
||||
keyEvent.preventDefault();
|
||||
if (!(event.shiftKey || event.ctrlKey) && hasSuggestions) {
|
||||
event.preventDefault();
|
||||
return typeaheadRef.insertSuggestion();
|
||||
}
|
||||
|
||||
@@ -109,7 +106,7 @@ export function SuggestionsPlugin({
|
||||
|
||||
case 'Tab': {
|
||||
if (hasSuggestions) {
|
||||
keyEvent.preventDefault();
|
||||
event.preventDefault();
|
||||
return typeaheadRef.insertSuggestion();
|
||||
}
|
||||
|
||||
@@ -118,7 +115,7 @@ export function SuggestionsPlugin({
|
||||
|
||||
default: {
|
||||
// Don't react on meta keys
|
||||
if (keyEvent.key.length === 1) {
|
||||
if (event.key.length === 1) {
|
||||
handleTypeaheadDebounced(editor, setState, onTypeahead, cleanText);
|
||||
}
|
||||
break;
|
||||
@@ -129,7 +126,7 @@ export function SuggestionsPlugin({
|
||||
},
|
||||
|
||||
commands: {
|
||||
selectSuggestion: (editor: CoreEditor, suggestion: CompletionItem): CoreEditor => {
|
||||
selectSuggestion: (editor, suggestion: CompletionItem): Editor => {
|
||||
const suggestions = state.groupedItems;
|
||||
if (!suggestions || !suggestions.length) {
|
||||
return editor;
|
||||
@@ -141,7 +138,7 @@ export function SuggestionsPlugin({
|
||||
return ed;
|
||||
},
|
||||
|
||||
applyTypeahead: (editor: CoreEditor, suggestion: CompletionItem): CoreEditor => {
|
||||
applyTypeahead: (editor, suggestion: CompletionItem) => {
|
||||
let suggestionText = suggestion.insertText || suggestion.label;
|
||||
|
||||
const preserveSuffix = suggestion.kind === 'function';
|
||||
@@ -169,7 +166,8 @@ export function SuggestionsPlugin({
|
||||
// If new-lines, apply suggestion as block
|
||||
if (suggestionText.match(/\n/)) {
|
||||
const fragment = makeFragment(suggestionText);
|
||||
return editor.deleteBackward(backward).deleteForward(forward).insertFragment(fragment).focus();
|
||||
editor.deleteBackward(backward).deleteForward(forward).insertFragment(fragment).focus();
|
||||
return editor;
|
||||
}
|
||||
|
||||
state = {
|
||||
@@ -177,13 +175,15 @@ export function SuggestionsPlugin({
|
||||
groupedItems: [],
|
||||
};
|
||||
|
||||
return editor
|
||||
editor
|
||||
.snapshotSelection()
|
||||
.deleteBackward(backward)
|
||||
.deleteForward(forward)
|
||||
.insertText(suggestionText)
|
||||
.moveForward(move)
|
||||
.focus();
|
||||
|
||||
return editor;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -203,7 +203,7 @@ export function SuggestionsPlugin({
|
||||
prefix={state.typeaheadPrefix}
|
||||
isOpen={!!state.groupedItems.length}
|
||||
groupedItems={state.groupedItems}
|
||||
onSelectSuggestion={(editor as CoreEditor & SuggestionsPluginCommands).selectSuggestion}
|
||||
onSelectSuggestion={(editor as Editor & SuggestionsPluginCommands).selectSuggestion}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -212,7 +212,7 @@ export function SuggestionsPlugin({
|
||||
}
|
||||
|
||||
const handleTypeahead = async (
|
||||
editor: CoreEditor,
|
||||
editor: Editor,
|
||||
onStateChange: (state: Partial<SuggestionsState>) => void,
|
||||
onTypeahead?: (typeahead: TypeaheadInput) => Promise<TypeaheadOutput>,
|
||||
cleanText?: (text: string) => string
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Value, Editor as CoreEditor } from 'slate';
|
||||
import { Value } from 'slate';
|
||||
import { Editor } from 'slate-react';
|
||||
|
||||
import { SearchFunctionType } from '../utils';
|
||||
|
||||
@@ -133,7 +134,7 @@ export interface TypeaheadInput {
|
||||
wrapperClasses: string[];
|
||||
labelKey?: string;
|
||||
value?: Value;
|
||||
editor?: CoreEditor;
|
||||
editor?: Editor;
|
||||
}
|
||||
|
||||
export interface SuggestionsState {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@emotion/core": ["./src/types/emotion-core-stub.d.ts"],
|
||||
"@grafana/slate-react": ["slate-react"],
|
||||
"@grafana/ui": ["."]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
"@testing-library/user-event": "14.4.3",
|
||||
"@types/classnames": "^2.2.7",
|
||||
"@types/deep-freeze": "^0.1.1",
|
||||
"@types/grafana__slate-react": "npm:@types/slate-react@0.22.5",
|
||||
"@types/hoist-non-react-statics": "^3.3.1",
|
||||
"@types/jest": "28.1.6",
|
||||
"@types/lodash": "4.14.182",
|
||||
@@ -23,6 +22,7 @@
|
||||
"@types/react": "17.0.42",
|
||||
"@types/react-icons": "2.2.7",
|
||||
"@types/reselect": "2.2.0",
|
||||
"@types/slate-react": "0.22.9",
|
||||
"@types/testing-library__jest-dom": "5.14.5",
|
||||
"@types/tinycolor2": "1.4.3",
|
||||
"enzyme": "3.11.0",
|
||||
|
||||
Reference in New Issue
Block a user