From 4dfcbc05410b6e82163793098b694c9454c8145b Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 1 Apr 2023 03:46:02 +0200 Subject: [PATCH 01/23] perf --- .eslintrc.js | 8 ++- examples/graphiql-parcel/src/index.tsx | 49 +++++++++---------- .../src/editor/components/header-editor.tsx | 4 +- .../graphiql-react/src/toolbar/button.tsx | 33 +++++++------ packages/graphiql/src/components/GraphiQL.tsx | 6 +-- 5 files changed, 55 insertions(+), 45 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 1f4ffac28a5..7bdc8cf3c0b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -50,6 +50,12 @@ module.exports = { }, rules: { + '@arthurgeron/react-usememo/require-usememo': [ + 'error', + { + checkHookCalls: false, + }, + ], // Possible Errors (http://eslint.org/docs/rules/#possible-errors) 'no-console': 'error', 'no-constant-binary-expression': 2, @@ -310,7 +316,7 @@ module.exports = { '@typescript-eslint/no-namespace': 'off', }, - plugins: ['promise', 'sonarjs', 'unicorn'], + plugins: ['promise', 'sonarjs', 'unicorn', '@arthurgeron/react-usememo'], }, { // Rules that requires type information diff --git a/examples/graphiql-parcel/src/index.tsx b/examples/graphiql-parcel/src/index.tsx index d21c3c8fbee..43c9e767c8b 100644 --- a/examples/graphiql-parcel/src/index.tsx +++ b/examples/graphiql-parcel/src/index.tsx @@ -1,30 +1,29 @@ -import ReactDOM from 'react-dom'; +import { render } from 'react-dom'; import { GraphiQL } from 'graphiql'; +import type { Fetcher } from '@graphiql/toolkit'; +import { CSSProperties } from 'react'; -const App = () => ( - { - const data = await fetch( - 'https://swapi-graphql.netlify.app/.netlify/functions/index', - { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - body: JSON.stringify(graphQLParams), - credentials: 'same-origin', - }, - ); - return data.json().catch(() => data.text()); - }} - /> -); +const fetcher: Fetcher = async graphQLParams => { + const data = await fetch( + 'https://swapi-graphql.netlify.app/.netlify/functions/index', + { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify(graphQLParams), + credentials: 'same-origin', + }, + ); + return data.json().catch(() => data.text()); +}; -ReactDOM.render(, document.getElementById('root')); +const style: CSSProperties = { height: '100vh' }; + +const App = () => ; + +render(, document.getElementById('root')); // Hot Module Replacement -if (module.hot) { - module.hot.accept(); -} +module.hot?.accept(); diff --git a/packages/graphiql-react/src/editor/components/header-editor.tsx b/packages/graphiql-react/src/editor/components/header-editor.tsx index 5ab7dae7da3..672a2b759a2 100644 --- a/packages/graphiql-react/src/editor/components/header-editor.tsx +++ b/packages/graphiql-react/src/editor/components/header-editor.tsx @@ -24,8 +24,8 @@ export function HeaderEditor({ isHidden, ...hookArgs }: HeaderEditorProps) { const ref = useHeaderEditor(hookArgs, HeaderEditor); useEffect(() => { - if (headerEditor && !isHidden) { - headerEditor.refresh(); + if (!isHidden) { + headerEditor?.refresh(); } }, [headerEditor, isHidden]); diff --git a/packages/graphiql-react/src/toolbar/button.tsx b/packages/graphiql-react/src/toolbar/button.tsx index b5711d4b5fd..5c132264187 100644 --- a/packages/graphiql-react/src/toolbar/button.tsx +++ b/packages/graphiql-react/src/toolbar/button.tsx @@ -1,4 +1,4 @@ -import { forwardRef, useState } from 'react'; +import { forwardRef, MouseEventHandler, useCallback, useState } from 'react'; import { clsx } from 'clsx'; import { Tooltip, UnStyledButton } from '../ui'; @@ -11,8 +11,24 @@ type ToolbarButtonProps = { export const ToolbarButton = forwardRef< HTMLButtonElement, ToolbarButtonProps & JSX.IntrinsicElements['button'] ->(({ label, ...props }, ref) => { +>(({ label, onClick, ...props }, ref) => { const [error, setError] = useState(null); + const handleClick: MouseEventHandler = useCallback( + event => { + try { + onClick?.(event); + setError(null); + } catch (err) { + setError( + err instanceof Error + ? err + : new Error(`Toolbar button click failed: ${err}`), + ); + } + }, + [onClick], + ); + return ( { - try { - props.onClick?.(event); - setError(null); - } catch (err) { - setError( - err instanceof Error - ? err - : new Error(`Toolbar button click failed: ${err}`), - ); - } - }} + onClick={handleClick} aria-label={error ? error.message : label} aria-invalid={error ? 'true' : props['aria-invalid']} /> diff --git a/packages/graphiql/src/components/GraphiQL.tsx b/packages/graphiql/src/components/GraphiQL.tsx index 0db2be31ca8..295e64f8547 100644 --- a/packages/graphiql/src/components/GraphiQL.tsx +++ b/packages/graphiql/src/components/GraphiQL.tsx @@ -297,18 +297,18 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { ) || ( <> prettify()} + onClick={prettify} label="Prettify query (Shift-Ctrl-P)" > merge()} + onClick={merge} label="Merge fragments into query (Shift-Ctrl-M)" > - copy()} label="Copy query (Shift-Ctrl-C)"> + {props.toolbar?.additionalContent || null} From 52adc2488be1e94a32bfdb345f9303f368e66784 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 1 Apr 2023 03:52:58 +0200 Subject: [PATCH 02/23] more --- .../components/field-documentation.tsx | 12 ++++------ .../components/type-documentation.tsx | 23 ++++++++----------- .../graphiql-react/src/history/components.tsx | 20 ++++++++-------- 3 files changed, 24 insertions(+), 31 deletions(-) diff --git a/packages/graphiql-react/src/explorer/components/field-documentation.tsx b/packages/graphiql-react/src/explorer/components/field-documentation.tsx index 655e37b9d64..90b210be2d1 100644 --- a/packages/graphiql-react/src/explorer/components/field-documentation.tsx +++ b/packages/graphiql-react/src/explorer/components/field-documentation.tsx @@ -1,5 +1,5 @@ import { GraphQLArgument } from 'graphql'; -import { useState } from 'react'; +import { useCallback, useState } from 'react'; import { Button, MarkdownContent } from '../../ui'; import { ExplorerFieldDef } from '../context'; @@ -36,6 +36,9 @@ export function FieldDocumentation(props: FieldDocumentationProps) { function Arguments({ field }: { field: ExplorerFieldDef }) { const [showDeprecated, setShowDeprecated] = useState(false); + const handleShowDeprecated = useCallback(() => { + setShowDeprecated(true); + }, []); if (!('args' in field)) { return null; @@ -68,12 +71,7 @@ function Arguments({ field }: { field: ExplorerFieldDef }) { ))} ) : ( - ) diff --git a/packages/graphiql-react/src/explorer/components/type-documentation.tsx b/packages/graphiql-react/src/explorer/components/type-documentation.tsx index 205ab71a3b5..3e5bccbea62 100644 --- a/packages/graphiql-react/src/explorer/components/type-documentation.tsx +++ b/packages/graphiql-react/src/explorer/components/type-documentation.tsx @@ -8,7 +8,7 @@ import { isNamedType, isObjectType, } from 'graphql'; -import { useState } from 'react'; +import { useCallback, useState } from 'react'; import { useSchemaContext } from '../../schema'; import { Button, MarkdownContent } from '../../ui'; @@ -63,6 +63,10 @@ function ImplementsInterfaces({ type }: { type: GraphQLNamedType }) { function Fields({ type }: { type: GraphQLNamedType }) { const [showDeprecated, setShowDeprecated] = useState(false); + const handleShowDeprecated = useCallback(() => { + setShowDeprecated(true); + }, []); + if ( !isObjectType(type) && !isInterfaceType(type) && @@ -101,12 +105,7 @@ function Fields({ type }: { type: GraphQLNamedType }) { ))} ) : ( - ) @@ -158,6 +157,9 @@ function Field({ field }: { field: ExplorerFieldDef }) { function EnumValues({ type }: { type: GraphQLNamedType }) { const [showDeprecated, setShowDeprecated] = useState(false); + const handleShowDeprecated = useCallback(() => { + setShowDeprecated(true); + }, []); if (!isEnumType(type)) { return null; @@ -190,12 +192,7 @@ function EnumValues({ type }: { type: GraphQLNamedType }) { ))} ) : ( - ) diff --git a/packages/graphiql-react/src/history/components.tsx b/packages/graphiql-react/src/history/components.tsx index 3ca42552d85..34850c3f874 100644 --- a/packages/graphiql-react/src/history/components.tsx +++ b/packages/graphiql-react/src/history/components.tsx @@ -1,5 +1,5 @@ import { QueryStoreItem } from '@graphiql/toolkit'; -import { Fragment, useEffect, useRef, useState } from 'react'; +import { Fragment, useCallback, useEffect, useRef, useState } from 'react'; import { clsx } from 'clsx'; import { useEditorContext } from '../editor'; @@ -56,8 +56,8 @@ export function HistoryItem(props: QueryHistoryItemProps) { const [isEditable, setIsEditable] = useState(false); useEffect(() => { - if (isEditable && inputRef.current) { - inputRef.current.focus(); + if (isEditable) { + inputRef.current?.focus(); } }, [isEditable]); @@ -66,6 +66,11 @@ export function HistoryItem(props: QueryHistoryItemProps) { props.item.operationName || formatQuery(props.item.query); + const handleSave = useCallback(() => { + setIsEditable(false); + editLabel({ ...props.item, label: inputRef.current?.value }); + }, [editLabel, props.item]); + return (
  • {isEditable ? ( @@ -84,14 +89,7 @@ export function HistoryItem(props: QueryHistoryItemProps) { }} placeholder="Type a label" /> - { - setIsEditable(false); - editLabel({ ...props.item, label: inputRef.current?.value }); - }} - > + Save Date: Sat, 1 Apr 2023 03:57:37 +0200 Subject: [PATCH 03/23] more --- .../src/explorer/components/search.tsx | 116 ++++++++++-------- 1 file changed, 67 insertions(+), 49 deletions(-) diff --git a/packages/graphiql-react/src/explorer/components/search.tsx b/packages/graphiql-react/src/explorer/components/search.tsx index 886899d7b89..c0c6d0e2c0e 100644 --- a/packages/graphiql-react/src/explorer/components/search.tsx +++ b/packages/graphiql-react/src/explorer/components/search.tsx @@ -14,7 +14,15 @@ import { isInterfaceType, isObjectType, } from 'graphql'; -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { + ChangeEventHandler, + KeyboardEventHandler, + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; import { MagnifyingGlassIcon } from '../../icons'; import { useSchemaContext } from '../../schema'; import debounce from '../../utility/debounce'; @@ -67,63 +75,73 @@ export function Search() { isInterfaceType(navItem.def) || isInputObjectType(navItem.def); + const handleSelect = useCallback( + (value: string) => { + const def = value as unknown as TypeMatch | FieldMatch; + push( + 'field' in def + ? { name: def.field.name, def: def.field } + : { name: def.type.name, def: def.type }, + ); + }, + [push], + ); + + const handleChange: ChangeEventHandler = useCallback( + event => { + setSearchValue(event.target.value); + }, + [], + ); + + const handleKeyDown: KeyboardEventHandler = useCallback( + event => { + if (!event.isDefaultPrevented()) { + const container = popoverRef.current; + if (!container) { + return; + } + + window.requestAnimationFrame(() => { + const element = container.querySelector('[aria-selected=true]'); + if (!(element instanceof HTMLElement)) { + return; + } + const top = element.offsetTop - container.scrollTop; + const bottom = + container.scrollTop + + container.clientHeight - + (element.offsetTop + element.clientHeight); + if (bottom < 0) { + container.scrollTop -= bottom; + } + if (top < 0) { + container.scrollTop += top; + } + }); + } + + // We don't want for example "Escape" key presses to bubble up + // further. This could have other effects like closing a dialog + // that contains this component. + event.stopPropagation(); + }, + [], + ); + return shouldSearchBoxAppear ? ( - { - const def = value as unknown as TypeMatch | FieldMatch; - push( - 'field' in def - ? { name: def.field.name, def: def.field } - : { name: def.type.name, def: def.type }, - ); - }} - > +
    { - if (inputRef.current) { - inputRef.current.focus(); - } + inputRef.current?.focus(); }} > { - setSearchValue(event.target.value); - }} - onKeyDown={event => { - if (!event.isDefaultPrevented()) { - const container = popoverRef.current; - if (!container) { - return; - } - - window.requestAnimationFrame(() => { - const element = container.querySelector('[aria-selected=true]'); - if (!(element instanceof HTMLElement)) { - return; - } - const top = element.offsetTop - container.scrollTop; - const bottom = - container.scrollTop + - container.clientHeight - - (element.offsetTop + element.clientHeight); - if (bottom < 0) { - container.scrollTop -= bottom; - } - if (top < 0) { - container.scrollTop += top; - } - }); - } - - // We don't want for example "Escape" key presses to bubble up - // further. This could have other effects like closing a dialog - // that contains this component. - event.stopPropagation(); - }} + onChange={handleChange} + onKeyDown={handleKeyDown} placeholder="⌘ K" ref={inputRef} value={searchValue} From f24c7b28ac8cd65df8faf994baec18493d350544 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 1 Apr 2023 03:59:52 +0200 Subject: [PATCH 04/23] more --- examples/graphiql-webpack/src/index.jsx | 45 +++++++++++++++---------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/examples/graphiql-webpack/src/index.jsx b/examples/graphiql-webpack/src/index.jsx index e955f2693ff..905c6ea945a 100644 --- a/examples/graphiql-webpack/src/index.jsx +++ b/examples/graphiql-webpack/src/index.jsx @@ -51,6 +51,25 @@ ${getQuery(arg, 2)} const snippets = [exampleSnippetOne, exampleSnippetTwo]; +const fetcher = async (graphQLParams, options) => { + const data = await fetch( + 'https://swapi-graphql.netlify.app/.netlify/functions/index', + { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + ...options.headers, + }, + body: JSON.stringify(graphQLParams), + credentials: 'same-origin', + }, + ); + return data.json().catch(() => data.text()); +}; + +const style = { height: '100vh' }; + const App = () => { const [query, setQuery] = React.useState(''); const explorerPlugin = useExplorerPlugin({ @@ -62,28 +81,18 @@ const App = () => { snippets, }); + const plugins = React.useMemo( + () => [explorerPlugin, exporterPlugin], + [explorerPlugin, exporterPlugin], + ); + return ( { - const data = await fetch( - 'https://swapi-graphql.netlify.app/.netlify/functions/index', - { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - ...options.headers, - }, - body: JSON.stringify(graphQLParams), - credentials: 'same-origin', - }, - ); - return data.json().catch(() => data.text()); - }} + plugins={plugins} + fetcher={fetcher} /> ); }; From 8430e5d9187347bd591fccf4d14ebeebbfc8dd14 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 1 Apr 2023 04:04:27 +0200 Subject: [PATCH 05/23] more --- .../graphiql-plugin-explorer/src/index.tsx | 222 ++++++++++-------- 1 file changed, 119 insertions(+), 103 deletions(-) diff --git a/packages/graphiql-plugin-explorer/src/index.tsx b/packages/graphiql-plugin-explorer/src/index.tsx index 4fd4116b678..35be73d05e8 100644 --- a/packages/graphiql-plugin-explorer/src/index.tsx +++ b/packages/graphiql-plugin-explorer/src/index.tsx @@ -5,122 +5,138 @@ import { useSchemaContext, } from '@graphiql/react'; import GraphiQLExplorer, { GraphiQLExplorerProps } from 'graphiql-explorer'; -import React, { useRef } from 'react'; +import React, { useCallback, useRef } from 'react'; import './graphiql-explorer.d.ts'; import './index.css'; +const colors = { + keyword: 'hsl(var(--color-primary))', + def: 'hsl(var(--color-tertiary))', + property: 'hsl(var(--color-info))', + qualifier: 'hsl(var(--color-secondary))', + attribute: 'hsl(var(--color-tertiary))', + number: 'hsl(var(--color-success))', + string: 'hsl(var(--color-warning))', + builtin: 'hsl(var(--color-success))', + string2: 'hsl(var(--color-secondary))', + variable: 'hsl(var(--color-secondary))', + atom: 'hsl(var(--color-tertiary))', +}; + +const arrowOpen = ( + + + +); + +const arrowClosed = ( + + + +); + +const checkboxUnchecked = ( + + + +); +const checkboxChecked = ( + + + + +); + +const styles = { + buttonStyle: { + backgroundColor: 'transparent', + border: 'none', + color: 'hsla(var(--color-neutral), var(--alpha-secondary, 0.6))', + cursor: 'pointer', + fontSize: '1em', + }, + explorerActionsStyle: { + padding: 'var(--px-8) var(--px-4)', + }, + actionButtonStyle: { + backgroundColor: 'transparent', + border: 'none', + color: 'hsla(var(--color-neutral), var(--alpha-secondary, 0.6))', + cursor: 'pointer', + fontSize: '1em', + }, +}; + function ExplorerPlugin(props: GraphiQLExplorerProps) { const { setOperationName } = useEditorContext({ nonNull: true }); const { schema } = useSchemaContext({ nonNull: true }); const { run } = useExecutionContext({ nonNull: true }); + const handleRunOperation = useCallback( + (operationName: string | null) => { + if (operationName) { + setOperationName(operationName); + } + run(); + }, + [run, setOperationName], + ); + return ( { - if (operationName) { - setOperationName(operationName); - } - run(); - }} + onRunOperation={handleRunOperation} explorerIsOpen - colors={{ - keyword: 'hsl(var(--color-primary))', - def: 'hsl(var(--color-tertiary))', - property: 'hsl(var(--color-info))', - qualifier: 'hsl(var(--color-secondary))', - attribute: 'hsl(var(--color-tertiary))', - number: 'hsl(var(--color-success))', - string: 'hsl(var(--color-warning))', - builtin: 'hsl(var(--color-success))', - string2: 'hsl(var(--color-secondary))', - variable: 'hsl(var(--color-secondary))', - atom: 'hsl(var(--color-tertiary))', - }} - arrowOpen={ - - - - } - arrowClosed={ - - - - } - checkboxUnchecked={ - - - - } - checkboxChecked={ - - - - - } - styles={{ - buttonStyle: { - backgroundColor: 'transparent', - border: 'none', - color: 'hsla(var(--color-neutral), var(--alpha-secondary, 0.6))', - cursor: 'pointer', - fontSize: '1em', - }, - explorerActionsStyle: { - padding: 'var(--px-8) var(--px-4)', - }, - actionButtonStyle: { - backgroundColor: 'transparent', - border: 'none', - color: 'hsla(var(--color-neutral), var(--alpha-secondary, 0.6))', - cursor: 'pointer', - fontSize: '1em', - }, - }} + colors={colors} + arrowOpen={arrowOpen} + arrowClosed={arrowClosed} + checkboxUnchecked={checkboxUnchecked} + checkboxChecked={checkboxChecked} + styles={styles} {...props} /> ); From 2994b1a8057744d3c01c84c31afe5391ea6da0f1 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 1 Apr 2023 04:08:56 +0200 Subject: [PATCH 06/23] more --- packages/graphiql/src/components/GraphiQL.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/graphiql/src/components/GraphiQL.tsx b/packages/graphiql/src/components/GraphiQL.tsx index 295e64f8547..222dab17ddf 100644 --- a/packages/graphiql/src/components/GraphiQL.tsx +++ b/packages/graphiql/src/components/GraphiQL.tsx @@ -9,6 +9,7 @@ import React, { ComponentType, PropsWithChildren, ReactNode, + useCallback, useState, } from 'react'; @@ -165,6 +166,7 @@ export function GraphiQL({ ); } + // Export main windows/panes to be used separately if desired. GraphiQL.Logo = GraphiQLLogo; GraphiQL.Toolbar = GraphiQLToolbar; @@ -296,10 +298,7 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { isChildComponentType(child, GraphiQL.Toolbar), ) || ( <> - + { + const onClickReference = useCallback(() => { if (pluginResize.hiddenElement === 'first') { pluginResize.setHiddenElement(null); } - }; + }, [pluginResize]); const modifier = window.navigator.platform.toLowerCase().indexOf('mac') === 0 ? ( From 703904c36beaab943f66a8ca0cae2baf6a4b9548 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 1 Apr 2023 04:13:46 +0200 Subject: [PATCH 07/23] more --- packages/graphiql/src/components/GraphiQL.tsx | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/graphiql/src/components/GraphiQL.tsx b/packages/graphiql/src/components/GraphiQL.tsx index 222dab17ddf..f3080c10a0a 100644 --- a/packages/graphiql/src/components/GraphiQL.tsx +++ b/packages/graphiql/src/components/GraphiQL.tsx @@ -324,6 +324,15 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { } }, [pluginResize]); + const handleClearData = useCallback(() => { + try { + storageContext?.clear(); + setClearStorageStatus('success'); + } catch { + setClearStorageStatus('error'); + } + }, [storageContext]); + const modifier = window.navigator.platform.toLowerCase().indexOf('mac') === 0 ? ( Cmd @@ -366,7 +375,7 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { schemaContext.introspect()} + onClick={schemaContext.introspect} aria-label="Re-fetch GraphQL schema" > editorContext.addTab()} + onClick={editorContext.addTab} aria-label="Add tab" >
  • {isEditable ? ( @@ -92,13 +111,7 @@ export function HistoryItem(props: QueryHistoryItemProps) { Save - { - setIsEditable(false); - }} - > + @@ -119,10 +132,7 @@ export function HistoryItem(props: QueryHistoryItemProps) { { - e.stopPropagation(); - setIsEditable(true); - }} + onClick={handleEditLabel} aria-label="Edit label" >
  • {isEditable ? ( @@ -120,11 +133,7 @@ export function HistoryItem(props: QueryHistoryItemProps) { { - queryEditor?.setValue(props.item.query ?? ''); - variableEditor?.setValue(props.item.variables ?? ''); - headerEditor?.setValue(props.item.headers ?? ''); - }} + onClick={handleHistoryItemClick} > {displayName} @@ -144,10 +153,7 @@ export function HistoryItem(props: QueryHistoryItemProps) { { - e.stopPropagation(); - toggleFavorite(props.item); - }} + onClick={handleToggleFavorite} aria-label={ props.item.favorite ? 'Remove favorite' : 'Add favorite' } diff --git a/packages/graphiql/src/components/GraphiQL.tsx b/packages/graphiql/src/components/GraphiQL.tsx index 1cd50a98965..01b49ce9326 100644 --- a/packages/graphiql/src/components/GraphiQL.tsx +++ b/packages/graphiql/src/components/GraphiQL.tsx @@ -374,11 +374,28 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { [], ); + 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('first'); + } else { + context.setVisiblePlugin(plugin); + pluginResize.setHiddenElement(null); + } + }, + [], + ); + return (
    - {pluginContext?.plugins.map(plugin => { + {pluginContext?.plugins.map((plugin, index) => { const isVisible = plugin === pluginContext.visiblePlugin; const label = `${isVisible ? 'Hide' : 'Show'} ${plugin.title}`; const Icon = plugin.icon; @@ -387,15 +404,8 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { { - if (isVisible) { - pluginContext.setVisiblePlugin(null); - pluginResize.setHiddenElement('first'); - } else { - pluginContext.setVisiblePlugin(plugin); - pluginResize.setHiddenElement(null); - } - }} + onClick={handlePluginClick} + data-index={index} aria-label={label} >
  • diff --git a/packages/graphiql/src/components/GraphiQL.tsx b/packages/graphiql/src/components/GraphiQL.tsx index 01b49ce9326..51f76ea1d77 100644 --- a/packages/graphiql/src/components/GraphiQL.tsx +++ b/packages/graphiql/src/components/GraphiQL.tsx @@ -388,7 +388,7 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { pluginResize.setHiddenElement(null); } }, - [], + [pluginContext, pluginResize], ); return ( From b754897da9a6e02577d1a7c1ec8108b62adc8790 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 15 Apr 2023 02:04:18 +0200 Subject: [PATCH 17/23] more --- packages/graphiql/src/components/GraphiQL.tsx | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/graphiql/src/components/GraphiQL.tsx b/packages/graphiql/src/components/GraphiQL.tsx index 51f76ea1d77..4414ffbca54 100644 --- a/packages/graphiql/src/components/GraphiQL.tsx +++ b/packages/graphiql/src/components/GraphiQL.tsx @@ -391,6 +391,22 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { [pluginContext, pluginResize], ); + const handleVariablesTabClick: MouseEventHandler = + useCallback(() => { + if (editorToolsResize.hiddenElement === 'second') { + editorToolsResize.setHiddenElement(null); + } + setActiveSecondaryEditor('variables'); + }, [editorToolsResize]); + + const handleHeadersTabClick: MouseEventHandler = + useCallback(() => { + if (editorToolsResize.hiddenElement === 'second') { + editorToolsResize.setHiddenElement(null); + } + setActiveSecondaryEditor('headers'); + }, [editorToolsResize]); + return (
    @@ -580,12 +596,7 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { ? 'active' : '' } - onClick={() => { - if (editorToolsResize.hiddenElement === 'second') { - editorToolsResize.setHiddenElement(null); - } - setActiveSecondaryEditor('variables'); - }} + onClick={handleVariablesTabClick} > Variables @@ -598,14 +609,7 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { ? 'active' : '' } - onClick={() => { - if ( - editorToolsResize.hiddenElement === 'second' - ) { - editorToolsResize.setHiddenElement(null); - } - setActiveSecondaryEditor('headers'); - }} + onClick={handleHeadersTabClick} > Headers From b00f9c0f114a73d55388bfe5c72aef7e843ed254 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 15 Apr 2023 02:10:00 +0200 Subject: [PATCH 18/23] more --- packages/graphiql/src/components/GraphiQL.tsx | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/graphiql/src/components/GraphiQL.tsx b/packages/graphiql/src/components/GraphiQL.tsx index 4414ffbca54..04f85ff93fe 100644 --- a/packages/graphiql/src/components/GraphiQL.tsx +++ b/packages/graphiql/src/components/GraphiQL.tsx @@ -407,6 +407,18 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { setActiveSecondaryEditor('headers'); }, [editorToolsResize]); + const toggleEditorTools: MouseEventHandler = + useCallback(() => { + editorToolsResize.setHiddenElement( + editorToolsResize.hiddenElement === 'second' ? null : 'second', + ); + }, [editorToolsResize]); + + const handleDismissShortKeysDialog: MouseEventHandler = + useCallback(() => { + setShowDialog(null); + }, []); + return (
    @@ -624,13 +636,7 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { > { - editorToolsResize.setHiddenElement( - editorToolsResize.hiddenElement === 'second' - ? null - : 'second', - ); - }} + onClick={toggleEditorTools} aria-label={ editorToolsResize.hiddenElement === 'second' ? 'Show editor tools' @@ -702,11 +708,11 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) {
    setShowDialog(null)} + onDismiss={handleDismissShortKeysDialog} >
    Short Keys
    - setShowDialog(null)} /> +
    From f6556ff76a0190f6615a82c998170d656d410001 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 15 Apr 2023 02:31:36 +0200 Subject: [PATCH 19/23] more --- packages/graphiql/src/components/GraphiQL.tsx | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/graphiql/src/components/GraphiQL.tsx b/packages/graphiql/src/components/GraphiQL.tsx index 04f85ff93fe..c9c4e3b21a1 100644 --- a/packages/graphiql/src/components/GraphiQL.tsx +++ b/packages/graphiql/src/components/GraphiQL.tsx @@ -419,6 +419,12 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { setShowDialog(null); }, []); + const handleDismissSettingsDialog: MouseEventHandler = + useCallback(() => { + setShowDialog(null); + setClearStorageStatus(null); + }, []); + return (
    @@ -807,19 +813,11 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) {
    { - setShowDialog(null); - setClearStorageStatus(null); - }} + onDismiss={handleDismissSettingsDialog} >
    Settings
    - { - setShowDialog(null); - setClearStorageStatus(null); - }} - /> +
    {props.showPersistHeadersSettings ? (
    From 93740a47be9ed036c1a8ed346ba6a6614b16640e Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 15 Apr 2023 02:35:00 +0200 Subject: [PATCH 20/23] add cspell words --- custom-words.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/custom-words.txt b/custom-words.txt index 13a2c04df3d..96728a85636 100644 --- a/custom-words.txt +++ b/custom-words.txt @@ -65,6 +65,7 @@ LekoArts // packages and tools argparse +arthurgeron atpl browserslist bundlephobia @@ -104,6 +105,7 @@ templayed typedoc twing undici +usememo velocityjs vite vitejs From 26222f33c890f296f085800ba060f94b522d6a75 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 15 Apr 2023 02:41:39 +0200 Subject: [PATCH 21/23] rename handleTheme to handleChangeTheme --- packages/graphiql/src/components/GraphiQL.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/graphiql/src/components/GraphiQL.tsx b/packages/graphiql/src/components/GraphiQL.tsx index c9c4e3b21a1..58875ba690d 100644 --- a/packages/graphiql/src/components/GraphiQL.tsx +++ b/packages/graphiql/src/components/GraphiQL.tsx @@ -351,7 +351,7 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { [editorContext], ); - const handleTheme: MouseEventHandler = useCallback( + const handleChangeTheme: MouseEventHandler = useCallback( event => { const selectedTheme = event.currentTarget.dataset.theme as | 'light' @@ -865,7 +865,7 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { @@ -873,7 +873,7 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { type="button" className={theme === 'light' ? 'active' : ''} data-theme="light" - onClick={handleTheme} + onClick={handleChangeTheme} > Light @@ -881,7 +881,7 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) { type="button" className={theme === 'dark' ? 'active' : ''} data-theme="dark" - onClick={handleTheme} + onClick={handleChangeTheme} > Dark From e36560263db92007f4f4bfc4bcfe2e21e536bb8f Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 27 May 2023 22:30:18 +0200 Subject: [PATCH 22/23] Update packages/graphiql-react/src/explorer/components/search.tsx Co-authored-by: Ted Thibodeau Jr --- packages/graphiql-react/src/explorer/components/search.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/graphiql-react/src/explorer/components/search.tsx b/packages/graphiql-react/src/explorer/components/search.tsx index c0c6d0e2c0e..ecd4258432a 100644 --- a/packages/graphiql-react/src/explorer/components/search.tsx +++ b/packages/graphiql-react/src/explorer/components/search.tsx @@ -121,7 +121,7 @@ export function Search() { }); } - // We don't want for example "Escape" key presses to bubble up + // We don't want, for example, "Escape" key presses to bubble up // further. This could have other effects like closing a dialog // that contains this component. event.stopPropagation(); From 95187670a2d72a68fe9109c9e0c59a1c94b38365 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 27 May 2023 22:39:14 +0200 Subject: [PATCH 23/23] rebase fixes --- .eslintrc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.js b/.eslintrc.js index 3c3251eb10c..97a639e3807 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -420,6 +420,7 @@ module.exports = { 'no-undef': 'off', 'react/jsx-no-undef': 'off', 'react-hooks/rules-of-hooks': 'off', + '@arthurgeron/react-usememo/require-usememo': 'off', }, }, ],