/* 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,
useCopyQuery,
useDragResize,
useEditorContext,
useExecutionContext,
useMergeQuery,
usePluginContext,
usePrettifyEditors,
useSchemaContext,
useTheme,
VariableEditor,
} from '@graphiql/react'
import { Fetcher } from '@graphiql/toolkit'
import clsx from 'clsx'
import { useEffect, useState } from 'react'
import styles from './graphiql.module.css'
export type GraphiQLProps = {
fetcher: Fetcher
theme?: 'dark' | 'light'
accessToken?: string
}
const 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 (
)
}
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 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 = (
<>
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 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)
}}
/>
))}
editorContext.addTab()}
aria-label="Add tab"
>
>
) : null}
{hasSingleTab ? (
editorContext.addTab()}
aria-label="Add tab"
>
) : null}
{
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}
{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"
>
)
}
export default GraphiQL