Skip to content

Commit

Permalink
extract useAutoCompleteLeafs hook
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasheyenbrock committed May 30, 2022
1 parent a50ec2a commit 14e362e
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 79 deletions.
69 changes: 3 additions & 66 deletions packages/graphiql-react/src/editor/context.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { fillLeafs, GetDefaultFieldNamesFn } from '@graphiql/toolkit';
import { DocumentNode, OperationDefinitionNode } from 'graphql';
import { VariableToType } from 'graphql-language-service';
import { ReactNode, useCallback, useMemo, useState } from 'react';
import { useSchemaContext } from '../schema';
import { ReactNode, useMemo, useState } from 'react';

import { createContextHook, createNullableContext } from '../utility/context';
import { CodeMirrorEditor } from './types';
Expand All @@ -15,7 +13,6 @@ export type CodeMirrorEditorWithOperationFacts = CodeMirrorEditor & {
};

export type EditorContextType = {
autoCompleteLeafs(): string | undefined;
headerEditor: CodeMirrorEditor | null;
queryEditor: CodeMirrorEditorWithOperationFacts | null;
responseEditor: CodeMirrorEditor | null;
Expand All @@ -30,16 +27,7 @@ export const EditorContext = createNullableContext<EditorContextType>(
'EditorContext',
);

type EditorContextProviderProps = {
children: ReactNode;
getDefaultFieldNames?: GetDefaultFieldNamesFn;
};

export function EditorContextProvider(props: EditorContextProviderProps) {
const { schema } = useSchemaContext({
nonNull: true,
caller: EditorContextProvider,
});
export function EditorContextProvider(props: { children: ReactNode }) {
const [headerEditor, setHeaderEditor] = useState<CodeMirrorEditor | null>(
null,
);
Expand All @@ -54,53 +42,8 @@ export function EditorContextProvider(props: EditorContextProviderProps) {
null,
);

const autoCompleteLeafs = useCallback<
EditorContextType['autoCompleteLeafs']
>(() => {
if (!queryEditor) {
return;
}

const query = queryEditor.getValue();
const { insertions, result } = fillLeafs(
schema,
query,
props.getDefaultFieldNames,
);
if (insertions && insertions.length > 0) {
queryEditor.operation(() => {
const cursor = queryEditor.getCursor();
const cursorIndex = queryEditor.indexFromPos(cursor);
queryEditor.setValue(result || '');
let added = 0;
const markers = insertions.map(({ index, string }) =>
queryEditor.markText(
queryEditor.posFromIndex(index + added),
queryEditor.posFromIndex(index + (added += string.length)),
{
className: 'autoInsertedLeaf',
clearOnEnter: true,
title: 'Automatically added leaf fields',
},
),
);
setTimeout(() => markers.forEach(marker => marker.clear()), 7000);
let newCursorIndex = cursorIndex;
insertions.forEach(({ index, string }) => {
if (index < cursorIndex) {
newCursorIndex += string.length;
}
});
queryEditor.setCursor(queryEditor.posFromIndex(newCursorIndex));
});
}

return result;
}, [props.getDefaultFieldNames, queryEditor, schema]);

const value = useMemo<EditorContextType>(
() => ({
autoCompleteLeafs,
headerEditor,
queryEditor,
responseEditor,
Expand All @@ -110,13 +53,7 @@ export function EditorContextProvider(props: EditorContextProviderProps) {
setResponseEditor,
setVariableEditor,
}),
[
autoCompleteLeafs,
headerEditor,
queryEditor,
responseEditor,
variableEditor,
],
[headerEditor, queryEditor, responseEditor, variableEditor],
);

return (
Expand Down
57 changes: 56 additions & 1 deletion packages/graphiql-react/src/editor/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { mergeAst } from '@graphiql/toolkit';
import { fillLeafs, GetDefaultFieldNamesFn, mergeAst } from '@graphiql/toolkit';
import { EditorChange } from 'codemirror';
import copyToClipboard from 'copy-to-clipboard';
import { parse, print } from 'graphql';
Expand Down Expand Up @@ -218,3 +218,58 @@ export function usePrettifyEditors({
}
}, [queryEditor, variableEditor, headerEditor]);
}

export function useAutoCompleteLeafs({
getDefaultFieldNames,
caller,
}: { getDefaultFieldNames?: GetDefaultFieldNamesFn; caller?: Function } = {}) {
const { schema } = useSchemaContext({
nonNull: true,
caller: caller || useAutoCompleteLeafs,
});
const { queryEditor } = useEditorContext({
nonNull: true,
caller: caller || useAutoCompleteLeafs,
});
return useCallback(() => {
if (!queryEditor) {
return;
}

const query = queryEditor.getValue();
const { insertions, result } = fillLeafs(
schema,
query,
getDefaultFieldNames,
);
if (insertions && insertions.length > 0) {
queryEditor.operation(() => {
const cursor = queryEditor.getCursor();
const cursorIndex = queryEditor.indexFromPos(cursor);
queryEditor.setValue(result || '');
let added = 0;
const markers = insertions.map(({ index, string }) =>
queryEditor.markText(
queryEditor.posFromIndex(index + added),
queryEditor.posFromIndex(index + (added += string.length)),
{
className: 'autoInsertedLeaf',
clearOnEnter: true,
title: 'Automatically added leaf fields',
},
),
);
setTimeout(() => markers.forEach(marker => marker.clear()), 7000);
let newCursorIndex = cursorIndex;
insertions.forEach(({ index, string }) => {
if (index < cursorIndex) {
newCursorIndex += string.length;
}
});
queryEditor.setCursor(queryEditor.posFromIndex(newCursorIndex));
});
}

return result;
}, [getDefaultFieldNames, queryEditor, schema]);
}
8 changes: 7 additions & 1 deletion packages/graphiql-react/src/editor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import {
useEditorContext,
} from './context';
import { useHeaderEditor } from './header-editor';
import { useCopyQuery, useMergeQuery, usePrettifyEditors } from './hooks';
import {
useAutoCompleteLeafs,
useCopyQuery,
useMergeQuery,
usePrettifyEditors,
} from './hooks';
import { useQueryEditor } from './query-editor';
import { useResponseEditor } from './response-editor';
import { useVariableEditor } from './variable-editor';
Expand All @@ -25,6 +30,7 @@ export {
ImagePreview,
EditorContext,
EditorContextProvider,
useAutoCompleteLeafs,
useCopyQuery,
useEditorContext,
useHeaderEditor,
Expand Down
2 changes: 2 additions & 0 deletions packages/graphiql-react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
EditorContextProvider,
ImagePreview,
onHasCompletion,
useAutoCompleteLeafs,
useCopyQuery,
useEditorContext,
useHeaderEditor,
Expand Down Expand Up @@ -57,6 +58,7 @@ export {
EditorContextProvider,
ImagePreview,
onHasCompletion,
useAutoCompleteLeafs,
useCopyQuery,
useEditorContext,
useHeaderEditor,
Expand Down
2 changes: 2 additions & 0 deletions packages/graphiql/__mocks__/@graphiql/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
SchemaContextProvider,
StorageContext,
StorageContextProvider,
useAutoCompleteLeafs,
useCopyQuery,
useEditorContext,
useExplorerContext,
Expand Down Expand Up @@ -54,6 +55,7 @@ export {
SchemaContextProvider,
StorageContext,
StorageContextProvider,
useAutoCompleteLeafs,
useCopyQuery,
useEditorContext,
useExplorerContext,
Expand Down
25 changes: 14 additions & 11 deletions packages/graphiql/src/components/GraphiQL.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
SchemaContextProvider,
StorageContext,
StorageContextProvider,
useAutoCompleteLeafs,
useCopyQuery,
useEditorContext,
useExplorerContext,
Expand Down Expand Up @@ -353,7 +354,6 @@ type TabsState = {
export function GraphiQL({
dangerouslyAssumeSchemaIsValid,
docExplorerOpen,
getDefaultFieldNames,
inputValueDeprecation,
introspectionQueryName,
maxHistoryLength,
Expand Down Expand Up @@ -383,8 +383,7 @@ export function GraphiQL({
<ExplorerContextProvider
isVisible={docExplorerOpen}
onToggleVisibility={onToggleDocs}>
<EditorContextProvider
getDefaultFieldNames={getDefaultFieldNames}>
<EditorContextProvider>
<HistoryContextProvider
maxHistoryLength={maxHistoryLength}
onToggle={onToggleHistory}>
Expand Down Expand Up @@ -441,7 +440,6 @@ type GraphiQLWithContextProviderProps = Omit<
GraphiQLProps,
| 'dangerouslyAssumeSchemaIsValid'
| 'docExplorerOpen'
| 'getDefaultFieldNames'
| 'inputValueDeprecation'
| 'introspectionQueryName'
| 'maxHistoryLength'
Expand All @@ -452,14 +450,19 @@ type GraphiQLWithContextProviderProps = Omit<
| 'storage'
>;

function GraphiQLConsumeContexts(props: GraphiQLWithContextProviderProps) {
function GraphiQLConsumeContexts({
getDefaultFieldNames,
onCopyQuery,
...props
}: GraphiQLWithContextProviderProps) {
const editorContext = useEditorContext({ nonNull: true });
const explorerContext = useExplorerContext();
const historyContext = useHistoryContext();
const schemaContext = useSchemaContext({ nonNull: true });
const storageContext = useStorageContext();

const copy = useCopyQuery({ onCopyQuery: props.onCopyQuery });
const autoCompleteLeafs = useAutoCompleteLeafs({ getDefaultFieldNames });
const copy = useCopyQuery({ onCopyQuery });
const merge = useMergeQuery();
const prettify = usePrettifyEditors();

Expand All @@ -471,6 +474,7 @@ function GraphiQLConsumeContexts(props: GraphiQLWithContextProviderProps) {
historyContext={historyContext}
schemaContext={schemaContext}
storageContext={storageContext}
autoCompleteLeafs={autoCompleteLeafs}
copy={copy}
merge={merge}
prettify={prettify}
Expand All @@ -480,14 +484,15 @@ function GraphiQLConsumeContexts(props: GraphiQLWithContextProviderProps) {

type GraphiQLWithContextConsumerProps = Omit<
GraphiQLWithContextProviderProps,
'onCopyQuery'
'onCopyQuery' | 'getDefaultFieldNames'
> & {
editorContext: EditorContextType;
explorerContext: ExplorerContextType | null;
historyContext: HistoryContextType | null;
schemaContext: SchemaContextType;
storageContext: StorageContextType | null;

autoCompleteLeafs(): string | undefined;
copy(): void;
merge(): void;
prettify(): void;
Expand Down Expand Up @@ -1006,7 +1011,7 @@ class GraphiQLWithContext extends React.Component<
console.warn(
'The method `GraphiQL.autoCompleteLeafs` is deprecated and will be removed in the next major version. Please switch to using the `autoCompleteLeafs` function provided by the `EditorContext` from the `@graphiql/react` package.',
);
return this.props.editorContext.autoCompleteLeafs();
return this.props.autoCompleteLeafs();
}

// Private methods
Expand Down Expand Up @@ -1150,9 +1155,7 @@ class GraphiQLWithContext extends React.Component<
// in case autoCompletion fails (the function returns undefined),
// the current query from the editor.
const editedQuery =
this.props.editorContext.autoCompleteLeafs() ||
getQuery(this.props) ||
'';
this.props.autoCompleteLeafs() || getQuery(this.props) || '';
const variables = getVariables(this.props);
const headers = getHeaders(this.props);
const shouldPersistHeaders = this.state.shouldPersistHeaders;
Expand Down

0 comments on commit 14e362e

Please sign in to comment.