Refactor: Suggestion plugin for slate (#19825)

This commit is contained in:
Andrej Ocenas 2019-10-21 18:53:35 +02:00 committed by GitHub
parent 3119f35715
commit 80a6853fd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 124 additions and 121 deletions

View File

@ -15,8 +15,6 @@ import IndentationPlugin from './slate-plugins/indentation';
import ClipboardPlugin from './slate-plugins/clipboard';
import RunnerPlugin from './slate-plugins/runner';
import SuggestionsPlugin, { SuggestionsState } from './slate-plugins/suggestions';
import { Typeahead } from './Typeahead';
import { makeValue, SCHEMA } from '@grafana/ui';
export interface QueryFieldProps {
@ -66,8 +64,6 @@ export class QueryField extends React.PureComponent<QueryFieldProps, QueryFieldS
mounted: boolean;
runOnChangeDebounced: Function;
editor: Editor;
// Is required by SuggestionsPlugin
typeaheadRef: Typeahead;
lastExecutedValue: Value | null = null;
constructor(props: QueryFieldProps, context: Context<any>) {
@ -80,7 +76,7 @@ export class QueryField extends React.PureComponent<QueryFieldProps, QueryFieldS
// Base plugins
this.plugins = [
NewlinePlugin(),
SuggestionsPlugin({ onTypeahead, cleanText, portalOrigin, onWillApplySuggestion, component: this }),
SuggestionsPlugin({ onTypeahead, cleanText, portalOrigin, onWillApplySuggestion }),
ClearPlugin(),
RunnerPlugin({ handler: this.runOnChangeAndRunQuery }),
SelectionShortcutsPlugin(),

View File

@ -6,7 +6,7 @@ import { Editor as CoreEditor } from 'slate';
import { Plugin as SlatePlugin } from '@grafana/slate-react';
import { TypeaheadOutput, CompletionItem, CompletionItemGroup } from 'app/types';
import { QueryField, TypeaheadInput } from '../QueryField';
import { TypeaheadInput } from '../QueryField';
import TOKEN_MARK from '@grafana/ui/src/slate-plugins/slate-prism/TOKEN_MARK';
import { TypeaheadWithTheme, Typeahead } from '../Typeahead';
@ -14,6 +14,12 @@ import { makeFragment } from '@grafana/ui';
export const TYPEAHEAD_DEBOUNCE = 100;
// Commands added to the editor by this plugin.
interface SuggestionsPluginCommands {
selectSuggestion: (suggestion: CompletionItem) => CoreEditor;
applyTypeahead: (suggestion: CompletionItem) => CoreEditor;
}
export interface SuggestionsState {
groupedItems: CompletionItemGroup[];
typeaheadPrefix: string;
@ -21,28 +27,33 @@ export interface SuggestionsState {
typeaheadText: string;
}
export default function SuggestionsPlugin({
onTypeahead,
cleanText,
onWillApplySuggestion,
portalOrigin,
}: {
onTypeahead: (typeahead: TypeaheadInput) => Promise<TypeaheadOutput>;
cleanText?: (text: string) => string;
onWillApplySuggestion?: (suggestion: string, state: SuggestionsState) => string;
portalOrigin: string;
}): SlatePlugin {
let typeaheadRef: Typeahead;
let state: SuggestionsState = {
groupedItems: [],
typeaheadPrefix: '',
typeaheadContext: '',
typeaheadText: '',
};
const handleTypeaheadDebounced = debounce(handleTypeahead, TYPEAHEAD_DEBOUNCE);
const setState = (update: Partial<SuggestionsState>) => {
state = {
...state,
...update,
};
};
export default function SuggestionsPlugin({
onTypeahead,
cleanText,
onWillApplySuggestion,
syntax,
portalOrigin,
component,
}: {
onTypeahead: (typeahead: TypeaheadInput) => Promise<TypeaheadOutput>;
cleanText?: (text: string) => string;
onWillApplySuggestion?: (suggestion: string, state: SuggestionsState) => string;
syntax?: string;
portalOrigin: string;
component: QueryField; // Need to attach typeaheadRef here
}): SlatePlugin {
return {
onBlur: (event, editor, next) => {
state = {
@ -88,7 +99,7 @@ export default function SuggestionsPlugin({
case 'ArrowUp':
if (hasSuggestions) {
event.preventDefault();
component.typeaheadRef.moveMenuIndex(event.key === 'ArrowDown' ? 1 : -1);
typeaheadRef.moveMenuIndex(event.key === 'ArrowDown' ? 1 : -1);
return;
}
@ -98,14 +109,14 @@ export default function SuggestionsPlugin({
case 'Tab': {
if (hasSuggestions) {
event.preventDefault();
return component.typeaheadRef.insertSuggestion();
return typeaheadRef.insertSuggestion();
}
break;
}
default: {
handleTypeahead(editor, onTypeahead, cleanText);
handleTypeaheadDebounced(editor, setState, onTypeahead, cleanText);
break;
}
}
@ -122,7 +133,7 @@ export default function SuggestionsPlugin({
// @ts-ignore
const ed = editor.applyTypeahead(suggestion);
handleTypeahead(editor, onTypeahead, cleanText);
handleTypeaheadDebounced(editor, setState, onTypeahead, cleanText);
return ed;
},
@ -186,13 +197,12 @@ export default function SuggestionsPlugin({
<>
{children}
<TypeaheadWithTheme
menuRef={(el: Typeahead) => (component.typeaheadRef = el)}
menuRef={(el: Typeahead) => (typeaheadRef = el)}
origin={portalOrigin}
prefix={state.typeaheadPrefix}
isOpen={!!state.groupedItems.length}
groupedItems={state.groupedItems}
//@ts-ignore
onSelectSuggestion={editor.selectSuggestion}
onSelectSuggestion={(editor as CoreEditor & SuggestionsPluginCommands).selectSuggestion}
/>
</>
);
@ -200,12 +210,12 @@ export default function SuggestionsPlugin({
};
}
const handleTypeahead = debounce(
async (
const handleTypeahead = async (
editor: CoreEditor,
onStateChange: (state: Partial<SuggestionsState>) => void,
onTypeahead?: (typeahead: TypeaheadInput) => Promise<TypeaheadOutput>,
cleanText?: (text: string) => string
) => {
): Promise<void> => {
if (!onTypeahead) {
return null;
}
@ -298,16 +308,13 @@ const handleTypeahead = debounce(
})
.filter(group => group.items && group.items.length); // Filter out empty groups
state = {
...state,
onStateChange({
groupedItems: filteredSuggestions,
typeaheadPrefix: prefix,
typeaheadContext: context,
typeaheadText: text,
};
});
// Bogus edit to force re-render
return editor.blur().focus();
},
TYPEAHEAD_DEBOUNCE
);
editor.blur().focus();
};