/* Based on https://github.com/graphql/graphiql/blob/main/packages/graphiql/src/components/GraphiQL.tsx */ import { ChevronDownIcon, ChevronUpIcon, CopyIcon, ExecuteButton, GraphiQLProvider, HeaderEditor, MergeIcon, PlusIcon, PrettifyIcon, QueryEditor, ReloadIcon, ResponseEditor, Spinner, Tab, Tabs, ToolbarButton, Tooltip, UnStyledButton, VariableEditor, useCopyQuery, useDragResize, useEditorContext, useExecutionContext, useMergeQuery, usePluginContext, usePrettifyEditors, useSchemaContext, useTheme, } from '@graphiql/react' import { Fetcher } from '@graphiql/toolkit' import clsx from 'clsx' import { MouseEventHandler, useCallback, useEffect, useState } from 'react' import styles from './graphiql.module.css' export interface GraphiQLProps { fetcher: Fetcher theme?: 'dark' | 'light' accessToken?: string } export default function GraphiQL({ fetcher, theme = 'dark', accessToken }: 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 ( ) } interface 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 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 toolbar = ( <> > ) const onClickReference = useCallback(() => { if (pluginResize.hiddenElement === 'second') { pluginResize.setHiddenElement(null) } }, [pluginResize]) const handleAddTab = editorContext.addTab const handleRefetchSchema = schemaContext.introspect const handleReorder = editorContext.moveTab const handlePluginClick: MouseEventHandler = useCallback( (e) => { const context = pluginContext! const pluginIndex = Number(e.currentTarget.dataset.index!) const plugin = context.plugins.find((_, index) => pluginIndex === index)! const isVisible = plugin === context.visiblePlugin if (isVisible) { context.setVisiblePlugin(null) pluginResize.setHiddenElement('second') } else { context.setVisiblePlugin(plugin) pluginResize.setHiddenElement(null) } }, [pluginContext, pluginResize] ) const handleToolsTabClick: MouseEventHandler = useCallback( (event) => { if (editorToolsResize.hiddenElement === 'second') { editorToolsResize.setHiddenElement(null) } setActiveSecondaryEditor(event.currentTarget.dataset.name as 'variables' | 'headers') }, [editorToolsResize] ) const toggleEditorTools: MouseEventHandler = useCallback(() => { editorToolsResize.setHiddenElement( editorToolsResize.hiddenElement === 'second' ? null : 'second' ) }, [editorToolsResize]) const addTab = ( ) const hasSingleTab = editorContext.tabs.length === 1 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) }} /> ))} {addTab} > )} {hasSingleTab && {addTab}} {toolbar} Variables Headers {editorToolsResize.hiddenElement === 'second' ? ( ) : ( )} {executionContext.isFetching ? : null} {pluginContext?.visiblePlugin && ( )} {PluginContent ? : null} {pluginContext?.plugins.map((plugin, index) => { const isVisible = plugin === pluginContext.visiblePlugin const label = `${isVisible ? 'Hide' : 'Show'} ${plugin.title}` const Icon = plugin.icon return ( ) })} ) }