/* Based on https://github.com/graphql/graphiql/blob/main/packages/graphiql/src/components/GraphiQL.tsx */ import { Button, ChevronDownIcon, ChevronUpIcon, CopyIcon, Dialog, ExecuteButton, GraphiQLProvider, HeaderEditor, KeyboardShortcutIcon, MergeIcon, PlusIcon, PrettifyIcon, QueryEditor, ReloadIcon, ResponseEditor, SettingsIcon, Spinner, Tab, Tabs, ToolbarButton, Tooltip, UnStyledButton, useCopyQuery, useDragResize, useEditorContext, useExecutionContext, useMergeQuery, usePluginContext, usePrettifyEditors, useSchemaContext, useStorageContext, useTheme, VariableEditor, } from '@graphiql/react' import { Fetcher } from '@graphiql/toolkit' import clsx from 'clsx' import 'graphiql/graphiql.css' import { PropsWithChildren, useEffect, useState } from 'react' import styles from './graphiql.module.css' export type GraphiQLProps = { fetcher: Fetcher theme?: 'dark' | 'light' apiKey?: string } const GraphiQL = ({ fetcher, theme = 'dark', apiKey }: GraphiQLProps) => { // Ensure props are correct if (typeof fetcher !== 'function') { throw new TypeError( 'The `GraphiQL` component requires a `fetcher` function to be passed as prop.' ) } return ( ) } type GraphiQLInterfaceProps = { theme: 'dark' | 'light' } export const GraphiQLInterface = ({ theme }: GraphiQLInterfaceProps) => { const editorContext = useEditorContext({ nonNull: true }) const executionContext = useExecutionContext({ nonNull: true }) const schemaContext = useSchemaContext({ nonNull: true }) const storageContext = useStorageContext() const pluginContext = usePluginContext() const copy = useCopyQuery() const merge = useMergeQuery() const prettify = usePrettifyEditors() const { setTheme } = useTheme() useEffect(() => { setTheme(theme) }, [theme]) const PluginContent = pluginContext?.visiblePlugin?.content const pluginResize = useDragResize({ defaultSizeRelation: 1 / 3, direction: 'horizontal', initiallyHidden: pluginContext?.visiblePlugin ? undefined : 'second', onHiddenElementChange: (resizableElement) => { if (resizableElement === 'first') { pluginContext?.setVisiblePlugin(null) } }, sizeThresholdSecond: 200, storageKey: 'docExplorerFlex', }) const editorResize = useDragResize({ direction: 'horizontal', storageKey: 'editorFlex', }) const editorToolsResize = useDragResize({ defaultSizeRelation: 3, direction: 'vertical', initiallyHidden: (() => { return editorContext.initialVariables || editorContext.initialHeaders ? undefined : 'second' })(), sizeThresholdSecond: 60, storageKey: 'secondaryEditorFlex', }) const [activeSecondaryEditor, setActiveSecondaryEditor] = useState<'variables' | 'headers'>( () => { return !editorContext.initialVariables && editorContext.initialHeaders ? 'headers' : 'variables' } ) const [showDialog, setShowDialog] = useState<'settings' | 'short-keys' | null>(null) const [clearStorageStatus, setClearStorageStatus] = useState<'success' | 'error' | null>(null) const logo = const toolbar = ( <> prettify()} label="Prettify query (Shift-Ctrl-P)"> merge()} label="Merge fragments into query (Shift-Ctrl-M)"> copy()} label="Copy query (Shift-Ctrl-C)"> ) const onClickReference = () => { if (pluginResize.hiddenElement === 'second') { pluginResize.setHiddenElement(null) } } const modifier = window.navigator.platform.toLowerCase().indexOf('mac') === 0 ? ( Cmd ) : ( Ctrl ) return (
{editorContext.tabs.length > 1 ? ( <> {editorContext.tabs.map((tab, index) => ( { executionContext.stop() editorContext.changeTab(index) }} > {tab.title} { if (editorContext.activeTabIndex === index) { executionContext.stop() } editorContext.closeTab(index) }} /> ))}
editorContext.addTab()} aria-label="Add tab" >
) : null}
{editorContext.tabs.length === 1 ? (
editorContext.addTab()} aria-label="Add tab" >
) : null} {logo}
{toolbar}
{ if (editorToolsResize.hiddenElement === 'second') { editorToolsResize.setHiddenElement(null) } setActiveSecondaryEditor('variables') }} > Variables { if (editorToolsResize.hiddenElement === 'second') { editorToolsResize.setHiddenElement(null) } setActiveSecondaryEditor('headers') }} > Headers
{ editorToolsResize.setHiddenElement( editorToolsResize.hiddenElement === 'second' ? null : 'second' ) }} aria-label={ editorToolsResize.hiddenElement === 'second' ? 'Show editor tools' : 'Hide editor tools' } > {editorToolsResize.hiddenElement === 'second' ? (
{executionContext.isFetching ? : null}
{pluginContext?.visiblePlugin ?
: null}
{PluginContent ? : null}
{pluginContext?.plugins.map((plugin) => { const isVisible = plugin === pluginContext.visiblePlugin const label = `${isVisible ? 'Hide' : 'Show'} ${plugin.title}` const Icon = plugin.icon return ( { if (isVisible) { pluginContext.setVisiblePlugin(null) pluginResize.setHiddenElement('second') } else { pluginContext.setVisiblePlugin(plugin) pluginResize.setHiddenElement(null) } }} aria-label={label} > ) })}
schemaContext.introspect()} aria-label="Re-fetch GraphQL schema" > setShowDialog('short-keys')} aria-label="Open short keys dialog" > setShowDialog('settings')} aria-label="Open settings dialog" >
setShowDialog(null)}>
Short Keys
setShowDialog(null)} />
Short key Function
{modifier} {' + '} F Search in editor
{modifier} {' + '} K Search in documentation
{modifier} {' + '} Enter Execute query
Ctrl {' + '} Shift {' + '} P Prettify editors
Ctrl {' + '} Shift {' + '} M Merge fragments definitions into operation definition
Ctrl {' + '} Shift {' + '} C Copy query
Ctrl {' + '} Shift {' + '} R Re-fetch schema using introspection

The editors use{' '} CodeMirror Key Maps {' '} that add more short keys. This instance of GraphiQL uses sublime .

{ setShowDialog(null) setClearStorageStatus(null) }} >
Settings
{ setShowDialog(null) setClearStorageStatus(null) }} />
{storageContext ? (
Clear storage
Remove all locally stored data and start fresh.
) : null}
) } // Configure the UI by providing this Component as a child of GraphiQL. function GraphiQLLogo(props: PropsWithChildren) { return (
{props.children || ( Graph i QL )}
) } GraphiQLLogo.displayName = 'GraphiQLLogo' export default GraphiQL