Skip to content

[graphiql]: support react 19, drop support react 16 and react 17 #3897

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 40 commits into from
May 2, 2025
Merged
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
1b6b507
upd
dimaMachina Apr 26, 2025
84ec2f8
upd
dimaMachina Apr 26, 2025
b3cc341
upd
dimaMachina Apr 26, 2025
178e594
upd
dimaMachina Apr 26, 2025
942afb1
upd
dimaMachina Apr 26, 2025
84b9983
exclude react-dom/client from bundle
dimaMachina Apr 26, 2025
e394bb6
bump react everywhere to v19
dimaMachina Apr 26, 2025
b2eb509
bump react everywhere to v19
dimaMachina Apr 26, 2025
58d9607
polish
dimaMachina Apr 26, 2025
9b0d339
fix failing text, to unblock canary
dimaMachina Apr 26, 2025
54b0dee
Merge branch 'main' into react19
dimaMachina Apr 26, 2025
3f3dc5e
upd
dimaMachina Apr 26, 2025
c58df79
Merge branch 'main' into react19
dimaMachina Apr 26, 2025
efc7c3f
try `minor` for graphiql/react, otherwise it pines to `1.0.0-next.2` …
dimaMachina Apr 26, 2025
07a0905
try workaround
dimaMachina Apr 26, 2025
c3b73f3
try workaround
dimaMachina Apr 26, 2025
adbdb8f
try workaround
dimaMachina Apr 26, 2025
a408e42
try workaround
dimaMachina Apr 26, 2025
4b34b10
this should fix vitest
dimaMachina Apr 26, 2025
284c2fa
try
dimaMachina Apr 27, 2025
2382b03
try
dimaMachina Apr 27, 2025
5242c56
lint
dimaMachina Apr 27, 2025
46b304f
try
dimaMachina Apr 27, 2025
6325cda
fix test
dimaMachina Apr 27, 2025
efbd430
try SOURCEMAP var
dimaMachina Apr 27, 2025
c1ab45d
try ESM_SH_BUILD var
dimaMachina Apr 27, 2025
d23559f
try
dimaMachina Apr 27, 2025
1b248df
rm some unneeded code
dimaMachina Apr 27, 2025
6fc5225
try to fix esbuild: package 'uWebSockets.js' not found
dimaMachina Apr 27, 2025
1d41eb0
update vite to see if it fix esbuild error?
dimaMachina Apr 27, 2025
cb95709
bump module "@emotion/is-prop-valid" not found to fix `module "@emoti…
dimaMachina Apr 28, 2025
9e856e6
upd
dimaMachina Apr 28, 2025
9efda10
upd
dimaMachina Apr 28, 2025
0f373b9
upd
dimaMachina Apr 28, 2025
78a8246
Merge branch 'main' into react19
dimaMachina Apr 30, 2025
c587f92
fix e2e
dimaMachina Apr 30, 2025
9fe2edb
add changeset
dimaMachina May 1, 2025
55c2aa3
add migration markdown file
dimaMachina May 1, 2025
ec81b20
fix
dimaMachina May 1, 2025
168c364
Merge branch 'v4' into react19
dimaMachina May 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/clean-lamps-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@graphiql/plugin-code-exporter': major
'@graphiql/plugin-explorer': major
'@graphiql/react': minor
'graphiql': major
---

drop commonjs build files
10 changes: 10 additions & 0 deletions .changeset/gold-cooks-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@graphiql/plugin-code-exporter': major
'@graphiql/plugin-explorer': major
'@graphiql/react': minor
'graphiql': major
---

- support react 19, drop support react 16 and react 17
- replace deprecated `ReactDOM.unmountComponentAtNode()` and `ReactDOM.render()` with `root.unmount()` and `createRoot(container).render()`
- update `@radix-ui` and `@headlessui/react` dependencies
17 changes: 12 additions & 5 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -366,6 +366,7 @@ module.exports = {
excludedFiles: ['**/*.{md,mdx}/*.{ts,tsx}'],
// extends: ['plugin:@typescript-eslint/recommended-type-checked'],
rules: {
// '@typescript-eslint/no-redundant-type-constituents': 'error',
'@typescript-eslint/prefer-optional-chain': 'error',
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
'@typescript-eslint/no-floating-promises': 'error',
@@ -388,11 +389,10 @@ module.exports = {
projectService: {
allowDefaultProject: [
'examples/monaco-graphql-react-vite/vite.config.ts',
'packages/*/vitest.config.mts',
'packages/*/vite.config.mts',
'packages/{graphiql,graphiql-plugin-explorer,graphiql-plugin-code-exporter}/vite.config.mts',
'packages/{codemirror-graphql,graphiql-toolkit,graphql-language-service-cli,graphql-language-service,monaco-graphql,vscode-graphql-syntax,graphiql}/vitest.config.mts',

'packages/cm6-graphql/__tests__/test.spec.ts',
'packages/graphiql-react/setup-files.ts',
'packages/graphiql/src/GraphiQL.spec.tsx',
'packages/vscode-graphql-syntax/tests/*.spec.ts',
'packages/graphql-language-service-cli/src/__tests__/*.test.ts',
@@ -483,15 +483,15 @@ module.exports = {
},
},
{
// Rule prefer await to then without React packages because it's ugly to have `async IIFE` inside `useEffect`
// Rule to prefer await to then without React packages because it's ugly to have `async IIFE` inside `useEffect`
files: ['packages/**'],
excludedFiles: ['packages/graphiql/**', 'packages/graphiql-react/**'],
rules: {
'promise/prefer-await-to-then': 'error',
},
},
{
files: ['packages/{graphiql-react,graphiql}/**'],
files: ['packages/{graphiql-react,graphiql}/**/*.{ts,tsx}'],
rules: {
'@typescript-eslint/no-restricted-imports': [
'error',
@@ -502,6 +502,7 @@ module.exports = {
},
],
'react-hooks/react-compiler': 'error',
'@typescript-eslint/no-deprecated': 'error',
},
},
{
@@ -529,6 +530,12 @@ module.exports = {
'mdx/code-blocks': true,
},
},
{
files: ['**/*.d.ts'],
rules: {
'no-var': 'off',
},
},
{
// ❗ALWAYS LAST
// Rules for codeblocks inside Markdown/MDX
26 changes: 26 additions & 0 deletions docs/migration/graphiql-4.0.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Upgrading `graphiql` from `3.x` to `4.0.0`

## `graphiql` changes

- Drop CommonJS build output
- Drop support React 16/17
- Support React 19

## `@graphiql/react` changes

- Drop CommonJS build output
- Drop support React 16/17
- Support React 19
- Update `@radix-ui` and `@headlessui/react` dependencies

## `@graphiql/plugin-code-exporter` changes

- Drop CommonJS build output
- Drop support React 16/17
- Support React 19

## `@graphiql/plugin-explorer` changes

- Drop CommonJS build output
- Drop support React 16/17
- Support React 19
4 changes: 2 additions & 2 deletions examples/graphiql-create-react-app/package.json
Original file line number Diff line number Diff line change
@@ -5,8 +5,8 @@
"dependencies": {
"graphiql": "^3.4.0",
"graphql": "^16.9.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-scripts": "5.0.1"
},
"scripts": {
4 changes: 2 additions & 2 deletions examples/graphiql-parcel/package.json
Original file line number Diff line number Diff line change
@@ -24,8 +24,8 @@
"dependencies": {
"graphiql": "^2.2.0",
"graphql": "^16.9.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"parcel": "^2.5.0",
4 changes: 2 additions & 2 deletions examples/graphiql-webpack/package.json
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@
"graphiql": "^3.9.0",
"graphql": "^16.9.0",
"graphql-ws": "^5.5.5",
"react": "^18.2.0",
"react": "^19.1.0",
"regenerator-runtime": "^0.13.9"
},
"devDependencies": {
@@ -29,7 +29,7 @@
"cross-env": "^7.0.2",
"css-loader": "^6.7.3",
"html-webpack-plugin": "^5.5.0",
"react-dom": "^18.2.0",
"react-dom": "^19.1.0",
"style-loader": "^3.3.1",
"webpack": "5.94.0",
"webpack-cli": "^5.0.1",
6 changes: 3 additions & 3 deletions examples/monaco-graphql-nextjs/package.json
Original file line number Diff line number Diff line change
@@ -19,12 +19,12 @@
"monaco-graphql": "^1.6.1",
"next": "13.4.7",
"prettier": "3.3.2",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@types/node": "^16.18.4",
"@types/react": "18.2.14",
"@types/react": "^19.1.2",
"next-global-css": "1.3.1",
"typescript": "^4.6.3"
}
6 changes: 3 additions & 3 deletions examples/monaco-graphql-react-vite/package.json
Original file line number Diff line number Diff line change
@@ -10,11 +10,11 @@
"monaco-editor": "^0.39.0",
"monaco-graphql": "^1.6.1",
"prettier": "3.3.2",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.3.1",
"@vitejs/plugin-react": "^4.4.1",
"vite": "^5.4.18",
"vite-plugin-monaco-editor": "^1.1.0"
},
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -143,6 +143,8 @@
"resolutions": {
"@babel/traverse": "^7.23.2",
"vscode-languageserver-types": "3.17.3",
"markdown-it": "14.1.0"
"markdown-it": "14.1.0",
"react": "18.3.1",
"react-dom": "18.3.1"
}
}
10 changes: 5 additions & 5 deletions packages/graphiql-plugin-code-exporter/package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"name": "@graphiql/plugin-code-exporter",
"version": "3.1.5",
"sideEffects": false,
"repository": {
"type": "git",
"url": "https://github.com/graphql/graphiql",
"directory": "packages/graphiql-plugin-code-exporter"
},
"author": "LekoArts",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "types/index.d.ts",
"license": "MIT",
"keywords": [
@@ -35,15 +35,15 @@
"peerDependencies": {
"@graphiql/react": "^0.29.0",
"graphql": "^15.5.0 || ^16.0.0 || ^17.0.0",
"react": "^16.8.0 || ^17 || ^18",
"react-dom": "^16.8.0 || ^17 || ^18"
"react": "^18 || ^19",
"react-dom": "^18 || ^19"
},
"devDependencies": {
"@graphiql/react": "^0.29.0",
"@vitejs/plugin-react": "^4.4.1",
"graphql": "^16.9.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"typescript": "^4.6.3",
"vite": "^6.3.3"
}
5 changes: 3 additions & 2 deletions packages/graphiql-plugin-code-exporter/vite.config.mts
Original file line number Diff line number Diff line change
@@ -15,9 +15,10 @@ export default defineConfig({
emptyOutDir: !IS_UMD,
lib: {
entry: 'src/index.tsx',
fileName: 'index',
fileName: (format, filePath) =>
`${filePath}.${format === 'umd' ? 'umd.' : ''}js`,
name: 'GraphiQLPluginCodeExporter',
formats: IS_UMD ? ['umd'] : ['cjs', 'es'],
formats: IS_UMD ? ['umd'] : ['es'],
cssFileName: 'style',
},
rollupOptions: {
10 changes: 5 additions & 5 deletions packages/graphiql-plugin-explorer/package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"name": "@graphiql/plugin-explorer",
"version": "3.2.6",
"sideEffects": false,
"repository": {
"type": "git",
"url": "https://github.com/graphql/graphiql",
"directory": "packages/graphiql-plugin-explorer"
},
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "types/index.d.ts",
"license": "MIT",
"keywords": [
@@ -34,15 +34,15 @@
"peerDependencies": {
"@graphiql/react": "^0.29.0",
"graphql": "^15.5.0 || ^16.0.0 || ^17.0.0",
"react": "^16.8.0 || ^17 || ^18",
"react-dom": "^16.8.0 || ^17 || ^18"
"react": "^18 || ^19",
"react-dom": "^18 || ^19"
},
"devDependencies": {
"@graphiql/react": "^0.29.0",
"@vitejs/plugin-react": "^4.4.1",
"graphql": "^16.9.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"typescript": "^4.6.3",
"vite": "^6.3.3",
"vite-plugin-svgr": "^4.3.0"
5 changes: 3 additions & 2 deletions packages/graphiql-plugin-explorer/vite.config.mts
Original file line number Diff line number Diff line change
@@ -24,9 +24,10 @@ export default defineConfig({
emptyOutDir: !IS_UMD,
lib: {
entry: 'src/index.tsx',
fileName: 'index',
fileName: (format, filePath) =>
`${filePath}.${format === 'umd' ? 'umd.' : ''}js`,
name: 'GraphiQLPluginExplorer',
formats: IS_UMD ? ['umd'] : ['cjs', 'es'],
formats: IS_UMD ? ['umd'] : ['es'],
cssFileName: 'style',
},
rollupOptions: {
49 changes: 24 additions & 25 deletions packages/graphiql-react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"name": "@graphiql/react",
"version": "0.29.0",
"sideEffects": [
"*.css"
],
"repository": {
"type": "git",
"url": "https://github.com/graphql/graphiql",
@@ -11,20 +14,17 @@
"url": "https://github.com/graphql/graphiql/issues?q=issue+label:@graphiql/react"
},
"license": "MIT",
"main": "dist/index.js",
"module": "dist/index.mjs",
"exports": {
"./package.json": "./package.json",
".": {
"types": "./types/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./font/roboto.css": "./font/roboto.css",
"./font/fira-code.css": "./font/fira-code.css",
"./dist/style.css": "./dist/style.css"
},
"types": "types/index.d.ts",
"types": "dist/index.d.ts",
"keywords": [
"react",
"graphql",
@@ -33,43 +33,41 @@
],
"files": [
"dist",
"font",
"src",
"types"
"font"
],
"scripts": {
"prebuild": "rimraf dist types",
"dev": "concurrently 'tsc --emitDeclarationOnly --watch' 'vite build --watch'",
"build": "tsc --emitDeclarationOnly && vite build",
"test": "vitest"
"dev": "vite build --watch",
"build": "vite build",
"test": "vitest",
"types:check": "tsc --noEmit"
},
"peerDependencies": {
"graphql": "^15.5.0 || ^16.0.0 || ^17.0.0",
"react": "^16.8.0 || ^17 || ^18",
"react-dom": "^16.8.0 || ^17 || ^18"
"react": "^18 || ^19",
"react-dom": "^18 || ^19"
},
"dependencies": {
"react-compiler-runtime": "19.1.0-rc.1",
"@graphiql/toolkit": "^0.11.2",
"@headlessui/react": "^1.7.15",
"@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-tooltip": "^1.0.6",
"@radix-ui/react-visually-hidden": "^1.0.3",
"@headlessui/react": "^2.2",
"@radix-ui/react-dialog": "^1.1",
"@radix-ui/react-dropdown-menu": "^2.1",
"@radix-ui/react-tooltip": "^1.2",
"@radix-ui/react-visually-hidden": "^1.2",
"@types/codemirror": "^5.60.8",
"clsx": "^1.2.1",
"codemirror": "^5.65.3",
"codemirror-graphql": "^2.2.1",
"copy-to-clipboard": "^3.2.0",
"framer-motion": "^6.5.1",
"framer-motion": "^12",
"get-value": "^3.0.1",
"graphql-language-service": "^5.3.1",
"markdown-it": "^14.1.0",
"set-value": "^4.1.0"
},
"devDependencies": {
"babel-plugin-react-compiler": "19.1.0-rc.1",
"@types/react-dom": "^18.3.1",
"@types/react-dom": "^19.1.2",
"@babel/helper-string-parser": "^7.19.4",
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.1.0",
@@ -78,10 +76,11 @@
"@types/set-value": "^4.0.1",
"@vitejs/plugin-react": "^4.4.1",
"graphql": "^16.9.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"typescript": "^4.6.3",
"vite": "^6.3.3",
"vite-plugin-svgr": "^4.3.0"
"vite-plugin-svgr": "^4.3.0",
"vite-plugin-dts": "^4.5.3"
}
}
2 changes: 1 addition & 1 deletion packages/graphiql-react/src/editor/common.ts
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ export async function importCodeMirror(
) {
const CodeMirror = await import('codemirror').then(c =>
// Depending on bundler and settings the dynamic import either returns a
// function (e.g. parcel) or an object containing a `default` property
// function (e.g., parcel) or an object containing a `default` property
typeof c === 'function' ? c : c.default,
);
await Promise.all(
4 changes: 2 additions & 2 deletions packages/graphiql-react/src/editor/context.tsx
Original file line number Diff line number Diff line change
@@ -211,7 +211,7 @@ export type EditorContextProviderProps = {
* - Adding a tab
* - Switching to a different tab
* - Closing a tab
* @param tabState The tabs state after it has been updated.
* @param tabState The tab state after it has been updated.
*/
onTabChange?(tabState: TabsState): void;
/**
@@ -336,7 +336,7 @@ export function EditorContextProvider(props: EditorContextProviderProps) {
storage?.set(PERSIST_HEADERS_STORAGE_KEY, persist.toString());
};

const lastShouldPersistHeadersProp = useRef<boolean | undefined>();
const lastShouldPersistHeadersProp = useRef<boolean | undefined>(undefined);
useEffect(() => {
const propValue = Boolean(props.shouldPersistHeaders);
if (lastShouldPersistHeadersProp?.current !== propValue) {
10 changes: 5 additions & 5 deletions packages/graphiql-react/src/editor/query-editor.ts
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ import {
GraphQLDocumentMode,
OperationFacts,
} from 'graphql-language-service';
import { MutableRefObject, useEffect, useRef } from 'react';
import { RefObject, useEffect, useRef } from 'react';

import { useExecutionContext } from '../execution';
import { useExplorerContext } from '../explorer';
@@ -149,7 +149,7 @@ export function useQueryEditor(
const merge = useMergeQuery({ caller: caller || _useQueryEditor });
const prettify = usePrettifyEditors({ caller: caller || _useQueryEditor });
const ref = useRef<HTMLDivElement>(null);
const codeMirrorRef = useRef<CodeMirrorType>();
const codeMirrorRef = useRef<CodeMirrorType>(undefined);

const onClickReferenceRef = useRef<
NonNullable<UseQueryEditorArgs['onClickReference']>
@@ -474,7 +474,7 @@ export function useQueryEditor(
function useSynchronizeSchema(
editor: CodeMirrorEditor | null,
schema: GraphQLSchema | null,
codeMirrorRef: MutableRefObject<CodeMirrorType | undefined>,
codeMirrorRef: RefObject<CodeMirrorType | undefined>,
) {
useEffect(() => {
if (!editor) {
@@ -493,7 +493,7 @@ function useSynchronizeSchema(
function useSynchronizeValidationRules(
editor: CodeMirrorEditor | null,
validationRules: ValidationRule[] | null,
codeMirrorRef: MutableRefObject<CodeMirrorType | undefined>,
codeMirrorRef: RefObject<CodeMirrorType | undefined>,
) {
useEffect(() => {
if (!editor) {
@@ -512,7 +512,7 @@ function useSynchronizeValidationRules(
function useSynchronizeExternalFragments(
editor: CodeMirrorEditor | null,
externalFragments: Map<string, FragmentDefinitionNode>,
codeMirrorRef: MutableRefObject<CodeMirrorType | undefined>,
codeMirrorRef: RefObject<CodeMirrorType | undefined>,
) {
const externalFragmentList = [...externalFragments.values()]; // eslint-disable-line react-hooks/exhaustive-deps -- false positive, variable is optimized by react-compiler, no need to wrap with useMemo

40 changes: 17 additions & 23 deletions packages/graphiql-react/src/editor/response-editor.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { formatError } from '@graphiql/toolkit';
import type { Position, Token } from 'codemirror';
import { ComponentType, useEffect, useRef, JSX } from 'react';
// eslint-disable-next-line react/no-deprecated -- We can't refactor to root.unmount() from React 18 because we support React 16/17 too
import { unmountComponentAtNode, render } from 'react-dom';
import { createRoot } from 'react-dom/client';
import { useSchemaContext } from '../schema';

import {
@@ -84,38 +83,33 @@ export function useResponseEditor(

useEffect(() => {
let isActive = true;

void importCodeMirrorImports().then(CodeMirror => {
// Don't continue if the effect has already been cleaned up
if (!isActive) {
return;
}

// Handle image tooltips and custom tooltips
const tooltipDiv = document.createElement('div');
const tooltipContainer = document.createElement('div');
const tooltipRoot = createRoot(tooltipContainer);
CodeMirror.registerHelper(
'info',
'graphql-results',
(token: Token, _options: any, _cm: CodeMirrorEditor, pos: Position) => {
const infoElements: JSX.Element[] = [];

const ResponseTooltipComponent = responseTooltipRef.current;
if (ResponseTooltipComponent) {
infoElements.push(
<ResponseTooltipComponent pos={pos} token={token} />,
);
}

if (ImagePreview.shouldRender(token)) {
infoElements.push(
<ImagePreview key="image-preview" token={token} />,
);
}
if (!infoElements.length) {
unmountComponentAtNode(tooltipDiv);
return null;
const ResponseTooltip = responseTooltipRef.current;
const infoElements: JSX.Element[] = [
ResponseTooltip && <ResponseTooltip pos={pos} token={token} />,
ImagePreview.shouldRender(token) && (
<ImagePreview key="image-preview" token={token} />
),
].filter((v): v is JSX.Element => Boolean(v));

if (infoElements.length) {
tooltipRoot.render(infoElements);
return tooltipContainer;
}
render(infoElements, tooltipDiv);
return tooltipDiv;
tooltipRoot.unmount();
},
);

@@ -151,7 +145,7 @@ export function useResponseEditor(
if (fetchError) {
responseEditor?.setValue(fetchError);
}
if (validationErrors.length > 0) {
if (validationErrors.length) {
responseEditor?.setValue(formatError(validationErrors));
}
}, [responseEditor, fetchError, validationErrors]);
7 changes: 1 addition & 6 deletions packages/graphiql-react/src/editor/variable-editor.ts
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ import {
usePrettifyEditors,
useSynchronizeOption,
} from './hooks';
import { CodeMirrorType, WriteableEditorProps } from './types';
import { WriteableEditorProps } from './types';

export type UseVariableEditorArgs = WriteableEditorProps & {
/**
@@ -64,8 +64,6 @@ export function useVariableEditor(
const merge = useMergeQuery({ caller: caller || _useVariableEditor });
const prettify = usePrettifyEditors({ caller: caller || _useVariableEditor });
const ref = useRef<HTMLDivElement>(null);
const codeMirrorRef = useRef<CodeMirrorType>();

useEffect(() => {
let isActive = true;

@@ -74,9 +72,6 @@ export function useVariableEditor(
if (!isActive) {
return;
}

codeMirrorRef.current = CodeMirror;

const container = ref.current;
if (!container) {
return;
25 changes: 15 additions & 10 deletions packages/graphiql-react/src/explorer/components/search.tsx
Original file line number Diff line number Diff line change
@@ -8,7 +8,12 @@ import {
isObjectType,
} from 'graphql';
import { FC, useEffect, useRef, useState } from 'react';
import { Combobox } from '@headlessui/react';
import {
Combobox,
ComboboxInput,
ComboboxOptions,
ComboboxOption,
} from '@headlessui/react';
import { MagnifyingGlassIcon } from '../../icons';
import { useSchemaContext } from '../../schema';
import debounce from '../../utility/debounce';
@@ -85,7 +90,7 @@ export const Search: FC = () => {
}}
>
<MagnifyingGlassIcon />
<Combobox.Input
<ComboboxInput
autoComplete="off"
onChange={event => setSearchValue(event.target.value)}
placeholder={`${isMacOs ? '⌘' : 'Ctrl'} K`}
@@ -95,7 +100,7 @@ export const Search: FC = () => {
/>
</div>
{isFocused && (
<Combobox.Options data-cy="doc-explorer-list">
<ComboboxOptions data-cy="doc-explorer-list">
{results.within.length +
results.types.length +
results.fields.length ===
@@ -105,13 +110,13 @@ export const Search: FC = () => {
</li>
) : (
results.within.map((result, i) => (
<Combobox.Option
<ComboboxOption
key={`within-${i}`}
value={result}
data-cy="doc-explorer-option"
>
<Field field={result.field} argument={result.argument} />
</Combobox.Option>
</ComboboxOption>
))
)}
{results.within.length > 0 &&
@@ -121,25 +126,25 @@ export const Search: FC = () => {
</div>
) : null}
{results.types.map((result, i) => (
<Combobox.Option
<ComboboxOption
key={`type-${i}`}
value={result}
data-cy="doc-explorer-option"
>
<Type type={result.type} />
</Combobox.Option>
</ComboboxOption>
))}
{results.fields.map((result, i) => (
<Combobox.Option
<ComboboxOption
key={`field-${i}`}
value={result}
data-cy="doc-explorer-option"
>
<Type type={result.type} />.
<Field field={result.field} argument={result.argument} />
</Combobox.Option>
</ComboboxOption>
))}
</Combobox.Options>
</ComboboxOptions>
)}
</Combobox>
);
3 changes: 1 addition & 2 deletions packages/graphiql-react/src/icons/implements.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions packages/graphiql-react/src/ui/tooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { ReactElement, ReactNode } from 'react';
import { FC, ReactNode } from 'react';
import * as T from '@radix-ui/react-tooltip';
import { createComponentGroup } from '../utility/component-group';
import './tooltip.css';

export function TooltipRoot({
export const TooltipRoot: FC<T.TooltipContentProps & { label: ReactNode }> = ({
children,
align = 'start',
side = 'bottom',
sideOffset = 5,
label,
}: T.TooltipContentProps & { label: ReactNode }): ReactElement {
}) => {
return (
<T.Root>
<T.Trigger asChild>{children}</T.Trigger>
@@ -25,7 +25,7 @@ export function TooltipRoot({
</T.Portal>
</T.Root>
);
}
};

export const Tooltip = createComponentGroup(TooltipRoot, {
Provider: T.Provider,
6 changes: 2 additions & 4 deletions packages/graphiql-react/tsconfig.json
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
@@ -17,7 +17,5 @@
"declaration": true,
"declarationDir": "types",
"types": ["vitest/globals", "@testing-library/jest-dom"]
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
}
8 changes: 0 additions & 8 deletions packages/graphiql-react/tsconfig.node.json

This file was deleted.

20 changes: 15 additions & 5 deletions packages/graphiql-react/vite.config.mts
Original file line number Diff line number Diff line change
@@ -3,10 +3,11 @@ import { defineConfig, PluginOption } from 'vite';
import react from '@vitejs/plugin-react';
import svgr from 'vite-plugin-svgr';
import type { PluginOptions as ReactCompilerConfig } from 'babel-plugin-react-compiler';
import packageJSON from './package.json';
import packageJSON from './package.json' assert { type: 'json' };
import dts from 'vite-plugin-dts';

export const reactCompilerConfig: Partial<ReactCompilerConfig> = {
target: '17',
target: '18',
sources(filename) {
if (filename.includes('__tests__')) {
return false;
@@ -52,6 +53,11 @@ export const plugins: PluginOption[] = [
titleProp: true,
},
}),
dts({
include: ['src/**'],
outDir: ['dist'],
exclude: ['**/*.spec.{ts,tsx}', '**/__tests__/'],
}),
];

export default defineConfig({
@@ -64,21 +70,25 @@ export default defineConfig({
sourcemap: true,
lib: {
entry: 'src/index.ts',
fileName: 'index',
formats: ['cjs', 'es'],
fileName(_format, entryName) {
const filePath = entryName.replace(/\.svg$/, '');
return `${filePath}.js`;
},
formats: ['es'],
cssFileName: 'style',
},
rollupOptions: {
external: [
'react/jsx-runtime',
'react-dom/client',
// Exclude peer dependencies and dependencies from bundle
...Object.keys(packageJSON.peerDependencies),
...Object.keys(packageJSON.dependencies),
// Exclude `codemirror/...` and `codemirror-graphql/...` but not `../style/codemirror.css`
/codemirror[/-]/,
],
output: {
chunkFileNames: '[name].[format].js',
preserveModules: true,
},
},
},
4 changes: 2 additions & 2 deletions packages/graphiql/index.html
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
}
</style>
<!--vite-replace-start-->
<link href="/dist/style.css" rel="stylesheet" />
<script
crossorigin
src="https://unpkg.com/react@18/umd/react.production.min.js"
@@ -33,13 +34,12 @@
src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"
></script>
<script src="/dist/index.umd.js"></script>
<link href="/dist/style.css" rel="stylesheet" />
<script type="module" src="/dist/e2e.js"></script>
<!--vite-replace-end-->
</head>
<body>
<div id="graphiql">
<div class="loading">Loading…</div>
</div>
<script type="module" src="resources/renderExample.js"></script>
</body>
</html>
17 changes: 8 additions & 9 deletions packages/graphiql/package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"name": "graphiql",
"version": "3.9.0",
"sideEffects": false,
"description": "An graphical interactive in-browser GraphQL IDE.",
"contributors": [
"Hyohyeon Jeong <asiandrummer@fb.com>",
"Lee Byron <lee@leebyron.com> (http://leebyron.com/)"
"Lee Byron <lee@leebyron.com> (https://leebyron.com)"
],
"repository": {
"type": "git",
@@ -16,11 +17,10 @@
"url": "https://github.com/graphql/graphiql/issues?q=issue+label:graphiql"
},
"license": "MIT",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"files": [
"dist",
"!dist/e2e.*",
"graphiql.js",
"graphiql.js.map",
"graphiql.min.js",
@@ -34,8 +34,7 @@
"./graphiql.css": "./dist/style.css",
".": {
"types": "./dist/index.d.ts",
"require": "./dist/index.js",
"import": "./dist/index.mjs"
"import": "./dist/index.js"
}
},
"scripts": {
@@ -55,8 +54,8 @@
},
"peerDependencies": {
"graphql": "^15.5.0 || ^16.0.0 || ^17.0.0",
"react": "^16.8.0 || ^17 || ^18",
"react-dom": "^16.8.0 || ^17 || ^18"
"react": "^18 || ^19",
"react-dom": "^18 || ^19"
},
"devDependencies": {
"lightningcss": "^1.29.3",
@@ -73,8 +72,8 @@
"graphql": "^16.9.0",
"graphql-http": "^1.22.1",
"graphql-subscriptions": "^2.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"start-server-and-test": "^1.10.11",
"subscriptions-transport-ws": "0.11.0",
"typescript": "^4.6.3",
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use no memo';

import { TabsState, Theme } from '@graphiql/react';

/* global React, ReactDOM, GraphiQL */

/**
@@ -14,53 +16,64 @@
* - vite dev server
*/

interface Params {
query?: string;
variables?: string;
headers?: string;
confirmCloseTab?: 'true';
forcedTheme?: 'light' | 'dark' | 'system';
defaultQuery?: string;
defaultTheme?: Theme;
defaultHeaders?: string;
}

// Parse the search string to get url parameters.
const parameters = Object.fromEntries(
const parameters: Params = Object.fromEntries(
new URLSearchParams(location.search).entries(),
);

// When the query and variables string is edited, update the URL bar so
// that it can be easily shared.
function onEditQuery(newQuery) {
function onEditQuery(newQuery: string): void {
parameters.query = newQuery;
updateURL();
}

function onEditVariables(newVariables) {
function onEditVariables(newVariables: string): void {
parameters.variables = newVariables;
updateURL();
}

function onEditHeaders(newHeaders) {
function onEditHeaders(newHeaders: string): void {
parameters.headers = newHeaders;
updateURL();
}

function onTabChange(tabsState) {
function onTabChange(tabsState: TabsState): void {
const activeTab = tabsState.tabs[tabsState.activeTabIndex];
parameters.query = activeTab.query;
parameters.variables = activeTab.variables;
parameters.headers = activeTab.headers;
parameters.query = activeTab.query ?? undefined;
parameters.variables = activeTab.variables ?? undefined;
parameters.headers = activeTab.headers ?? undefined;
updateURL();
}

function confirmCloseTab(index) {
function confirmCloseTab(index: number): boolean {
// eslint-disable-next-line no-alert
return confirm(`Are you sure you want to close tab with index ${index}?`);
}

function updateURL() {
function updateURL(): void {
const newSearch = Object.entries(parameters)
.filter(([_key, value]) => value)
.map(
([key, value]) =>
encodeURIComponent(key) + '=' + encodeURIComponent(value),
)
.join('&');
history.replaceState(null, null, `?${newSearch}`);
history.replaceState(null, '', `?${newSearch}`);
}

function getSchemaUrl() {
function getSchemaUrl(): string {
const isDev = /localhost$/.test(location.hostname);

if (isDev) {
3 changes: 3 additions & 0 deletions packages/graphiql/src/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
declare var React: import('react');
declare var ReactDOM: import('react-dom/client');
declare var GraphiQL: import('./cdn');
30 changes: 15 additions & 15 deletions packages/graphiql/vite.config.mts
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ const reactCompilerConfig: Partial<ReactCompilerConfig> = {
) {
return false;
}
return filename.includes(`packages${sep}graphiql${sep}`);
return filename.includes(`packages${sep}graphiql${sep}src`);
},
};

@@ -31,7 +31,7 @@ const umdConfig = defineConfig({
define: {
// graphql v17
'globalThis.process.env.NODE_ENV': 'true',
// https://github.com/graphql/graphql-js/blob/16.x.x/website/docs/tutorials/going-to-production.md#vite
// https://github.com/graphql/graphql-js/blob/16.x.x/website/pages/docs/going-to-production.mdx
'globalThis.process': 'true',
'process.env.NODE_ENV': '"production"',
},
@@ -45,7 +45,10 @@ const umdConfig = defineConfig({
emptyOutDir: false,
lib: {
entry: 'src/cdn.ts',
// 👇 The name of the exposed global variable. Required when the formats option includes umd or iife
/**
* The name of the exposed global variable. Required when the `formats` option includes `umd`
* or `iife`.
*/
name: 'GraphiQL',
fileName: 'index',
formats: ['umd'],
@@ -64,20 +67,13 @@ const umdConfig = defineConfig({
});

const esmConfig = defineConfig({
...(process.env.NODE_ENV !== 'production' && {
resolve: {
alias: {
'react/compiler-runtime': 'react-compiler-runtime',
},
},
}),
build: {
minify: false,
sourcemap: true,
lib: {
entry: 'src/index.ts',
fileName: 'index',
formats: ['cjs', 'es'],
entry: ['src/index.ts', 'src/e2e.ts'],
fileName: (_format, filePath) => `${filePath}.js`,
formats: ['es'],
},
rollupOptions: {
external: [
@@ -86,10 +82,13 @@ const esmConfig = defineConfig({
...Object.keys(packageJSON.peerDependencies),
...Object.keys(packageJSON.dependencies),
],
output: {
preserveModules: true,
},
},
},
server: {
// prevent a browser window from opening automatically
// Prevent a browser window from opening automatically
open: false,
proxy: {
'/graphql': 'http://localhost:8080',
@@ -104,6 +103,7 @@ const esmConfig = defineConfig({

function htmlPlugin(): PluginOption {
const htmlForVite = /* HTML */ `
<link href="/src/style.css" rel="stylesheet" />
<script type="module">
import React from 'react';
import ReactDOM from 'react-dom/client';
@@ -115,7 +115,7 @@ function htmlPlugin(): PluginOption {
GraphiQL,
});
</script>
<link href="/src/style.css" rel="stylesheet" />
<script type="module" src="/src/example.ts"></script>
`;

return {
1,062 changes: 448 additions & 614 deletions yarn.lock

Large diffs are not rendered by default.