diff --git a/.changeset/five-pillows-fail.md b/.changeset/five-pillows-fail.md index d7f6afeef25..e98c1fdc646 100644 --- a/.changeset/five-pillows-fail.md +++ b/.changeset/five-pillows-fail.md @@ -3,8 +3,8 @@ --- Add new components: -- UI components (`Button`, `ButtonGroup`, `Dialog`, `Menu`, `Spinner`, `Tab`, `Tabs`, `UnStyledButton` and lots of icon components) +- UI components (`Button`, `ButtonGroup`, `Dialog`, `Menu`, `Spinner`, `Tab`, `Tabs`, `Tooltip`, `UnStyledButton` and lots of icon components) - Editor components (`QueryEditor`, `VariableEditor`, `HeaderEditor` and `ResponseEditor`) -- Toolbar components (`ExecuteButton` and `ToolbarButton`) +- Toolbar components (`ExecuteButton`, `ToolbarButton`, `ToolbarMenu` and `ToolbarSelect`) - Docs components (`Argument`, `DefaultValue`, `DeprecationReason`, `Directive`, `DocExplorer`, `ExplorerSection`, `FieldDocumentation`, `FieldLink`, `SchemaDocumentation`, `Search`, `TypeDocumentation` and `TypeLink`) - `History` component diff --git a/.changeset/real-waves-enjoy.md b/.changeset/real-waves-enjoy.md index f729f5fba94..c0797cd7f48 100644 --- a/.changeset/real-waves-enjoy.md +++ b/.changeset/real-waves-enjoy.md @@ -5,6 +5,8 @@ BREAKING: The following static properties of the `GraphiQL` component have been removed: - `GraphiQL.Button`: You can use the `ToolbarButton` component from `@graphiql/react` instead. - `GraphiQL.ToolbarButton`: This exposed the same component as `GraphiQL.Button`. +- `GraphiQL.Menu`: You can use the `ToolbarMenu` component from `@graphiql/react` instead. +- `GraphiQL.MenuItem`: You can use the `ToolbarMenu.Item` component from `@graphiql/react` instead. - `GraphiQL.Group`: Grouping multiple buttons side-by-side is not provided out-of-the box anymore in the new GraphiQL UI. If you want to implement a similar feature in the new vertical toolbar you can do so by adding your own styles for your custom toolbar elements. Example: ```jsx import { GraphiQL } from "graphiql"; diff --git a/.changeset/red-zoos-divide.md b/.changeset/red-zoos-divide.md index aac443000ea..e8b04c69311 100644 --- a/.changeset/red-zoos-divide.md +++ b/.changeset/red-zoos-divide.md @@ -5,3 +5,7 @@ BREAKING: The following exports of the `graphiql` package have been removed: - `DocExplorer`: Now exported from `@graphiql/react` as `DocExplorer` - The `schema` prop has been removed, the component now uses the schema provided by the `ExplorerContext` +- `ToolbarMenu`: Now exported from `@graphiql/react` as `ToolbarMenu` +- `ToolbarMenuItem`: Now exported from `@graphiql/react` as `ToolbarMenu.Item` +- `ToolbarSelect`: Now exported from `@graphiql/react` as `ToolbarListbox` +- `ToolbarSelectOption`: Now exported from `@graphiql/react` as `ToolbarListbox.Option` diff --git a/custom-words.txt b/custom-words.txt index 94ce626729c..6039da2bc17 100644 --- a/custom-words.txt +++ b/custom-words.txt @@ -118,6 +118,7 @@ languageservice linenumber linenumbers linkify +listbox listvalues matchingbracket modulemap diff --git a/packages/graphiql-react/package.json b/packages/graphiql-react/package.json index e5c2ada3b47..9c01b0c9b65 100644 --- a/packages/graphiql-react/package.json +++ b/packages/graphiql-react/package.json @@ -40,7 +40,9 @@ "@graphiql/toolkit": "^1.0.0-next.2", "@reach/combobox": "^0.17.0", "@reach/dialog": "^0.17.0", + "@reach/listbox": "^0.17.0", "@reach/menu-button": "^0.17.0", + "@reach/tooltip": "^0.17.0", "@reach/visually-hidden": "^0.17.0", "codemirror": "^5.65.3", "codemirror-graphql": "^2.0.0-next.2", diff --git a/packages/graphiql-react/src/editor/context.tsx b/packages/graphiql-react/src/editor/context.tsx index 2701ed54c3f..e1f2542bf05 100644 --- a/packages/graphiql-react/src/editor/context.tsx +++ b/packages/graphiql-react/src/editor/context.tsx @@ -319,13 +319,13 @@ const DEFAULT_QUERY = `# Welcome to GraphiQL # # Keyboard shortcuts: # -# Prettify Query: Shift-Ctrl-P (or press the prettify button above) +# Prettify query: Shift-Ctrl-P (or press the prettify button) # -# Merge Query: Shift-Ctrl-M (or press the merge button above) +# Merge fragments: Shift-Ctrl-M (or press the merge button) # -# Run Query: Ctrl-Enter (or press the play button above) +# Run Query: Ctrl-Enter (or press the play button) # -# Auto Complete: Ctrl-Space (or just start typing) +# Auto Complete: Ctrl-Space (or just start typing) # `; diff --git a/packages/graphiql-react/src/history/__tests__/components.spec.tsx b/packages/graphiql-react/src/history/__tests__/components.spec.tsx index 9366c4b67bc..180287b0175 100644 --- a/packages/graphiql-react/src/history/__tests__/components.spec.tsx +++ b/packages/graphiql-react/src/history/__tests__/components.spec.tsx @@ -118,10 +118,10 @@ describe('QueryHistoryItem', () => { }); it('renders label input if the edit label button is clicked', () => { - const { container, getByTitle } = render( + const { container, getByLabelText } = render( , ); - fireEvent.click(getByTitle('Edit label')); + fireEvent.click(getByLabelText('Edit label')); expect(container.querySelectorAll('li.editable').length).toBe(1); expect(container.querySelectorAll('input').length).toBe(1); expect( diff --git a/packages/graphiql-react/src/history/components.tsx b/packages/graphiql-react/src/history/components.tsx index d3bf98d3031..8c5ffbf3e2f 100644 --- a/packages/graphiql-react/src/history/components.tsx +++ b/packages/graphiql-react/src/history/components.tsx @@ -3,7 +3,7 @@ import { Fragment, useEffect, useRef, useState } from 'react'; import { useEditorContext } from '../editor'; import { CloseIcon, PenIcon, StarFilledIcon, StarIcon } from '../icons'; -import { UnStyledButton } from '../ui'; +import { Tooltip, UnStyledButton } from '../ui'; import { useHistoryContext } from './context'; import './style.css'; @@ -118,28 +118,40 @@ export function HistoryItem(props: QueryHistoryItemProps) { > {displayName} - { - e.stopPropagation(); - setIsEditable(true); - }} - > - - - { - e.stopPropagation(); - toggleFavorite(props.item); - }} - title={props.item.favorite ? 'Remove favorite' : 'Add favorite'} + + { + e.stopPropagation(); + setIsEditable(true); + }} + aria-label="Edit label" + > + + + - {props.item.favorite ? : } - + { + e.stopPropagation(); + toggleFavorite(props.item); + }} + aria-label={ + props.item.favorite ? 'Remove favorite' : 'Add favorite' + } + > + {props.item.favorite ? ( + + )} diff --git a/packages/graphiql-react/src/history/style.css b/packages/graphiql-react/src/history/style.css index 804fd158ede..f29c5830f65 100644 --- a/packages/graphiql-react/src/history/style.css +++ b/packages/graphiql-react/src/history/style.css @@ -81,7 +81,6 @@ button.graphiql-history-item-action { & > svg { height: 14px; - pointer-events: none; width: 14px; } } diff --git a/packages/graphiql-react/src/index.ts b/packages/graphiql-react/src/index.ts index 75c5ddad60e..852716f3534 100644 --- a/packages/graphiql-react/src/index.ts +++ b/packages/graphiql-react/src/index.ts @@ -47,7 +47,6 @@ export { HistoryContextProvider, useHistoryContext, } from './history'; -export * from './icons'; export { SchemaContext, SchemaContextProvider, @@ -59,10 +58,12 @@ export { useStorageContext, } from './storage'; export { useTheme } from './theme'; -export * from './toolbar'; -export * from './ui'; export { useDragResize } from './utility/resize'; +export * from './icons'; +export * from './ui'; +export * from './toolbar'; + export type { EditorContextType, ResponseTooltipType, diff --git a/packages/graphiql-react/src/toolbar/button.css b/packages/graphiql-react/src/toolbar/button.css index 44fb55d3e96..d4773bd50c3 100644 --- a/packages/graphiql-react/src/toolbar/button.css +++ b/packages/graphiql-react/src/toolbar/button.css @@ -6,8 +6,4 @@ button.graphiql-toolbar-button { &.error { background: hsla(var(--color-error), 0.15); } - - & > svg { - pointer-events: none; - } } diff --git a/packages/graphiql-react/src/toolbar/button.tsx b/packages/graphiql-react/src/toolbar/button.tsx index ec6bf5c8f7a..0399493d969 100644 --- a/packages/graphiql-react/src/toolbar/button.tsx +++ b/packages/graphiql-react/src/toolbar/button.tsx @@ -1,39 +1,45 @@ import { forwardRef, useState } from 'react'; - -import { UnStyledButton } from '../ui'; +import { Tooltip, UnStyledButton } from '../ui'; +import { compose } from '../utility/compose'; import './button.css'; +type ToolbarButtonProps = { + label: string; +}; + export const ToolbarButton = forwardRef< HTMLButtonElement, - JSX.IntrinsicElements['button'] ->((props, ref) => { + ToolbarButtonProps & JSX.IntrinsicElements['button'] +>(({ label, ...props }, ref) => { const [error, setError] = useState(null); return ( - { - try { - props.onClick?.(event); - setError(null); - } catch (err) { - setError( - err instanceof Error - ? err - : new Error(`Toolbar button click failed: ${err}`), - ); - } - }} - title={error ? error.message : props.title} - aria-invalid={error ? 'true' : props['aria-invalid']} - /> + + { + try { + props.onClick?.(event); + setError(null); + } catch (err) { + setError( + err instanceof Error + ? err + : new Error(`Toolbar button click failed: ${err}`), + ); + } + }} + aria-label={error ? error.message : label} + aria-invalid={error ? 'true' : props['aria-invalid']} + /> + ); }); ToolbarButton.displayName = 'ToolbarButton'; diff --git a/packages/graphiql-react/src/toolbar/execute.css b/packages/graphiql-react/src/toolbar/execute.css index a954d4c42a4..b277dd3241b 100644 --- a/packages/graphiql-react/src/toolbar/execute.css +++ b/packages/graphiql-react/src/toolbar/execute.css @@ -2,7 +2,7 @@ position: relative; } -.graphiql-execute-button { +button.graphiql-execute-button { background-color: hsl(var(--color-primary)); border: none; border-radius: var(--border-radius-8); @@ -24,7 +24,6 @@ display: block; height: var(--px-16); margin: auto; - pointer-events: none; width: var(--px-16); } } diff --git a/packages/graphiql-react/src/toolbar/execute.tsx b/packages/graphiql-react/src/toolbar/execute.tsx index 5d34d282e36..20678c1eab5 100644 --- a/packages/graphiql-react/src/toolbar/execute.tsx +++ b/packages/graphiql-react/src/toolbar/execute.tsx @@ -1,7 +1,7 @@ import { useEditorContext } from '../editor'; import { useExecutionContext } from '../execution'; import { PlayIcon, StopIcon } from '../icons'; -import { Menu } from '../ui'; +import { Menu, Tooltip } from '../ui'; import './execute.css'; @@ -18,16 +18,20 @@ export function ExecuteButton() { const operations = queryEditor?.operations || []; const hasOptions = operations.length > 1 && typeof operationName !== 'string'; + const label = `${isFetching ? 'Stop' : 'Execute'} query (Ctrl-Enter)`; const buttonProps = { type: 'button' as const, className: 'graphiql-execute-button', - title: 'Execute Query (Ctrl-Enter)', children: isFetching ? : , + 'aria-label': label, }; return hasOptions ? ( - + + + + {operations.map((operation, i) => { const opName = operation.name @@ -55,15 +59,17 @@ export function ExecuteButton() { ) : ( -