Repository: graphql/graphiql Branch: main Commit: 01723a406a01 Files: 735 Total size: 3.2 MB Directory structure: gitextract_nfz5esf2/ ├── .browserslistrc ├── .changeset/ │ ├── README.md │ └── config.json ├── .codecov.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── config.yml │ │ ├── graphiql-bug.yml │ │ ├── graphiql-feature.md │ │ ├── language-server-bug.yml │ │ └── language-server-feature.md │ ├── ISSUE_TEMPLATE.md │ └── workflows/ │ ├── main-test.yml │ ├── pr-graphql-compat-check.yml │ ├── pr.yml │ └── release.yml ├── .gitignore ├── .mailmap ├── .npmignore ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .vscode/ │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── .yarnrc.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── DEVELOPMENT.md ├── LICENSE ├── README.md ├── RELEASING.md ├── SECURITY.md ├── babel.config.js ├── cspell.json ├── docs/ │ ├── migration/ │ │ ├── graphiql-2.0.0.md │ │ ├── graphiql-4.0.0.md │ │ └── graphiql-5.0.0.md │ └── security/ │ └── 2021-introspection-schema-xss.md ├── examples/ │ ├── cm6-graphql-legacy-parcel/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.html │ │ │ ├── index.ts │ │ │ └── sample-query.ts │ │ └── tsconfig.json │ ├── cm6-graphql-parcel/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.html │ │ │ ├── index.ts │ │ │ ├── sample-query.ts │ │ │ └── testSchema.ts │ │ └── tsconfig.json │ ├── graphiql-cdn/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.html │ │ └── package.json │ ├── graphiql-create-react-app/ │ │ └── README.md │ ├── graphiql-nextjs/ │ │ ├── README.md │ │ ├── next-env.d.ts │ │ ├── next.config.ts │ │ ├── package.json │ │ ├── src/ │ │ │ └── app/ │ │ │ ├── globals.css │ │ │ ├── graphiql.tsx │ │ │ ├── layout.tsx │ │ │ └── page.ts │ │ └── tsconfig.json │ ├── graphiql-parcel/ │ │ └── README.md │ ├── graphiql-vite/ │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.jsx │ │ │ └── index.jsx │ │ └── vite.config.mjs │ ├── graphiql-vite-react-router/ │ │ ├── README.md │ │ ├── app/ │ │ │ ├── root.tsx │ │ │ ├── routes/ │ │ │ │ └── _index/ │ │ │ │ ├── create-fetcher.ts │ │ │ │ ├── globals.css │ │ │ │ ├── graphiql.client.tsx │ │ │ │ └── route.ts │ │ │ └── routes.ts │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── react-router.config.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── graphiql-webpack/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── index.html.ejs │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.css │ │ │ ├── index.jsx │ │ │ ├── select-server-plugin.css │ │ │ ├── select-server-plugin.jsx │ │ │ └── snippets.js │ │ └── webpack.config.js │ ├── monaco-graphql-nextjs/ │ │ ├── README.md │ │ ├── next-env.d.ts │ │ ├── next.config.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── app/ │ │ │ │ ├── env.d.ts │ │ │ │ ├── globals.css │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ │ ├── constants.ts │ │ │ └── editor.tsx │ │ └── tsconfig.json │ ├── monaco-graphql-react-vite/ │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── env.d.ts │ │ │ └── index.tsx │ │ ├── tsconfig.json │ │ └── vite.config.ts │ └── monaco-graphql-webpack/ │ ├── CHANGELOG.md │ ├── README.md │ ├── babel.config.js │ ├── package.json │ ├── src/ │ │ ├── editors.ts │ │ ├── index.html.ejs │ │ ├── index.ts │ │ ├── schema.ts │ │ └── style.css │ ├── tsconfig.json │ └── webpack.config.js ├── functions/ │ ├── graphql.ts │ └── package.json ├── jest.config.base.js ├── jest.config.js ├── js-green-licenses.json ├── netlify.toml ├── package.json ├── packages/ │ ├── cm6-graphql/ │ │ ├── .gitignore │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── __tests__/ │ │ │ ├── cases.txt │ │ │ ├── test.spec.ts │ │ │ └── types.txt │ │ ├── package.json │ │ ├── src/ │ │ │ ├── commands.ts │ │ │ ├── completions.ts │ │ │ ├── graphql.ts │ │ │ ├── helpers.ts │ │ │ ├── index.ts │ │ │ ├── interfaces.ts │ │ │ ├── jump.ts │ │ │ ├── language.ts │ │ │ ├── lint.ts │ │ │ ├── state.ts │ │ │ ├── syntax.grammar │ │ │ └── syntax.grammar.d.ts │ │ ├── tsconfig.esm.json │ │ └── tsconfig.json │ ├── codemirror-graphql/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── resources/ │ │ │ └── checkgit.sh │ │ ├── setup-files.ts │ │ ├── src/ │ │ │ ├── __tests__/ │ │ │ │ ├── hint.test.ts │ │ │ │ ├── kitchen-sink.graphql │ │ │ │ ├── lint.test.ts │ │ │ │ ├── mode.test.ts │ │ │ │ ├── schema-kitchen-sink.graphql │ │ │ │ └── testSchema.ts │ │ │ ├── cm6-legacy/ │ │ │ │ └── mode.ts │ │ │ ├── hint.ts │ │ │ ├── index.d.ts │ │ │ ├── info.ts │ │ │ ├── jump.ts │ │ │ ├── lint.ts │ │ │ ├── mode.ts │ │ │ ├── results/ │ │ │ │ ├── __tests__/ │ │ │ │ │ └── mode.test.ts │ │ │ │ └── mode.ts │ │ │ ├── utils/ │ │ │ │ ├── SchemaReference.ts │ │ │ │ ├── __tests__/ │ │ │ │ │ └── jsonParse.test.ts │ │ │ │ ├── collectVariables.ts │ │ │ │ ├── forEachState.ts │ │ │ │ ├── getTypeInfo.ts │ │ │ │ ├── hintList.ts │ │ │ │ ├── info-addon.ts │ │ │ │ ├── jsonParse.ts │ │ │ │ ├── jump-addon.ts │ │ │ │ ├── mode-factory.ts │ │ │ │ ├── mode-indent.ts │ │ │ │ └── runParser.ts │ │ │ └── variables/ │ │ │ ├── __tests__/ │ │ │ │ ├── hint.test.ts │ │ │ │ ├── lint.test.ts │ │ │ │ └── mode.test.ts │ │ │ ├── hint.ts │ │ │ ├── lint.ts │ │ │ └── mode.ts │ │ ├── tsconfig.esm.json │ │ ├── tsconfig.json │ │ └── vitest.config.mts │ ├── graphiql/ │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── __mocks__/ │ │ │ ├── monaco-editor.ts │ │ │ └── zustand.ts │ │ ├── cypress/ │ │ │ ├── e2e/ │ │ │ │ ├── docs.cy.ts │ │ │ │ ├── errors.cy.ts │ │ │ │ ├── graphql-ws.cy.ts │ │ │ │ ├── headers.cy.ts │ │ │ │ ├── history.cy.ts │ │ │ │ ├── incremental-delivery.cy.ts │ │ │ │ ├── init.cy.ts │ │ │ │ ├── keyboard.cy.ts │ │ │ │ ├── lint.cy.ts │ │ │ │ ├── prettify.cy.ts │ │ │ │ ├── tabs.cy.ts │ │ │ │ └── theme.cy.ts │ │ │ ├── env.d.ts │ │ │ ├── fixtures/ │ │ │ │ ├── bad-schema.json │ │ │ │ ├── example.json │ │ │ │ └── fixtures.ts │ │ │ ├── plugins/ │ │ │ │ └── index.ts │ │ │ ├── support/ │ │ │ │ ├── commands.ts │ │ │ │ └── e2e.ts │ │ │ └── tsconfig.json │ │ ├── cypress.config.ts │ │ ├── index.html │ │ ├── package.json │ │ ├── setup-files.ts │ │ ├── setup-window.ts │ │ ├── src/ │ │ │ ├── GraphiQL.spec.tsx │ │ │ ├── GraphiQL.tsx │ │ │ ├── cdn.ts │ │ │ ├── e2e.ts │ │ │ ├── graphiql.css │ │ │ ├── index.ts │ │ │ ├── setup-workers/ │ │ │ │ ├── esm.sh.ts │ │ │ │ ├── vite.ts │ │ │ │ └── webpack.ts │ │ │ ├── style.css │ │ │ └── ui/ │ │ │ ├── footer.tsx │ │ │ ├── index.ts │ │ │ ├── logo.tsx │ │ │ ├── short-keys.tsx │ │ │ ├── sidebar.tsx │ │ │ └── toolbar.tsx │ │ ├── test/ │ │ │ ├── README.md │ │ │ ├── e2e-server.js │ │ │ ├── execute.js │ │ │ ├── package.json │ │ │ └── schema.js │ │ ├── tsconfig.json │ │ ├── vite.config.mts │ │ └── vitest.config.mts │ ├── graphiql-plugin-code-exporter/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── example/ │ │ │ └── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── graphiql-code-exporter.d.ts │ │ │ ├── index.css │ │ │ └── index.tsx │ │ ├── tsconfig.json │ │ └── vite.config.mts │ ├── graphiql-plugin-doc-explorer/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── setup-files.ts │ │ ├── src/ │ │ │ ├── components/ │ │ │ │ ├── __tests__/ │ │ │ │ │ ├── doc-explorer.spec.tsx │ │ │ │ │ ├── field-documentation.spec.tsx │ │ │ │ │ ├── fixtures.ts │ │ │ │ │ ├── test-utils.ts │ │ │ │ │ ├── type-documentation.spec.tsx │ │ │ │ │ └── type-link.spec.tsx │ │ │ │ ├── argument.css │ │ │ │ ├── argument.tsx │ │ │ │ ├── default-value.css │ │ │ │ ├── default-value.tsx │ │ │ │ ├── deprecation-reason.css │ │ │ │ ├── deprecation-reason.tsx │ │ │ │ ├── directive.css │ │ │ │ ├── directive.tsx │ │ │ │ ├── doc-explorer.css │ │ │ │ ├── doc-explorer.tsx │ │ │ │ ├── field-documentation.tsx │ │ │ │ ├── field-link.css │ │ │ │ ├── field-link.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── schema-documentation.css │ │ │ │ ├── schema-documentation.tsx │ │ │ │ ├── search.css │ │ │ │ ├── search.tsx │ │ │ │ ├── section.css │ │ │ │ ├── section.tsx │ │ │ │ ├── type-documentation.css │ │ │ │ ├── type-documentation.tsx │ │ │ │ ├── type-link.css │ │ │ │ ├── type-link.tsx │ │ │ │ └── utils.tsx │ │ │ ├── context.tsx │ │ │ ├── deprecated.ts │ │ │ ├── index.ts │ │ │ └── schema-reference.ts │ │ ├── tsconfig.json │ │ ├── vite.config.mts │ │ └── vitest.config.mts │ ├── graphiql-plugin-explorer/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── graphiql-explorer.d.ts │ │ │ ├── index.css │ │ │ ├── index.tsx │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ └── vite.config.mts │ ├── graphiql-plugin-history/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── setup-files.ts │ │ ├── src/ │ │ │ ├── __tests__/ │ │ │ │ └── components.spec.tsx │ │ │ ├── components.tsx │ │ │ ├── context.ts │ │ │ ├── deprecated.ts │ │ │ ├── index.ts │ │ │ └── style.css │ │ ├── tsconfig.json │ │ ├── vite.config.mts │ │ └── vitest.config.mts │ ├── graphiql-react/ │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── font/ │ │ │ ├── fira-code.css │ │ │ └── roboto.css │ │ ├── package.json │ │ ├── setup-files.ts │ │ ├── src/ │ │ │ ├── components/ │ │ │ │ ├── button/ │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── button-group/ │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── dialog/ │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── dropdown-menu/ │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── execute-button/ │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── image-preview.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── markdown-content/ │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── operation-editor.tsx │ │ │ │ ├── provider.tsx │ │ │ │ ├── request-headers-editor.tsx │ │ │ │ ├── response-editor.tsx │ │ │ │ ├── spinner/ │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── tabs/ │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── toolbar-button/ │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── toolbar-menu/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── tooltip/ │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ └── variables-editor.tsx │ │ │ ├── constants.ts │ │ │ ├── deprecated.ts │ │ │ ├── env.d.ts │ │ │ ├── icons/ │ │ │ │ └── index.tsx │ │ │ ├── index.ts │ │ │ ├── setup-workers/ │ │ │ │ ├── esm.sh.ts │ │ │ │ ├── vite.ts │ │ │ │ └── webpack.ts │ │ │ ├── stores/ │ │ │ │ ├── editor.ts │ │ │ │ ├── execution.ts │ │ │ │ ├── index.ts │ │ │ │ ├── monaco.ts │ │ │ │ ├── plugin.ts │ │ │ │ ├── schema.ts │ │ │ │ ├── storage.ts │ │ │ │ └── theme.ts │ │ │ ├── style/ │ │ │ │ ├── auto-insertion.css │ │ │ │ ├── editor.css │ │ │ │ └── root.css │ │ │ ├── types.test-d.ts │ │ │ ├── types.ts │ │ │ ├── utility/ │ │ │ │ ├── cleanup-disposables.ts │ │ │ │ ├── create-bounded-use-store.ts │ │ │ │ ├── create-editor.ts │ │ │ │ ├── debounce.ts │ │ │ │ ├── hooks.ts │ │ │ │ ├── index.ts │ │ │ │ ├── jsonc.ts │ │ │ │ ├── markdown.ts │ │ │ │ ├── monaco-ssr.ts │ │ │ │ ├── pick.ts │ │ │ │ ├── resize.ts │ │ │ │ ├── tabs.spec.ts │ │ │ │ ├── tabs.ts │ │ │ │ ├── whitespace.spec.ts │ │ │ │ └── whitespace.ts │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ ├── vite.config.mts │ │ └── vitest.config.mts │ ├── graphiql-toolkit/ │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── docs/ │ │ │ └── create-fetcher.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── async-helpers/ │ │ │ │ └── index.ts │ │ │ ├── create-fetcher/ │ │ │ │ ├── __tests__/ │ │ │ │ │ ├── buildFetcher.spec.ts │ │ │ │ │ └── lib.spec.ts │ │ │ │ ├── createFetcher.ts │ │ │ │ ├── index.ts │ │ │ │ ├── lib.ts │ │ │ │ └── types.ts │ │ │ ├── format/ │ │ │ │ └── index.ts │ │ │ ├── graphql-helpers/ │ │ │ │ ├── __tests__/ │ │ │ │ │ ├── __queries__/ │ │ │ │ │ │ ├── mergedQuery.graphql │ │ │ │ │ │ ├── mergedQueryWithSchema.graphql │ │ │ │ │ │ └── testQuery.graphql │ │ │ │ │ ├── __schema__/ │ │ │ │ │ │ └── sorareSchema.graphql │ │ │ │ │ └── merge-ast.spec.ts │ │ │ │ ├── auto-complete.ts │ │ │ │ ├── index.ts │ │ │ │ ├── merge-ast.ts │ │ │ │ └── operation-name.ts │ │ │ ├── index.ts │ │ │ └── storage/ │ │ │ ├── __tests__/ │ │ │ │ ├── base.spec.ts │ │ │ │ └── query.spec.ts │ │ │ ├── base.ts │ │ │ ├── custom.ts │ │ │ ├── history.ts │ │ │ ├── index.ts │ │ │ └── query.ts │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.mts │ ├── graphql-language-service/ │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── benchmark/ │ │ │ ├── fixtures/ │ │ │ │ ├── github.graphql │ │ │ │ └── kitchen-sink.graphql │ │ │ └── index.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.ts │ │ │ ├── interface/ │ │ │ │ ├── __tests__/ │ │ │ │ │ ├── __queries__/ │ │ │ │ │ │ └── testQuery.graphql │ │ │ │ │ ├── __schema__/ │ │ │ │ │ │ ├── HoverTestSchema.graphql │ │ │ │ │ │ └── StarWarsSchema.graphql │ │ │ │ │ ├── getAutocompleteSuggestions.test.ts │ │ │ │ │ ├── getDefinition.test.ts │ │ │ │ │ ├── getDiagnostics.test.ts │ │ │ │ │ ├── getHoverInformation.test.ts │ │ │ │ │ ├── getOutline.test.ts │ │ │ │ │ ├── kitchen-sink.graphql │ │ │ │ │ └── queries/ │ │ │ │ │ ├── definitionQuery.graphql │ │ │ │ │ └── testQuery.graphql │ │ │ │ ├── autocompleteUtils.ts │ │ │ │ ├── getAutocompleteSuggestions.ts │ │ │ │ ├── getDefinition.ts │ │ │ │ ├── getDiagnostics.ts │ │ │ │ ├── getHoverInformation.ts │ │ │ │ ├── getOutline.ts │ │ │ │ └── index.ts │ │ │ ├── parser/ │ │ │ │ ├── CharacterStream.ts │ │ │ │ ├── RuleHelpers.ts │ │ │ │ ├── Rules.ts │ │ │ │ ├── __tests__/ │ │ │ │ │ ├── CharacterStream.test.ts │ │ │ │ │ ├── OnlineParser.test.ts │ │ │ │ │ ├── OnlineParserUtils.ts │ │ │ │ │ └── RuleHelpers.test.ts │ │ │ │ ├── api.ts │ │ │ │ ├── getTypeInfo.ts │ │ │ │ ├── index.ts │ │ │ │ ├── onlineParser.ts │ │ │ │ └── types.ts │ │ │ ├── temp-bin.ts │ │ │ ├── types.ts │ │ │ └── utils/ │ │ │ ├── Range.ts │ │ │ ├── __tests__/ │ │ │ │ ├── Range.test.ts │ │ │ │ ├── __fixtures__/ │ │ │ │ │ ├── file.js │ │ │ │ │ ├── invalid.fake │ │ │ │ │ ├── noextension │ │ │ │ │ └── package.json │ │ │ │ ├── __schema__/ │ │ │ │ │ ├── RecursiveSchema.graphql │ │ │ │ │ └── StarWarsSchema.graphql │ │ │ │ ├── collectVariables.test.ts │ │ │ │ ├── getASTNodeAtPosition.test.ts │ │ │ │ ├── getVariablesJSONSchema.test.ts │ │ │ │ └── validateWithCustomRules.test.ts │ │ │ ├── collectVariables.ts │ │ │ ├── fragmentDependencies.ts │ │ │ ├── getASTNodeAtPosition.ts │ │ │ ├── getOperationFacts.ts │ │ │ ├── getVariablesJSONSchema.ts │ │ │ ├── index.ts │ │ │ └── validateWithCustomRules.ts │ │ ├── tsconfig.esm.json │ │ ├── tsconfig.json │ │ └── vitest.config.mts │ ├── graphql-language-service-cli/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bin/ │ │ │ └── graphql.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── __tests__/ │ │ │ │ ├── client.test.ts │ │ │ │ └── index.test.ts │ │ │ ├── cli.ts │ │ │ └── client.ts │ │ ├── tsconfig.esm.json │ │ ├── tsconfig.json │ │ └── vitest.config.mts │ ├── graphql-language-service-server/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── jest.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── GraphQLCache.ts │ │ │ ├── GraphQLLanguageService.ts │ │ │ ├── Logger.ts │ │ │ ├── MessageProcessor.ts │ │ │ ├── __tests__/ │ │ │ │ ├── .graphqlrc.yml │ │ │ │ ├── GraphQLCache.test.ts │ │ │ │ ├── GraphQLLanguageService.test.ts │ │ │ │ ├── Logger.test.ts │ │ │ │ ├── MessageProcessor.spec.ts │ │ │ │ ├── MessageProcessor.test.ts │ │ │ │ ├── __queries__/ │ │ │ │ │ ├── test.graphql │ │ │ │ │ ├── test2.graphql │ │ │ │ │ ├── test3.graphql │ │ │ │ │ └── testFragment.graphql │ │ │ │ ├── __schema__/ │ │ │ │ │ └── StarWarsSchema.graphql │ │ │ │ ├── __utils__/ │ │ │ │ │ ├── MockProject.ts │ │ │ │ │ ├── runServer.js │ │ │ │ │ └── utils.ts │ │ │ │ ├── findGraphQLTags.test.ts │ │ │ │ ├── parseDocument.test.ts │ │ │ │ ├── startServer.spec.ts │ │ │ │ └── startServer.test.ts │ │ │ ├── common.ts │ │ │ ├── constants.ts │ │ │ ├── findGraphQLTags.ts │ │ │ ├── index.ts │ │ │ ├── parseDocument.ts │ │ │ ├── parsers/ │ │ │ │ ├── astro.ts │ │ │ │ ├── babel.ts │ │ │ │ ├── index.ts │ │ │ │ ├── svelte.ts │ │ │ │ ├── types.ts │ │ │ │ └── vue.ts │ │ │ ├── startServer.ts │ │ │ ├── stringToHash.ts │ │ │ └── types.ts │ │ ├── tsconfig.esm.json │ │ └── tsconfig.json │ ├── monaco-graphql/ │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── GraphQLWorker.ts │ │ │ ├── LanguageService.ts │ │ │ ├── api.ts │ │ │ ├── full.ts │ │ │ ├── graphql.worker.ts │ │ │ ├── graphqlMode.ts │ │ │ ├── initialize.ts │ │ │ ├── initializeMode.ts │ │ │ ├── languageFeatures.ts │ │ │ ├── lite.ts │ │ │ ├── monaco-editor.ts │ │ │ ├── monaco.contribution.ts │ │ │ ├── schemaLoader.ts │ │ │ ├── typings/ │ │ │ │ ├── index.ts │ │ │ │ ├── monaco-editor.d.ts │ │ │ │ └── picomatch-browser.d.ts │ │ │ ├── utils.ts │ │ │ └── workerManager.ts │ │ ├── test/ │ │ │ └── monaco-editor.test.ts │ │ ├── tsconfig.esm.json │ │ ├── tsconfig.json │ │ └── vitest.config.mts │ ├── vscode-graphql/ │ │ ├── .vscodeignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── esbuild.js │ │ ├── package.json │ │ ├── snippets/ │ │ │ └── graphql.json │ │ ├── src/ │ │ │ ├── apis/ │ │ │ │ └── statusBar.ts │ │ │ ├── extension.ts │ │ │ ├── serverIpc/ │ │ │ │ └── index.ts │ │ │ └── serverStdio/ │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── vscode-graphql-execution/ │ │ ├── .vscodeignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── esbuild.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── extension.ts │ │ │ ├── helpers/ │ │ │ │ ├── extensions.ts │ │ │ │ ├── network.ts │ │ │ │ └── source.ts │ │ │ └── providers/ │ │ │ ├── exec-codelens.ts │ │ │ └── exec-content.ts │ │ └── tsconfig.json │ └── vscode-graphql-syntax/ │ ├── .vscodeignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── grammars/ │ │ ├── graphql.js.json │ │ ├── graphql.json │ │ ├── graphql.markdown.codeblock.json │ │ ├── graphql.php.json │ │ ├── graphql.python.json │ │ ├── graphql.re.json │ │ ├── graphql.rescript.json │ │ └── graphql.scala.json │ ├── language/ │ │ └── language-configuration.json │ ├── package.json │ ├── tests/ │ │ ├── __fixtures__/ │ │ │ ├── StarWarsSchema.graphql │ │ │ ├── kitchen-sink.graphql │ │ │ ├── query.graphql │ │ │ ├── test-js.md │ │ │ ├── test-py.md │ │ │ ├── test-sfc-comp.vue │ │ │ ├── test-sfc.vue │ │ │ ├── test.astro │ │ │ ├── test.js │ │ │ ├── test.md │ │ │ ├── test.php │ │ │ ├── test.py │ │ │ ├── test.re │ │ │ ├── test.scala │ │ │ ├── test.svelte │ │ │ └── test.ts │ │ ├── __snapshots__/ │ │ │ ├── graphql-grammar.spec.ts.snap │ │ │ ├── js-grammar.spec.ts.snap │ │ │ ├── markdown-grammar.spec.ts.snap │ │ │ ├── php-grammar.spec.ts.snap │ │ │ ├── python-grammar.spec.ts.snap │ │ │ ├── reason-grammar.spec.ts.snap │ │ │ └── scala-grammar.spec.ts.snap │ │ ├── __utilities__/ │ │ │ ├── serializer.ts │ │ │ └── utilities.ts │ │ ├── graphql-grammar.spec.ts │ │ ├── js-grammar.spec.ts │ │ ├── markdown-grammar.spec.ts │ │ ├── php-grammar.spec.ts │ │ ├── python-grammar.spec.ts │ │ ├── reason-grammar.spec.ts │ │ └── scala-grammar.spec.ts │ └── vitest.config.mts ├── resources/ │ ├── README.md │ ├── babel.config.js │ ├── custom-words.txt │ ├── patch-monaco-editor-type.mjs │ ├── patches/ │ │ └── @changesets+assemble-release-plan+6.0.3.patch │ ├── tsconfig.base.cjs.json │ ├── tsconfig.base.esm.json │ ├── tsconfig.build.cjs.json │ └── tsconfig.build.esm.json ├── scripts/ │ ├── canary-release.js │ ├── prepublish.sh │ ├── renameFileExtensions.js │ └── set-resolution.js ├── tsconfig.json ├── turbo.json ├── typedoc.json ├── wg.config.js └── working-group/ ├── README.md ├── agendas/ │ ├── 2019/ │ │ ├── 2019-05-14.md │ │ ├── 2019-06-18.md │ │ └── 2019-08-21.md │ ├── 2020/ │ │ ├── 2020-03-10.md │ │ ├── 2020-04-14.md │ │ └── 2020-05-21.md │ ├── 2021/ │ │ └── 2021-10-12.md │ ├── 2022/ │ │ ├── 2022-01-11.md │ │ ├── 2022-02-22-monaco.md │ │ ├── 2022-03-08.md │ │ ├── 2022-04-12.md │ │ ├── 2022-05-10.md │ │ ├── 2022-06-14.md │ │ ├── 2022-07-12.md │ │ ├── 2022-08-09.md │ │ ├── 2022-09-13.md │ │ ├── 2022-10-11.md │ │ ├── 2022-11-08.md │ │ └── 2022-12-13.md │ ├── 2023/ │ │ ├── 2023-01-10.md │ │ ├── 2023-02-14.md │ │ ├── 2023-04-11.md │ │ ├── 2023-05-09.md │ │ ├── 2023-06-13.md │ │ ├── 2023-07-11.md │ │ ├── 2023-08-08.md │ │ ├── 2023-09-12.md │ │ ├── 2023-10-10.md │ │ ├── 2023-11-14.md │ │ └── 2023-12-12.md │ ├── 2024/ │ │ ├── 08-Aug/ │ │ │ └── 13-graphiql-wg-august-2024.md │ │ ├── 09-Sep/ │ │ │ └── 10-graphiql-wg-september-2024.md │ │ ├── 10-Oct/ │ │ │ └── 08-graphiql-wg-october-2024.md │ │ ├── 11-Nov/ │ │ │ └── 12-graphiql-wg-november-2024.md │ │ └── 12-Dec/ │ │ └── 10-graphiql-wg-december-2024.md │ ├── 2025/ │ │ ├── 01-Jan/ │ │ │ └── 14-graphiql-wg-january-2025.md │ │ ├── 02-Feb/ │ │ │ └── 11-graphiql-wg-february-2025.md │ │ ├── 03-Mar/ │ │ │ └── 11-graphiql-wg-march-2025.md │ │ ├── 04-Apr/ │ │ │ └── 08-graphiql-wg-april-2025.md │ │ ├── 05-May/ │ │ │ └── 13-graphiql-wg-may-2025.md │ │ ├── 06-Jun/ │ │ │ └── 10-graphiql-wg-june-2025.md │ │ ├── 07-Jul/ │ │ │ └── 08-graphiql-wg-july-2025.md │ │ ├── 08-Aug/ │ │ │ └── 12-graphiql-wg-august-2025.md │ │ ├── 09-Sep/ │ │ │ └── 09-graphiql-wg-september-2025.md │ │ ├── 10-Oct/ │ │ │ └── 14-graphiql-wg-october-2025.md │ │ ├── 11-Nov/ │ │ │ └── 11-graphiql-wg-november-2025.md │ │ └── 12-Dec/ │ │ └── 09-graphiql-wg-december-2025.md │ └── 2026/ │ ├── 01-Jan/ │ │ └── 13-graphiql-wg-january-2026.md │ ├── 02-Feb/ │ │ └── 10-graphiql-wg-february-2026.md │ ├── 03-Mar/ │ │ └── 10-graphiql-wg-march-2026.md │ ├── 04-Apr/ │ │ └── 14-graphiql-wg-april-2026.md │ ├── 05-May/ │ │ └── 12-graphiql-wg-may-2026.md │ └── 06-Jun/ │ └── 09-graphiql-wg-june-2026.md ├── minutes/ │ ├── 2019-05-14.md │ ├── 2019-06-18.md │ ├── 2019-08-21.md │ ├── 2020-03-10.md │ ├── 2021-10-12.md │ └── 2022-01-11.md └── proposals/ └── .gitkeep ================================================ FILE CONTENTS ================================================ ================================================ FILE: .browserslistrc ================================================ last 2 versions Firefox ESR not dead not IE 11 not ios 10 ================================================ FILE: .changeset/README.md ================================================ # Changesets Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with multi-package repos, or single-package repos to help you version and publish your code. You can find the full documentation for it [in our repository](https://github.com/changesets/changesets) We have a quick list of common questions to get you started engaging with this project in [our documentation](https://github.com/changesets/changesets/blob/master/docs/common-questions.md) ================================================ FILE: .changeset/config.json ================================================ { "$schema": "https://unpkg.com/@changesets/config@2.0.1/schema.json", "changelog": ["@changesets/changelog-github", { "repo": "graphql/graphiql" }], "commit": false, "linked": [], "access": "public", "baseBranch": "main", "ignore": [ "example-graphiql-vite", "example-graphiql-vite-react-router", "example-graphiql-webpack", "example-monaco-graphql-nextjs", "example-monaco-graphql-react-vite", "example-monaco-graphql-webpack" ], "updateInternalDependencies": "patch", "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": { "onlyUpdatePeerDependentsWhenOutOfRange": true } } ================================================ FILE: .codecov.yml ================================================ codecov: notify: require_ci_to_pass: yes coverage: precision: 2 round: down range: '30...100' status: project: default: target: 50% # the minimum required coverage value threshold: .1% # the leniency in hitting the target, allows 1% drop patch: default: informational: true comment: # this is a top-level key layout: 'reach, diff, flags, files' behavior: default require_changes: true # if true: only post the comment if coverage changes ================================================ FILE: .editorconfig ================================================ # EditorConfig is awesome: https://EditorConfig.org # top-most EditorConfig file root = true # Unix-style newlines with a newline ending every file [*] end_of_line = lf insert_final_newline = true ================================================ FILE: .eslintignore ================================================ .changeset/*.md # ignore working-group dir markdown so it's easier for people to edit from the UI working-group/ packages/codemirror-graphql/src/__tests__/schema-kitchen-sink.graphql CHANGELOG.md **/CHANGELOG.md packages/vscode-graphql-syntax/tests/__fixtures__/ packages/graphql-language-service-server/src/__tests__/parseDocument.test.ts ================================================ FILE: .eslintrc.js ================================================ /** * Copyright (c) Facebook, Inc. * All rights reserved. * * This source code is licensed under the license found in the * LICENSE file in the root directory of this source tree. * */ const RESTRICTED_IMPORTS = [ { name: 'graphql/type', message: 'use `graphql`' }, { name: 'graphql/language', message: 'use `graphql`' }, { name: 'graphql/type/introspection', message: 'use `graphql`' }, { name: 'graphql/type/definition', message: 'use `graphql`' }, { name: 'graphql/type/directives', message: 'use `graphql`' }, { name: 'graphql/version', message: 'use `graphql`' }, { name: 'monaco-editor', message: '`monaco-editor` imports all languages; use `monaco-graphql/esm/monaco-editor` instead to import only `json` and `graphql` languages', allowTypeImports: true, }, ]; module.exports = { root: true, reportUnusedDisableDirectives: true, ignorePatterns: [ 'react-app-env.d.ts', 'next-env.d.ts', 'changesets/**/*.md', '**/CHANGELOG.md', 'functions/*', 'packages/vscode-graphql-syntax/tests/__fixtures__/*', // symlinks 'packages/graphiql-react/__mocks__/monaco-editor.ts', 'packages/graphiql-plugin-doc-explorer/__mocks__/zustand.ts', 'packages/graphiql-plugin-doc-explorer/__mocks__/monaco-editor.ts', 'packages/graphiql-plugin-history/__mocks__/zustand.ts', 'packages/graphiql-plugin-history/__mocks__/monaco-editor.ts', ], overrides: [ { // Rules for all code files files: ['**/*.{js,jsx,ts,tsx,mts,cts}'], parserOptions: { ecmaVersion: 6, }, settings: { react: { version: 'detect', }, }, // https://github.com/sindresorhus/globals/blob/master/globals.json env: { atomtest: true, es6: true, node: true, browser: true, }, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:import-x/recommended', 'plugin:import-x/typescript', 'plugin:react/recommended', 'plugin:react-hooks/recommended-legacy', 'plugin:react/jsx-runtime', 'prettier', ], plugins: ['promise', 'sonarjs', 'unicorn', '@shopify'], globals: { atom: false, document: false, window: false, monaco: true, Map: true, Set: true, }, rules: { '@shopify/prefer-early-return': ['error', { maximumStatements: 2 }], '@shopify/prefer-class-properties': 'off', // enable after https://github.com/Shopify/web-configs/issues/387 will be fixed 'sonarjs/no-inverted-boolean-check': 'error', // Possible Errors (http://eslint.org/docs/rules/#possible-errors) 'no-console': 'error', 'no-constant-binary-expression': 'error', 'no-empty': ['error', { allowEmptyCatch: true }], 'no-extra-parens': 'off', 'no-template-curly-in-string': 'off', 'valid-jsdoc': 'off', // Best Practices (http://eslint.org/docs/rules/#best-practices) 'accessor-pairs': 'error', 'array-callback-return': 'off', 'block-scoped-var': 'off', 'class-methods-use-this': 'off', complexity: 'off', 'consistent-return': 'off', curly: 'error', 'default-case': 'off', 'dot-notation': 'error', eqeqeq: ['error', 'allow-null'], 'guard-for-in': 'off', 'no-alert': 'error', 'no-await-in-loop': 'error', 'no-caller': 'error', 'no-case-declarations': 'off', 'no-div-regex': 'error', 'no-else-return': ['error', { allowElseIf: false }], 'no-eq-null': 'off', 'no-eval': 'error', 'no-extend-native': 'error', 'no-extra-bind': 'error', 'no-extra-label': 'error', 'no-floating-decimal': 'off', // prettier --list-different 'no-implicit-coercion': 'error', 'no-implicit-globals': 'off', 'no-implied-eval': 'error', 'no-invalid-this': 'off', 'no-iterator': 'error', 'no-labels': 'error', 'no-lone-blocks': 'error', 'no-loop-func': 'off', 'no-magic-numbers': 'off', 'no-multi-str': 'off', 'no-new-func': 'error', 'no-new-wrappers': 'error', 'no-new': 'error', 'no-octal-escape': 'error', 'no-param-reassign': 'error', 'no-proto': 'error', 'no-restricted-properties': [ 'error', { object: 'window', property: 'localStorage', message: 'Use `localStorage` instead', }, { object: 'window', property: 'location', message: 'Use `location` instead', }, { object: 'window', property: 'navigator', message: 'Use `navigator` instead', }, { object: 'window', property: 'getComputedStyle', message: 'Use `getComputedStyle` instead', }, { object: 'self', message: 'Use `globalThis` instead', }, ], 'no-return-assign': 'error', 'no-return-await': 'error', 'no-script-url': 'error', 'no-self-compare': 'error', 'no-sequences': 'error', 'no-throw-literal': 'error', 'no-unmodified-loop-condition': 'off', 'no-useless-call': 'error', 'no-useless-concat': 'error', 'no-useless-return': 'off', 'no-warning-comments': 'off', radix: 'error', 'require-await': 'off', 'vars-on-top': 'off', yoda: 'error', 'unicorn/prefer-string-slice': 'error', 'sonarjs/no-identical-functions': 'error', 'sonarjs/no-unused-collection': 'error', 'sonarjs/no-extra-arguments': 'error', 'unicorn/no-useless-undefined': 'error', 'no-var': 'error', // Strict Mode (http://eslint.org/docs/rules/#strict-mode) strict: 'off', // Variables (http://eslint.org/docs/rules/#variables) 'init-declarations': 'off', 'no-catch-shadow': 'error', 'no-label-var': 'error', 'no-restricted-globals': ['error', 'stop'], 'no-shadow': 'off', '@typescript-eslint/no-shadow': 'error', 'no-undef-init': 'off', 'no-undefined': 'off', '@typescript-eslint/no-unused-vars': [ 'error', { varsIgnorePattern: '^(React|_)', // allow underscores in destructuring argsIgnorePattern: '^_', }, ], 'no-use-before-define': 'off', 'unicorn/no-useless-switch-case': 'error', // Node.js and CommonJS (http://eslint.org/docs/rules/#nodejs-and-commonjs) 'callback-return': 'off', 'global-require': 'off', 'handle-callback-err': 'error', 'no-mixed-requires': 'error', 'no-new-require': 'error', 'no-path-concat': 'error', 'no-process-env': 'off', 'no-process-exit': 'off', 'no-restricted-modules': 'off', 'no-sync': 'off', // Stylistic Issues (http://eslint.org/docs/rules/#stylistic-issues) camelcase: 'off', 'capitalized-comments': 'off', 'consistent-this': 'off', 'func-name-matching': 'off', 'func-names': 'off', 'func-style': 'off', 'id-blacklist': 'off', 'id-length': 'off', 'id-match': 'off', indent: 'off', 'line-comment-position': 'off', 'linebreak-style': 'off', // prettier --list-different 'lines-around-comment': 'off', 'lines-around-directive': 'off', 'max-depth': 'off', 'max-lines': 'off', 'max-nested-callbacks': 'off', 'max-params': 'off', 'max-statements-per-line': 'off', 'max-statements': 'off', 'multiline-ternary': 'off', 'new-cap': 'off', 'newline-after-var': 'off', 'newline-before-return': 'off', 'newline-per-chained-call': 'off', 'no-bitwise': 'error', 'no-continue': 'off', 'no-inline-comments': 'off', 'no-mixed-operators': 'off', 'no-negated-condition': 'off', 'unicorn/no-negated-condition': 'error', 'no-nested-ternary': 'off', 'no-new-object': 'error', 'no-plusplus': 'off', 'no-restricted-syntax': [ 'error', { // ❌ useMemo(…, []) selector: 'CallExpression[callee.name=useMemo][arguments.1.type=ArrayExpression][arguments.1.elements.length=0]', message: "`useMemo` with an empty dependency array can't provide a stable reference, use `useRef` instead.", }, { // ❌ event.keyCode selector: 'MemberExpression > .property[type=Identifier][name=keyCode]', message: 'Use `.key` instead of `.keyCode`', }, ], 'no-ternary': 'off', 'no-underscore-dangle': 'off', 'no-unneeded-ternary': 'off', 'object-curly-newline': 'off', 'object-property-newline': 'off', 'one-var-declaration-per-line': 'off', 'one-var': ['error', 'never'], 'operator-assignment': 'error', 'operator-linebreak': 'off', 'require-jsdoc': 'off', 'sort-keys': 'off', 'sort-vars': 'off', 'spaced-comment': ['error', 'always', { markers: ['/'] }], 'wrap-regex': 'off', 'unicorn/prefer-dom-node-remove': 'error', // ECMAScript 6 (http://eslint.org/docs/rules/#ecmascript-6) 'arrow-body-style': 'off', '@typescript-eslint/no-restricted-imports': [ 'error', ...RESTRICTED_IMPORTS, ], 'no-useless-computed-key': 'error', 'no-useless-constructor': 'off', 'no-useless-rename': 'error', 'prefer-arrow-callback': ['error', { allowNamedFunctions: true }], 'object-shorthand': [ 'error', 'always', { avoidExplicitReturnArrows: true }, ], 'prefer-numeric-literals': 'off', 'prefer-template': 'off', 'sort-imports': 'off', 'symbol-description': 'error', 'sonarjs/no-ignored-return': 'error', 'unicorn/no-array-push-push': 'error', 'import-x/no-extraneous-dependencies': 'error', 'import-x/no-duplicates': 'error', 'import-x/no-named-as-default': 'error', 'prefer-object-spread': 'error', // React rules 'react/no-unused-state': 'error', 'react/jsx-curly-brace-presence': 'error', 'react/jsx-boolean-value': 'error', 'react/jsx-handler-names': 'error', 'react/jsx-pascal-case': 'error', 'react/no-did-mount-set-state': 'error', 'react/no-did-update-set-state': 'error', 'react/prop-types': 'off', 'react/prefer-es6-class': 'error', 'react/prefer-stateless-function': 'error', 'react/self-closing-comp': 'error', 'react/jsx-no-useless-fragment': 'error', 'react/jsx-filename-extension': [ 'error', { extensions: ['.tsx', '.jsx'], allow: 'as-needed' }, ], 'unicorn/no-typeof-undefined': 'error', 'unicorn/prefer-at': 'error', 'unicorn/consistent-destructuring': 'error', 'prefer-destructuring': [ 'error', { VariableDeclarator: { object: true } }, ], 'promise/no-multiple-resolved': 'error', 'unicorn/no-zero-fractions': 'error', 'sonarjs/no-redundant-jump': 'error', 'unicorn/prefer-logical-operator-over-ternary': 'error', 'logical-assignment-operators': [ 'error', 'always', { enforceForIfStatements: true }, ], 'unicorn/prefer-regexp-test': 'error', 'unicorn/prefer-export-from': ['error', { ignoreUsedVariables: true }], 'unicorn/throw-new-error': 'error', 'unicorn/prefer-includes': 'error', 'unicorn/no-array-for-each': 'error', 'unicorn/prefer-dom-node-append': 'error', 'no-lonely-if': 'error', 'unicorn/no-lonely-if': 'error', 'unicorn/prefer-optional-catch-binding': 'error', 'unicorn/prefer-array-flat-map': 'error', 'no-unused-expressions': 'off', '@typescript-eslint/no-unused-expressions': 'error', 'sonarjs/no-small-switch': 'error', 'sonarjs/no-duplicated-branches': 'error', 'sonarjs/prefer-promise-shorthand': 'error', 'sonarjs/no-dead-store': 'error', 'sonarjs/void-use': 'error', 'unicorn/prefer-node-protocol': 'error', 'import-x/no-unresolved': [ 'error', { ignore: [ '^node:', '\\.svg\\?react$', 'vitest/config', './vite.config.mjs', ], }, ], 'no-extra-boolean-cast': [ 'error', { enforceForInnerExpressions: true }, ], 'unicorn/no-length-as-slice-end': 'error', 'unicorn/prefer-string-replace-all': 'error', 'unicorn/prefer-array-some': 'error', // '@typescript-eslint/prefer-for-of': 'error', TODO 'unicorn/no-hex-escape': 'off', // TODO: enable // doesn't catch a lot of cases; we use ESLint builtin `no-restricted-syntax` to forbid `.keyCode` 'unicorn/prefer-keyboard-event-key': 'off', 'unicorn/prefer-switch': 'error', 'unicorn/prefer-dom-node-text-content': 'error', quotes: ['error', 'single', { avoidEscape: true }], // Matches Prettier, but also replaces backticks with single quotes // TODO: Fix all errors for the following rules included in recommended config '@typescript-eslint/no-require-imports': 'off', 'import-x/no-named-as-default-member': 'off', }, }, { files: ['packages/{monaco-graphql,graphiql*}/**/*.{ts,tsx,mts,cts}'], excludedFiles: ['packages/graphiql-toolkit/**/*.{ts,tsx}'], rules: { '@typescript-eslint/no-unnecessary-condition': 'error', }, }, { // Rules that requires type information files: ['**/*.{ts,tsx,mts,cts}'], 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', '@typescript-eslint/non-nullable-type-assertion-style': 'error', '@typescript-eslint/consistent-type-assertions': 'error', '@typescript-eslint/no-duplicate-type-constituents': 'error', '@typescript-eslint/no-unnecessary-type-conversion': 'error', // '@typescript-eslint/await-thenable': 'error', // TODO // TODO: Fix all errors for the following rules included in recommended config '@typescript-eslint/no-deprecated': 'off', '@typescript-eslint/no-unsafe-function-type': 'off', '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/ban-ts-comment': 'off', '@typescript-eslint/ban-types': 'off', '@typescript-eslint/no-empty-function': 'off', '@typescript-eslint/triple-slash-reference': 'off', '@typescript-eslint/no-namespace': 'off', }, parserOptions: { projectService: { allowDefaultProject: [ 'examples/monaco-graphql-react-vite/vite.config.ts', 'packages/{codemirror-graphql,graphiql-toolkit,graphql-language-service-cli,graphql-language-service,monaco-graphql,vscode-graphql-syntax}/vitest.config.mts', 'packages/cm6-graphql/__tests__/test.spec.ts', 'packages/graphiql/cypress.config.ts', 'packages/vscode-graphql-syntax/tests/*.spec.ts', 'packages/graphql-language-service-cli/src/__tests__/*.test.ts', 'packages/monaco-graphql/test/monaco-editor.test.ts', 'packages/codemirror-graphql/setup-files.ts', 'packages/codemirror-graphql/src/__tests__/testSchema.ts', 'packages/codemirror-graphql/src/__tests__/*.test.ts', 'packages/codemirror-graphql/src/{variables,utils,results}/__tests__/*.test.ts', 'packages/graphql-language-service/benchmark/index.ts', 'packages/graphql-language-service/src/{utils,parser,interface}/__tests__/*.test.ts', 'packages/graphql-language-service/src/parser/__tests__/OnlineParserUtils.ts', 'packages/graphql-language-service-server/src/__tests__/*.{spec,test}.ts', 'packages/graphql-language-service-server/src/__tests__/__utils__/utils.ts', 'packages/graphql-language-service-server/src/__tests__/__utils__/MockProject.ts', 'packages/vscode-graphql-syntax/tests/__utilities__/serializer.ts', 'packages/vscode-graphql-syntax/tests/__utilities__/utilities.ts', ], maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING: 100, }, }, }, // Cypress plugin, global, etc., only for cypress directory // https://github.com/cypress-io/eslint-plugin-cypress // cypress clashes with jest expect() { files: ['**/cypress/**'], extends: 'plugin:cypress/recommended', rules: { // Because innerText doesn't return hidden elements and returns new line (\n) characters 'unicorn/prefer-dom-node-text-content': 'off', }, }, { // Rules for unit tests files: [ '**/__{tests,mocks}__/*.{js,jsx,ts,tsx}', '**/*.spec.{ts,js.jsx.tsx}', ], extends: ['plugin:jest/recommended'], rules: { 'jest/no-conditional-expect': 'off', 'jest/expect-expect': ['error', { assertFunctionNames: ['expect*'] }], }, }, { // Resources are typically our helper scripts; make life easier there files: ['resources/**', '**/resources/**', 'scripts/**'], rules: { 'no-console': 'off', }, }, { // Disable rules for examples folder files: ['examples/**'], rules: { 'no-console': 'off', 'no-new': 'off', 'no-alert': 'off', 'import-x/no-unresolved': 'off', }, }, { // Rule for ignoring imported dependencies from tests files files: [ '**/__tests__/**', 'webpack.config.js', '**/tests/**', 'test.config.js', 'vitest.config.mts', 'setup-files.ts', ], rules: { 'import-x/no-extraneous-dependencies': 'off', }, }, { // Rule for allowing import `vscode` package files: [ 'packages/vscode-graphql/**', 'packages/vscode-graphql-execution/**', ], rules: { 'import-x/no-unresolved': ['error', { ignore: ['^node:', 'vscode'] }], }, }, { // 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}/**/*.{ts,tsx}'], rules: { '@typescript-eslint/no-restricted-imports': [ 'error', ...RESTRICTED_IMPORTS, { name: 'react', importNames: ['memo', 'useCallback', 'useMemo'], }, ], 'react-hooks/react-compiler': 'error', '@typescript-eslint/no-deprecated': 'error', }, }, { // Monaco-GraphQL rules files: ['packages/monaco-graphql/**'], rules: { '@typescript-eslint/no-restricted-imports': [ 'error', ...RESTRICTED_IMPORTS.filter(({ name }) => name !== 'monaco-editor'), { name: 'monaco-editor', message: '`monaco-editor` imports all languages; use locale `monaco-editor.ts` instead to import only `json` and `graphql` languages', }, ], }, }, { // Parsing Markdown/MDX files: ['**/*.{md,mdx}'], parser: 'eslint-mdx', plugins: ['mdx'], processor: 'mdx/remark', settings: { 'mdx/code-blocks': true, }, }, { files: ['**/*.d.ts'], rules: { 'no-var': 'off', }, }, { // ❗ALWAYS LAST // Rules for codeblocks inside Markdown/MDX files: ['**/*.{md,mdx}/*.{js,jsx,ts,tsx}'], rules: { 'import-x/no-extraneous-dependencies': 'off', '@typescript-eslint/no-unused-vars': 'off', 'import-x/no-unresolved': 'off', 'no-console': 'off', 'no-undef': 'off', 'react/jsx-no-undef': 'off', 'react-hooks/rules-of-hooks': 'off', 'sonarjs/no-dead-store': 'off', '@typescript-eslint/no-restricted-imports': 'off', '@typescript-eslint/no-unnecessary-condition': 'off', '@typescript-eslint/no-deprecated': 'off', }, }, ], }; ================================================ FILE: .gitattributes ================================================ # Set the default behavior, in case people don't have core.autocrlf set. * text=auto *.js text eol=lf *.jsx text eol=lf *.ts text eol=lf *.tsx text eol=lf *.json text eol=lf *.md text eol=lf *.html text eol=lf *.css text eol=lf *.sh text eol=lf *.yml text eol=lf .yarn/releases/*.cjs export-ignore binary linguist-generated ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: true contact_links: - name: '📚 Support/Q&A' url: https://github.com/graphql/graphiql/discussions/categories/q-a-support about: >- Some questions are already answered in our github discussions Q&A section If you don't find an answer, [create a support ticket](ttps://github.com/graphql/graphiql/discussions/new?category=q-a-support) - name: '💬 `graphiql` Discord Support' url: https://discord.gg/NP5vbPeUFp about: '`graphiql` Discord Support Channel' - name: '💬 `vscode-graphql` Discord Support' url: https://discord.gg/bHrQtxGNzQ about: '`vscode-graphql` Discord Support Channel' - name: '💬 GraphQL LSP & CLI Discord Support' url: https://discord.gg/wkQCKwazxj about: >- GraphQL LSP (Language Server Protocol) Server Discord Support Channel For `graphql-language-service-server` and/or `graphql-language-service-cli` - name: '💬 `monaco-graphql` Discord Support' url: https://discord.gg/r4BxrAG6fN about: '`monaco-graphql` Discord Support Channel' - name: '💬 `codedemirror-graphql` Discord Support' url: https://discord.gg/cffZwk8NJW about: '`codemirror-graphql` Discord Support Channel' ================================================ FILE: .github/ISSUE_TEMPLATE/graphiql-bug.yml ================================================ name: GraphiQL 🐞 Bug description: File a bug with the graphiql web editor title: '[graphiql] ' labels: [bug, needs triage, graphiql] body: - type: checkboxes attributes: label: Is there an existing issue for this? description: Please search to see if an issue already exists for the bug you encountered. options: - label: I have searched the existing issues required: true - type: textarea attributes: label: Current Behavior description: A concise description of what you're experiencing. validations: required: false - type: textarea attributes: label: Expected Behavior description: A concise description of what you expected to happen. validations: required: false - type: textarea attributes: label: Steps To Reproduce description: Steps to reproduce the behavior. placeholder: | 1. In this environment... 2. With this config... 3. Do '...' in [repro codesandbox/stackblitz]() 4. See error... validations: required: false - type: textarea attributes: label: Environment description: | examples: * **GraphiQL Version**: latest * **OS**: Ubuntu 20.04 * **Browser**: Chrome 106 * **Bundler**: vite x.y * **`react` Version**: 18 * **`graphql` Version**: 16 value: | * GraphiQL Version: * OS: * Browser: * Bundler: * `react` Version: * `graphql` Version: validations: required: false - type: textarea attributes: label: Anything else? description: | Links? References? Anything that will give us more context about the issue you are encountering! Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. validations: required: false ================================================ FILE: .github/ISSUE_TEMPLATE/graphiql-feature.md ================================================ --- name: GraphiQL Feature Request about: Request a feature for the graphiql web editor title: '[graphiql] <title>' labels: [graphiql, enhancement] --- <!-- - Some features can be built with the new sidebar plugins We encourage exploring the plugin API prior to opening a feature request: SDK hooks https://graphiql-test.netlify.app/typedoc/modules/graphiql_react.html Sidebar Plugins api: https://graphiql-test.netlify.app/typedoc/modules/graphiql_react.html#graphiqlplugin-2 examples: https://github.com/graphql/graphiql/tree/main/packages/graphiql-plugin-explorer In the event that the plugin API doesn't allow you to build a feature, it may be that expanding the plugin API *itself* is the best place for the feature to be introduced! Consider this flexible solution when opening a new feature request since it also unlocks new opportunities. - Prior to opening a feature request, please search for existing requests. If you find an existing feature that matches your needs, use the 👍 emote to show your support for it. If the specifics of your use case are not covered in the existing feature request but the idea seems similar enough, please take the time to *add new conversation* which helps the feature's design evolve. - If you do not find any other existing requests for the feature you desire, you should open a new feature request. Please take the time to help us understand your use-case as precisely as possible. Be sure to demonstrate that you've evaluated existing features and found them unsuitable and were unable to implement the functionality with the plugin API. Be flexible in your design and consider slight variations which might necessitate a specific API design. We also hope you'll be willing to engage in the on-going design discussion prior to opening a pull-request. borrowed from the apollo server template --> ================================================ FILE: .github/ISSUE_TEMPLATE/language-server-bug.yml ================================================ name: Generic IDE (LSP Server) Bug 🐞 description: File any non syntax highlighting related bugs in vscode or any IDE lsp runtime (vim, intellij, emacs, sublime, etc), with the `graphql-language-service-server` / `graphql-lsp` CLI title: '[lsp-server] 🐞 <title>' labels: [bug, lsp-server] body: - type: checkboxes attributes: label: Is there an existing issue for this? description: Please search to see if an issue already exists for the bug you encountered. options: - label: I have searched the existing issues required: true - type: textarea attributes: label: Current Behavior description: A concise description of the issue you're experiencing. validations: required: false - type: textarea attributes: label: Expected Behavior description: A concise description of what you expected to happen. validations: required: false - type: textarea attributes: label: Steps To Reproduce description: Steps to reproduce the behavior. placeholder: | 1. In this environment... 2. With this (redacted) graphql config with [filename]... 3. Do '...' with [lsp client] 4. See errors in output channel, etc... validations: required: false - type: textarea attributes: label: Environment description: | examples: * **LSP Server Version**: latest * **OS**: Ubuntu 20.04 * **LSP Client**: vscode (`vscode-graphql`, etc), intellij-lsp, nvim coc, etc value: | * LSP Server Version: * OS: * LSP Client: validations: required: false - type: textarea attributes: label: Anything else? description: | Links? References? Anything that will give us more context about the issue you are encountering Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. ================================================ FILE: .github/ISSUE_TEMPLATE/language-server-feature.md ================================================ --- name: LSP/CLI Feature Request about: Request a feature for the `graphql-language-service-server` and/or cli title: '[lsp-server] <title>' labels: [lsp-server, enhancement] --- <!-- ## Current Behavior (if applicable) ## Desired Behavior Helpful things to include: - screenshots & videos where applicable - graphql config sample if related to the problem you are hoping to solve - examples of other graphql language tools that support this, if applicable - if the feature involves adding support for a feature already in the current spec or proposed working group spec, please include a link to the applicable section of the spec ## PRs welcome! If you find a way to solve this problem by modifying the code in either the source or the distributed code, we are more than happy to accept enhancement requests as PRs! --> ================================================ FILE: .github/ISSUE_TEMPLATE.md ================================================ <!-- 1. Have you tried searching issues and discussions to see if your question was already answered? 2. If you want to fix a bug or request a feature, PRs are always welcome! --> ================================================ FILE: .github/workflows/main-test.yml ================================================ name: Main Tests # report coverage on main for codecov baseline on: push: branches: [main] jobs: install: name: Install runs-on: ubuntu-latest steps: - name: Cancel Previous Runs uses: styfle/cancel-workflow-action@0.12.1 with: access_token: ${{ github.token }} - name: Checkout Code uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: cache: yarn - name: Cache node modules id: cache-modules uses: actions/cache@v4 with: path: | **/node_modules key: modules-${{ github.sha }} - uses: actions/cache@v4 with: path: | ~/.cache/Cypress key: cypress-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile --immutable jest: name: Jest Unit Tests runs-on: ubuntu-latest needs: [install] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 - id: cache-modules uses: actions/cache@v4 with: path: | **/node_modules key: modules-${{ github.sha }} - run: yarn test --coverage - uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: coverage/lcov.info fail_ci_if_error: true verbose: true ================================================ FILE: .github/workflows/pr-graphql-compat-check.yml ================================================ name: Build & Test PR w/ GraphQL Regressions on: push: # only on merge to main. # it's rare that this workflow would # show us an error, but when it does it's important! branches: [main] # don't run this regression suite if we don't need to paths-ignore: - '**.md' - 'examples' - '!examples/monaco-graphql-webpack' # TODO: test matrix? permissions: contents: read # to fetch code (actions/checkout) jobs: build: name: Build & Test runs-on: ubuntu-20.04 strategy: matrix: release: # test against the latest 16.x version, which might be newer than what we have - '^16' # test against the oldest version we support - '^16.0.0' # test against the latest alpha - '^17.0.0-alpha' steps: - name: Checkout Code uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: cache: yarn - name: Cache node modules uses: actions/cache@v4 with: path: node_modules key: node_modules-${{hashFiles('yarn.lock')}} restore-keys: node_modules- - name: Force GraphQL ${{ matrix.release }} solution run: yarn repo:resolve graphql@${{ matrix.release }} - run: yarn install --frozen-lockfile --immutable - name: Unit Tests run: yarn test:ci - name: Cypress run: yarn e2e ================================================ FILE: .github/workflows/pr.yml ================================================ name: PR on: pull_request: types: [opened, synchronize] jobs: install: name: Install runs-on: ubuntu-latest steps: - name: Cancel Previous Runs uses: styfle/cancel-workflow-action@0.12.1 with: access_token: ${{ github.token }} - name: Checkout Code uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: cache: yarn - name: Cache node modules id: cache-modules uses: actions/cache@v4 with: path: | **/node_modules key: modules-${{ github.sha }} - uses: actions/cache@v4 with: path: | ~/.cache/Cypress key: cypress-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile --immutable build: name: Build runs-on: ubuntu-latest needs: [install] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 - id: cache-modules uses: actions/cache@v4 with: path: | **/node_modules key: modules-${{ github.sha }} - run: yarn build - uses: actions/cache@v4 with: key: build-${{ github.sha }} path: ${{ env.BUILD-CACHE-LIST }} cspell: name: CSpell runs-on: ubuntu-latest needs: [install] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 - id: cache-modules uses: actions/cache@v4 with: path: | **/node_modules key: modules-${{ github.sha }} - run: yarn lint-cspell prettier: name: Prettier runs-on: ubuntu-latest needs: [install] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 - id: cache-modules uses: actions/cache@v4 with: path: | **/node_modules key: modules-${{ github.sha }} - run: yarn pretty-check jest: name: Jest Unit & Integration Tests runs-on: ubuntu-latest needs: [install] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 - id: cache-modules uses: actions/cache@v4 with: path: | **/node_modules key: modules-${{ github.sha }} - run: yarn test --coverage - uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: coverage/lcov.info fail_ci_if_error: true verbose: true vitest: name: Vitest Unit Tests runs-on: ubuntu-latest needs: [build] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 - id: cache-modules uses: actions/cache@v4 with: path: | **/node_modules key: modules-${{ github.sha }} - uses: actions/cache@v4 with: key: build-${{ github.sha }} path: ${{ env.BUILD-CACHE-LIST }} - run: yarn vitest eslint: name: ESLint runs-on: ubuntu-latest needs: [build] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 - id: cache-modules uses: actions/cache@v4 with: path: | **/node_modules key: modules-${{ github.sha }} - uses: actions/cache@v4 with: key: build-${{ github.sha }} path: ${{ env.BUILD-CACHE-LIST }} - run: yarn eslint types-check: name: Types Check runs-on: ubuntu-latest needs: [build] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 - id: cache-modules uses: actions/cache@v4 with: path: | **/node_modules key: modules-${{ github.sha }} - uses: actions/cache@v4 with: key: build-${{ github.sha }} path: ${{ env.BUILD-CACHE-LIST }} - run: yarn types:check e2e: name: Cypress runs-on: ubuntu-latest needs: [build] steps: - uses: actions/checkout@v4 - id: cache-modules uses: actions/cache@v4 with: path: | **/node_modules key: modules-${{ github.sha }} - uses: actions/cache@v4 with: key: build-${{ github.sha }} path: ${{ env.BUILD-CACHE-LIST }} - uses: actions/cache@v4 with: path: | ~/.cache/Cypress key: cypress-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - name: Cypress run uses: cypress-io/github-action@v6 with: install: false command: yarn e2e - uses: actions/upload-artifact@v4 if: failure() with: name: cypress-screenshots path: packages/graphiql/cypress/screenshots if-no-files-found: ignore - uses: actions/upload-artifact@v4 if: failure() with: name: cypress-videos path: packages/graphiql/cypress/videos if-no-files-found: ignore canary: name: Canary runs-on: ubuntu-latest # ensure the basic checks pass before running the canary needs: [build, jest, eslint, vitest, e2e] if: github.event.pull_request.head.repo.full_name == github.repository steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: actions/setup-node@v4 - id: cache-modules uses: actions/cache@v4 with: path: | **/node_modules key: modules-${{ github.sha }} - uses: actions/cache@v4 with: key: build-${{ github.sha }} path: ${{ env.BUILD-CACHE-LIST }} - name: Setup NPM credentials run: echo "//registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN" >> ~/.npmrc env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Release Canary id: canary uses: 'kamilkisiela/release-canary@master' with: npm-token: ${{ secrets.NPM_TOKEN }} npm-script: 'yarn release:canary' changesets: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Publish a message if: steps.canary.outputs.released == 'true' uses: 'dotansimha/pr-comment@master' with: commentKey: canary message: | The latest changes of this PR are available as canary in npm (based on the declared `changesets`): ``` ${{ steps.canary.outputs.changesetsPublishedPackages}} ``` bot-token: ${{ secrets.GITHUB_TOKEN }} bot: 'github-actions[bot]' github-token: ${{ secrets.GITHUB_TOKEN }} - name: Publish an empty message if: steps.canary.outputs.released == 'false' uses: 'dotansimha/pr-comment@master' with: commentKey: canary message: | The latest changes of this PR are not available as canary, since there are no linked `changesets` for this PR. bot-token: ${{ secrets.GITHUB_TOKEN }} bot: 'github-actions[bot]' github-token: ${{ secrets.GITHUB_TOKEN }} license-check: name: Check Licenses runs-on: ubuntu-latest needs: [install] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 - id: cache-modules uses: actions/cache@v4 with: path: | **/node_modules key: modules-${{ github.sha }} - run: yarn install --frozen-lockfile --immutable - name: License Check run: yarn license-check env: BUILD-CACHE-LIST: | packages/**/dist/**/* packages/**/cjs/**/* packages/**/esm/**/* packages/**/types/**/* packages/codemirror-graphql/*.js* packages/codemirror-graphql/*.d.ts packages/codemirror-graphql/cm6-legacy/**/* packages/codemirror-graphql/results/**/* packages/codemirror-graphql/variables/**/* packages/codemirror-graphql/utils/**/* !**/node_modules ================================================ FILE: .github/workflows/release.yml ================================================ name: Release on: push: branches: [main, graphiql-5] permissions: {} jobs: release: permissions: contents: write # for changesets/action to git push environment: deploy name: Release runs-on: ubuntu-latest steps: - name: Cancel Previous Runs uses: styfle/cancel-workflow-action@0.12.1 with: access_token: ${{ github.token }} - name: Checkout Code uses: actions/checkout@v4 with: fetch-depth: 0 - uses: actions/setup-node@v4 with: cache: yarn - name: Cache node modules uses: actions/cache@v4 id: cache-modules with: path: node_modules key: node_modules-${{hashFiles('yarn.lock')}} restore-keys: node_modules- - run: yarn install --frozen-lockfile --immutable - name: Create Release Pull Request or Publish to npm id: changesets uses: changesets/action@v1 with: version: yarn ci:version # This expects you to have a script called release which does a build for your packages and calls changeset publish publish: yarn release env: # only use GH token here, because GITHUB_TOKEN is no longer allowed to create PRs GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # for vscode marketplace, see https://github.com/microsoft/vscode-vsce/blob/194d59b975523696362ead891dc0f3ddd277b3bd/README.md#linux VSCE_PAT: ${{ secrets.VSCE_PAT }} # for ovsx, see https://github.com/eclipse/openvsx/blob/master/cli/README.md#publish-extensions OVSX_PAT: ${{ secrets.OPEN_VSX_TOKEN }} ================================================ FILE: .gitignore ================================================ *.swp *~ .*.haste_cache.* .DS_Store .secrets *.log .yarn/* !.yarn/releases/* !.yarn/plugins/* node_modules/ coverage/ .nyc_output dist/ esm/ out/ *.vsix *.tsbuildinfo yarn-1.18.0.js *.orig .idea/ # Local Netlify folder .netlify/ examples/*/yarn.lock package-lock.json .eslintcache .cspellcache vite.config.d.ts vite.config.js tsconfig.vitest-temp.json .next/ .turbo/ types/ packages/codemirror-graphql/cm6-legacy/ packages/codemirror-graphql/results/ packages/codemirror-graphql/utils/ packages/codemirror-graphql/variables/ packages/codemirror-graphql/*.js packages/codemirror-graphql/*.d.ts packages/codemirror-graphql/*.map !packages/codemirror-graphql/*.config.js packages/graphiql/cypress/screenshots/ packages/graphiql/cypress/downloads/ packages/graphiql/cypress/videos/ packages/graphiql/typedoc/ packages/graphiql/webpack/ .react-router/ ================================================ FILE: .mailmap ================================================ Angel Gomez Salazar <agomezs@fb.com> Angel Gomez Salazar <agomezs@fb.com> Angel Gomez <AGS-@users.noreply.github.com> Angel Gomez Salazar <agomezs@fb.com> angel.gomez <angelegomezsd@gmail.com> Hyohyeon Jeong <asiandrummer@fb.com> Hyo Jeong <asiandrummer@users.noreply.github.com> ================================================ FILE: .npmignore ================================================ .* *.swp *~ *.iml .*.haste_cache.* .DS_Store .idea npm-debug.log .babelrc CONTRIBUTING.md node_modules coverage resources src packages packages/graphiql/*.html cypress.json babel.config.js **/*.tsbuildinfo ================================================ FILE: .npmrc ================================================ engine-strict=true access=public ================================================ FILE: .nvmrc ================================================ 20 ================================================ FILE: .prettierignore ================================================ # removing this will break tests b/c of whitespace changes + format on save/commit, etc packages/graphql-language-service-server/src/__tests__/parseDocument.test.ts ================================================ FILE: .prettierrc ================================================ { "singleQuote": true, "trailingComma": "all", "arrowParens": "avoid", "proseWrap": "never", "overrides": [ { "files": ["*.md", "*.mdx"], "options": { "printWidth": 80, "proseWrap": "preserve" } }, { "files": "*.svg", "options": { "parser": "html" } } ] } ================================================ FILE: .vscode/extensions.json ================================================ { "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] } ================================================ FILE: .vscode/launch.json ================================================ // A launch configuration that compiles the extension and then opens it inside a new window // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 { "version": "0.2.0", "configurations": [ { "name": "VS Code LSP Extension: Run", "type": "extensionHost", "request": "launch", "runtimeExecutable": "${execPath}", "args": [ "--extensionDevelopmentPath=${workspaceFolder}/packages/vscode-graphql" ], "outFiles": [ "${workspaceFolder}/packages/vscode-graphql/out/extension.js" ], "sourceMaps": true, "preLaunchTask": "watch-vscode" }, { "type": "node", "name": "jest watch", "request": "launch", "program": "${workspaceFolder}/node_modules/jest/bin/jest", "args": [ "--config", "jest.config.js", "--color", "--runInBand", "--watch", "${relativeFile}" ], "cwd": "${workspaceFolder}", "console": "integratedTerminal", "internalConsoleOptions": "neverOpen" }, { "name": "VS Code Exec Extension: Run", "type": "extensionHost", "request": "launch", "runtimeExecutable": "${execPath}", "args": [ "--extensionDevelopmentPath=${workspaceFolder}/packages/vscode-graphql-execution" ], "outFiles": [ "${workspaceFolder}/packages/vscode-graphql-execution/out/extension.js" ], "sourceMaps": true, "preLaunchTask": "watch-vscode-exec" } ] } ================================================ FILE: .vscode/settings.json ================================================ { "npm.packageManager": "yarn", "editor.formatOnSave": true, "files.insertFinalNewline": true, "editor.trimAutoWhitespace": false, "coverage-gutters.showLineCoverage": true, "coverage-gutters.coverageBaseDir": "coverage", "coverage-gutters.coverageFileNames": [ "lcov.info", "cov.xml", "coverage.xml", "jacoco.xml", "coverage.cobertura.xml" ], "typescript.tsdk": "node_modules/typescript/lib" } ================================================ FILE: .vscode/tasks.json ================================================ { "version": "2.0.0", "tasks": [ { "label": "watch-vscode", "type": "npm", "script": "watch-vscode", "problemMatcher": ["$tsc-watch"], "isBackground": true, "presentation": { "reveal": "always" }, "group": { "kind": "build", "isDefault": true } }, { "label": "watch-vscode-exec", "type": "npm", "script": "watch-vscode-exec", "problemMatcher": ["$tsc-watch"], "isBackground": true, "presentation": { "reveal": "always" }, "group": { "kind": "build", "isDefault": true } } ] } ================================================ FILE: .yarnrc.yml ================================================ compressionLevel: 0 enableGlobalCache: false nodeLinker: node-modules yarnPath: .yarn/releases/yarn-4.9.1.cjs ================================================ FILE: CHANGELOG.md ================================================ > **Archived** For up to date changelogs that are automatically generated by [changesets](https://github.com/atlassian/changesets), see CHANGELOG.md files in respective workspaces. For example, the `graphiql` changelog is located at [packages/graphiql/CHANGELOG.md](./packages/graphiql/CHANGELOG.md), and the language server changelog is located at [packages/graphql-language-service-server/CHANGELOG.md](./packages/graphql-language-service-server/CHANGELOG.md) ## GraphiQL 0.14.2 - 11 Aug, 2019 ### Fixes - Fix SSR & use of window when introducing new `extraKeys` capability (#942) ## GraphiQL 0.14.0 - 11 Aug, 2019 ### Features - Add defaultVariableEditorOpen prop (#744) - @acao ### Fixes - Fix formatting of subscription errors - #636, #722 - @benjie - preserve ctrl-f key for macOS - #759 - @pd4d10 - Fix earlier 'Mode graphql failed to advance stream' on Linux by eating an exotic whitespace character - #735 closed by #932 - @benjie - Fix: check `this.editor` exists before `this.editor.off` in QueryEditor ## Codemirror GraphQL - 0.9 - 11 Aug, 2019 ### Chores - BREAKING: Update to gls-interface and gls-parser ^2.1 - BREAKING: Deprecate support for GraphQL 0.11 and below - BREAKING: introduce MIT license - BREAKING: Support GraphQL 14 ## GraphQL Language Service Server 2.1.0 - 11 Aug, 2019 ### Features - Replace babylon with @babel/parser (#879) @ganemone - Add support for gql template tags (#883) @ganemone @Neitsch ### Chores - BREAKING: remove incompatible dependencies on graphql 0.11 and below - BREAKING: add peer support for graphql 14.x - BREAKING: change copyright to MIT - update formatting for monorepo eslint/prettier rules - update readme, badges ## GraphQL Language Service Parser 2.1.0 - 11 Aug, 2019 ### Fixes - Fix 'mode graphql failed to advance stream' error from shift-alt-space, etc - #932 - @benjie ## GraphQL Language Service Interface 2.1.0 - 11 Aug, 2019 ### Features - add \_\_typename field suggestion against object type - (#903) @yoshiakis - Update sortText logic, so that field sort is schema driven rather than alphabetically sorted - (#884) @ganemone ### Chores - BREAKING: add peer support for graphql 14.x - MINOR BREAKING: Use MIT license - add test case for language service hover - @divyenduz @AGS- ## GraphQL Language Service 2.1.0 - BREAKING: add peer support for graphql 14.x - BREAKING: remove incompatible dependencies on graphql 0.11 and below (b/c of gls-utils 2.x) ## GraphQL Language Service Utils 2.1.0 - 11 Aug, 2019 ### Chores - BREAKING: change copyright to MIT - update formatting for monorepo eslint/prettier rules - update readme, badges ## GraphQL Language Service Types 1.3.0 - 11 Aug, 2019 ### Chores - BREAKING: change copyright to MIT - BREAKING: add peer support for graphql 14.x - update formatting for monorepo eslint/prettier rules - update readme, badges ## GraphiQL 0.13.2 - 21 June, 2019 ### Features - Hint/popup/etc DOM nodes use container rather than creating children of <body> - #791 - @codestryke - Add readOnly prop and pass to `QueryEditor` and `VariableEditor` - #718 - @TheSharpieOne - Add operationName to introspection query - #664 - @jbblanchet - Image Preview Functionality - #789 - @dunnbobcat @asiandrummer ### Fixes - Destroy image hover tooltip when it isn't needed - #874 - @acao - Copy non-formatted query to avoid stripping out comments - #832 - @jaebradley - Normalizes no-break spaces - #781 - @zouxuoz - Prevents crashing on Shift-Alt-Space - #781 - @zouxuoz - Fix UI state change after favorite a query - #747 - @benjie ### Chores - BREAKING: Upgrade to `codemirror-graphql` 0.8.3 - #773 - @jonaskello - BREAKING: Change copyright to GraphQL Contributors, License to MIT - Netlify deployments per PR - @orta - Add unit test coverage - Switch to Jest ## Codemirror Graphql Mode 0.8.4 - 11 Aug, 2018 You will now be importing async methods from gls-interface 2.0.0, thus your bundler will require regenerator runtime ## Chores - BREAKING - Use GLS interface/parser 2.1.0 for graphql 14 - BREAKING - This introduces async/await ## GraphQL Language Service Interface 2.0.0 - 11 Sep, 2018 ### Chores - BREAKING: upgrade internal dependencies - gls-parser, gls-types, and gls-utils to 2.0.0 - @lostplan - BREAKING: remove incompatible dependencies on graphql 0.11 and below - @lostplan ## GraphQL Language Service Utils 2.0.0 - 11 Sep, 2018 ### Chores - BREAKING: deprecate support for graphql-js 0.11.x and below - @lostplan [graphql/graphql-language-service#256](https://github.com/graphql/graphql-language-service/pull/256) [new ref](https://github.com/graphql/graphiql/commit/895e68537fd802b8b6ddf2578a1f76f85982c773) because of [this change](https://github.com/graphql/graphiql/commit/068c57fdb4a147be3c2fc38167e2def74d217a82#diff-696ceb17e38e4a274d4a149d24513b78) - BREAKING: GraphQL 14.x support, peer dependency resolutions - #244 - @AGS- ## GraphQL Language Service Utils 1.2.2 - 11 Sep, 2018 ### Chores - add graphql-js 0.13 to peer deps of types package (graphql/graphql-language-service#241) ## GraphQL Language Service Server 2.0.0 - 11 Sep, 2019 ### Chores - add graphql-js 0.13 to peer dependencies (graphql/graphql-language-service#241) - BREAKING: upgrade internal dependencies - gls-interface, gls-server and gls-utils to 2.0.0 @lostplan ## GraphQL Language Service 2.0.0 - 11 Sep, 2018 ### Chores - BREAKING: upgrade internal dependencies - gls-interface, gls-server and gls-utils to 2.0.0 @Sol ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing We welcome contributions and assistance! If you want to know where to start, check out our [Github Projects sorted by name](https://github.com/graphql/graphiql/projects?query=is%3Aopen+sort%3Aname-asc). If you want to add a new feature, note that GraphiQL is eventually going to support its own extension system, and we are rarely adding new features, so make sure you submit feature requests with that in mind. ## Development To get setup for development, refer to [DEVELOPMENT.md](./DEVELOPMENT.md) ## Issues We use GitHub issues to track public bugs and requests. Please ensure your bug description is clear and has sufficient instructions to be able to reproduce the issue. The best way is to provide a reduced test case on jsFiddle or jsBin. ## Pull Requests All active development of this project happens on GitHub. We actively welcome your [pull requests](https://help.github.com/articles/creating-a-pull-request). ### Type Prefixes [a list of type prefixes](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional#type-enum) is available: ```json [ "build", "ci", "chore", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test" ] ``` of these, `fix` and `feat` can trigger patch and minor version releases, reflexively. the rest are useful to help track activity. another commit message that can trigger a major version bump is this: ``` feat: introduce new `fooBar()` API, break `foo()` api - list changes BREAKING CHANGE: break `foo()` api ``` notice the non breaking spaces between header and footer. ## Releasing Please see [the RELEASING.md document](./RELEASING.md). ## License By contributing to GraphiQL, you agree that your contributions will be licensed under the LICENSE file in the project root directory. ================================================ FILE: DEVELOPMENT.md ================================================ # Getting Started Please note that we require a signed GraphQL Specification Membership agreement before landing a contribution. This is checked automatically when you open a PR. If you have not signed the membership agreement (it's free), you will be prompted by the EasyCLA bot. For more details, please see the [GraphQL WG repo](https://github.com/graphql/graphql-wg/tree/main/membership). 0. First, you will need the latest `git`, `yarn` 4, & `node` 18 or greater. macOS, Windows and Linux should all be supported as build environments. > [!WARNING] > > None of the commands below will work with `npm`. Please use `yarn` in this repo. 1. Fork this repo by using the "Fork" button in the upper-right 2. Check out your fork ```sh git clone git@github.com:your-name-here/graphiql.git ``` 3. Install or Update all dependencies ```sh yarn ``` 4. Build all interdependencies so the project you are working on can resolve other packages First, you'll need: ```sh yarn build ``` or ```sh yarn build:watch ``` If you are focused on GraphiQL development, you can run: ```sh yarn dev:graphiql ``` 5. Get coding! If you've added code, add tests. If you've changed APIs, update any relevant documentation or tests. Ensure your work is committed within a feature branch. 6. Ensure all tests pass and build everything ```sh yarn test ``` ## Fix CI issues with linting If you have `prettier` or `eslint --fix`-able issues you see in CI, use — `yarn format` If you see `typescript` build issues, do a `yarn build` locally, and make sure the whole project references tree builds. Changing interfaces can end up breaking their implementations. ## Run tests for GraphiQL: - `yarn test graphiql` will run all tests for graphiql. You can also run tests from a workspace, but most tooling is at the root. - `yarn test --watch` will run `jest` with `--watch` - `yarn e2e` at the root will run the end-to-end suite - `yarn start-monaco` will launch `webpack` dev server for the `monaco` editor example with GitHub API from the root. This is the fastest way to test changes to `graphql-language-service-interface`, parser, etc. If you want these commands to watch for changes to dependent packages in the repo, then run `yarn build --watch` alongside either of these. ## Developing for GraphiQL If you want to develop just for graphiql, you won't need to execute commands from the package subdirectory at `packages/graphiql`. First, you'll need to `yarn build` all the packages from the root. Then, you can run `yarn dev:graphiql` command, which will launch `vite` dev server for GraphiQL. ```text VITE v6.3.4 ready in 1015 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose ``` ## Developing Monaco GraphQL 1. First run `yarn`. 2. Run `yarn tsc --watch` to watch `monaco-graphql` and `graphql-language-service` in one screen session/terminal tab/etc 3. In another session, run `yarn start-monaco` from anywhere in the repository aside from an individual workspace. 4. Alternatively to the webpack example, or in addition, you can run monaco or next.js examples, though these examples are simpler. They also require their own `yarn` or `npm install` as they are excluded from the `workspaces` resolved on global `yarn install` ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) GraphQL Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ <!-- @format --> # GraphQL IDE Monorepo > **Security Notice:** All versions of `graphiql` < `1.4.7` are vulnerable to an > XSS attack in cases where the GraphQL server to which the GraphiQL web app > connects is not trusted. Learn more > [in the graphiql `security` docs directory](docs/security) > **Looking for the [GraphiQL Docs?](packages/graphiql/README.md)**: This is the > root of the monorepo! The full GraphiQL docs are located at > [`packages/graphiql`](packages/graphiql) [![Build Status](https://github.com/graphql/graphiql/workflows/Node.JS%20CI/badge.svg)](https://github.com/graphql/graphiql/actions?query=workflow%3A%22Node.JS+CI%22) [![Discord](https://img.shields.io/discord/625400653321076807.svg)](https://discord.gg/NP5vbPeUFp) [![Code Coverage](https://img.shields.io/codecov/c/github/graphql/graphiql)](https://codecov.io/gh/graphql/graphiql) ![GitHub top language](https://img.shields.io/github/languages/top/graphql/graphiql) ![GitHub language count](https://img.shields.io/github/languages/count/graphql/graphiql) [![Snyk Vulnerabilities for GitHub Repo](https://img.shields.io/snyk/vulnerabilities/github/graphql/graphiql)](https://snyk.io/test/github/graphql/graphiql) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3887/badge)](https://bestpractices.coreinfrastructure.org/projects/3887) ## Overview GraphiQL is the reference implementation of this monorepo, GraphQL IDE, an official project under the GraphQL Foundation. The code uses the permissive MIT license. Whether you want a simple GraphiQL IDE instance for your server, or a more advanced web or desktop GraphQL IDE experience for your framework or plugin, or you want to build an IDE extension or plugin, you've come to the right place! The purpose of this monorepo is to give the GraphQL Community: - a to-specification official language service (see: [API Docs](https://graphiql-test.netlify.app/typedoc)) - a comprehensive LSP server and CLI service for use with IDEs - a codemirror mode - a monaco mode (in the works) - an example of how to use this ecosystem with GraphiQL. - examples of how to implement or extend GraphiQL. ## [`graphiql`](packages/graphiql#readme) <!-- prettier-ignore --> > [![NPM](https://img.shields.io/npm/v/graphiql.svg)](https://npmjs.com/graphiql) > ![jsDelivr hits (npm)](https://img.shields.io/jsdelivr/npm/hm/graphiql) > ![npm downloads](https://img.shields.io/npm/dm/graphiql?label=npm%20downloads) > ![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/graphiql) > ![npm bundle size (version)](https://img.shields.io/bundlephobia/min/graphiql/latest) > ![npm bundle size (version)](https://img.shields.io/bundlephobia/minzip/graphiql/latest) ![Screenshot of GraphiQL with Doc Explorer Open](packages/graphiql/resources/graphiql.png) _/ˈɡrafək(ə)l/_ A graphical interactive in-browser GraphQL IDE. [Try the live demo](https://graphql.org/swapi-graphql). We also have [a demo using our latest netlify build](http://graphiql-test.netlify.app) for the `main` branch. The GraphiQL IDE, implemented in React, currently using [GraphQL mode for CodeMirror](packages/codemirror-graphql#readme) & [GraphQL Language Service](packages/graphql-language-service#readme). **Learn more about [GraphiQL in `packages/graphiql/README.md`](packages/graphiql#readme)** ## [`monaco-graphql`](packages/monaco-graphql#readme) [![NPM](https://img.shields.io/npm/v/monaco-graphql.svg)](https://npmjs.com/monaco-graphql) ![jsDelivr hits (npm)](https://img.shields.io/jsdelivr/npm/hm/monaco-graphql) ![npm downloads](https://img.shields.io/npm/dm/monaco-graphql?label=npm%20downloads) ![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/monaco-graphql) Provides monaco editor with a powerful, schema-driven graphql language mode. Uses the `graphql-language-service`directly. See the [webpack example](examples/monaco-graphql-webpack#readme) for a plain javascript demo using GitHub API ## [`codemirror-graphql`](packages/codemirror-graphql#readme) [![NPM](https://img.shields.io/npm/v/codemirror-graphql.svg)](https://npmjs.com/codemirror-graphql) ![jsDelivr hits (npm)](https://img.shields.io/jsdelivr/npm/hm/codemirror-graphql) ![npm downloads](https://img.shields.io/npm/dm/codemirror-graphql?label=npm%20downloads) ![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/codemirror-graphql) ![Animated Codemirror GraphQL Completion Example](https://raw.githubusercontent.com/graphql/graphiql/main/packages/codemirror-graphql/resources/example.gif) Provides CodeMirror 5 with a parser mode for GraphQL along with a live linter and typeahead hinter powered by your GraphQL Schema. Uses the `graphql-language-service`. ## [`cm6-graphql`](packages/cm6-graphql#readme) [![NPM](https://img.shields.io/npm/v/codemirror-graphql.svg)](https://npmjs.com/cm6-graphql) ![jsDelivr hits (npm)](https://img.shields.io/jsdelivr/npm/hm/cm6-graphql) ![npm downloads](https://img.shields.io/npm/dm/cm6-graphql?label=npm%20downloads) ![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/cm6-graphql) Provides CodeMirror 6 with a full-featured language mode for GraphQL. Uses the `graphql-language-service`. ## [`graphql-language-service`](packages/graphql-language-service#readme) [![NPM](https://img.shields.io/npm/v/graphql-language-service.svg)](https://npmjs.com/graphql-language-service) ![npm downloads](https://img.shields.io/npm/dm/graphql-language-service?label=npm%20downloads) ![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/graphql-language-service) Provides language services for [`graphql-language-service-server`](packages/graphql-language-service-server#readme) [`codemirror-graphql`](packages/codemirror-graphql) and [`monaco-graphql`](packages/monaco-graphql). Previously published separately as the now-retired `graphql-language-service-interface`, `graphql-language-service-parser`, `graphql-language-service-utils` and `graphql-language-service-types`. ## [`graphql-language-service-server`](packages/graphql-language-service-server#readme) [![NPM](https://img.shields.io/npm/v/graphql-language-service-server.svg)](https://npmjs.com/graphql-language-service-server) ![npm downloads](https://img.shields.io/npm/dm/graphql-language-service-server?label=npm%20downloads) ![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/graphql-language-service-server) Provides language services for LSP-based IDE extensions using the `graphql-language-service` ## [`graphql.vscode-graphql`](packages/vscode-graphql#readme) An example implementation of `graphql-language-service-server` for Visual Studio Code. Available [on the marketplace](https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql). OVSX fix is pending. ## [`graphql.vscode-graphql-syntax`](packages/vscode-graphql-syntax#readme) A new syntax highlighting-only extension for vscode to be used by other vscode extensions. ## [`graphql.vscode-graphql-execution`](packages/vscode-graphql-execution#readme) An extension for vscode-graphql that allows inline query execution. ## [`graphql-language-service-cli`](packages/graphql-language-service-cli#readme) [![NPM](https://img.shields.io/npm/v/graphql-language-service-cli.svg)](https://npmjs.com/graphql-language-service-cli) ![npm downloads](https://img.shields.io/npm/dm/graphql-language-service-cli?label=npm%20downloads) ![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/graphql-language-service-cli) Provides a CLI for the language service server. ## Browser & Runtime Support Many of these packages need to work in multiple environments. By default, all typescript packages target `es6`. `graphql-language-service-server` and `graphql-language-service-cli` are made for the node runtime, so they target `es2017` `codemirror-graphql` and the `graphiql` browser bundle use the [`.browserslistrc`](./.browserslistrc), which targets modern browsers to keep bundle size small and keep the language services performant where async/await is used, and especially to avoid the requirement of `regenerator-runtime` or special babel configuration. ### [`.browserslistrc`](./.browserslistrc): ``` last 2 versions Firefox ESR not dead not IE 11 not ios 10 maintained node versions ``` To be clear, we do _not_ support Internet Explorer or older versions of evergreen browsers. ## Development To get setup for local development of this monorepo, refer to [DEVELOPMENT.md](./DEVELOPMENT.md) # Contributing to this repo This is an open source project, and we welcome contributions. Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute. This repository is managed by EasyCLA. Project participants must sign the free [GraphQL Specification Membership agreement](https://preview-spec-membership.graphql.org) before making a contribution. You only need to do this one time, and it can be signed by [individual contributors](http://individual-spec-membership.graphql.org) or their [employers](http://corporate-spec-membership.graphql.org). To initiate the signature process please open a PR against this repo. The EasyCLA bot will block the merge if we still need a membership agreement from you. Please note that EasyCLA is configured to accept commits from certain GitHub bots. These are approved on an exception basis once we are confident that any content they create is either unlikely to consist of copyrightable content or else was written by someone who has already signed the CLA (e.g., a project maintainer). The bots that have currently been approved as exceptions are: - github-actions (exclusively for the `changesets` Action) You can find [detailed information here](https://github.com/graphql/graphql-wg/tree/main/membership). If you have issues, please email [operations@graphql.org](mailto:operations@graphql.org). ## Maintainers Maintainers of this repository regularly review PRs and issues and help advance the GraphiQL roadmap ### Alumni Without these amazing past maintainers, where would we be?! - [@leebyron](https://github.com/leebyron) - original author of all libraries - [@asiandrummer](https://github.com/asiandrummer) - original creator of GraphiQL - [@wincent](https://github.com/wincent) - early co-author and maintainer - [@lostplan](https://github.com/lostplan) - maintained the language service ecosystem until about 2017 - [@IvanGoncharov](https://github.com/ivangoncharov) - maintainer and transitional mentor to @acao and others - [@orta](https://github.com/orta) - has helped with so many parts of the project over the years, and provided the original redesign! - [@divyenduz](https://github.com/divyenduz) - the original creator of `vscode-graphql`, and contributor to much of the ecosystem. Thanks Divy! ### Active Maintainers who are currently active (to varying degrees, please contact us via our discord channels!): - [@imolorhe](https://github.com/imolorhe) - [@yoshiakis](https://github.com/yoshiakis) - [@urigo](https://github.com/urigo) - [@timsuchanek](https://github.com/timsuchanek) - [@thomasheyenbrock](https://github.com/thomasheyenbrock) - [@n1ru4l](https://github.com/n1ru4l) - [@acao](https://github.com/acao) - [@stonexer](https://github.com/stonexer) - [@dimaMachina](https://github.com/dimaMachina) - [@dotansimha](https://github.com/dotansimha) - [@saihaj](https://github.com/saihaj) - [@jonathanawesome](https://github.com/jonathanawesome) - [@cshaver](https://github.com/cshaver) > Thank you graphql community for all the help & support! I did it all for you, > and I couldn't have done it without you ❤️ - @acao ### Fielding Proposals! The door is open for proposals for the new GraphiQL Plugin API, and other ideas on how to make the rest of the IDE ecosystem more performant, scalable, interoperable and extensible. Feel free to open a PR to create a document in the `/proposals/` directory. Eventually we hope to move these to a repo that serves this purpose. ## Community - **Discord** [![Discord](https://img.shields.io/discord/625400653321076807.svg)](https://discord.gg/NP5vbPeUFp) - Most discussion outside of GitHub happens on the GraphQL [Discord Server](https://discord.gg/NP5vbPeUFp) - **Twitter** - [@GraphiQL](https://twitter.com/@GraphiQL) and [#GraphiQL](https://twitter.com/hashtag/GraphiQL) - **GitHub** - Create feature requests, discussions issues and bugs above - **Working Group** - Yes, you're invited! Monthly planning/decision making meetings, and working sessions every two weeks on zoom! [Learn more.](working-group#readme) ================================================ FILE: RELEASING.md ================================================ # Cutting New Releases TODO: Redo for `changesets`. See [`Changesets Readme`](./.changeset/README.md) ================================================ FILE: SECURITY.md ================================================ # GraphiQL Ecosystem Security Advisories Security Advisories for packages in this repository will be listed here ## GraphiQL ### 2021 - [Introspection Schema XSS Attack](./docs/security/2021-introspection-schema-xss.md) ================================================ FILE: babel.config.js ================================================ // for ESM don't transpile modules const envConfig = { modules: 'commonjs', }; if (process.env.ESM) { envConfig.modules = false; envConfig.targets = { node: 'current' }; envConfig.bugfixes = true; } if (process.env.CDN) { envConfig.modules = 'umd'; envConfig.targets = null; } module.exports = { presets: [ [require.resolve('@babel/preset-env'), envConfig], require.resolve('@babel/preset-react'), require.resolve('@babel/preset-typescript'), ], env: { test: { presets: [ [require.resolve('@babel/preset-env'), envConfig], [require.resolve('@babel/preset-react'), { runtime: 'automatic' }], require.resolve('@babel/preset-typescript'), ], plugins: [require.resolve('babel-plugin-macros')], }, development: { compact: false, }, }, plugins: [ require.resolve('@babel/plugin-proposal-class-properties'), require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'), require.resolve('@babel/plugin-proposal-optional-chaining'), require.resolve('@babel/plugin-transform-private-methods'), ['babel-plugin-transform-import-meta', { module: 'ES6' }], ], }; ================================================ FILE: cspell.json ================================================ { "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", "language": "en", "useGitignore": true, "cache": { "useCache": true }, "dictionaries": ["custom-words"], "dictionaryDefinitions": [ { "name": "custom-words", "path": "./resources/custom-words.txt", "addWords": true } ], "ignorePaths": [ "**/CHANGELOG.md", "**/package.json", "**/esbuild.js", ".eslintrc.js", ".vscode/extensions.json", "packages/monaco-graphql/test/monaco-editor.test.ts", "working-group" ], "files": ["**/*.{js,cjs,mjs,ts,jsx,tsx,md,mdx,html,json,css,toml,yaml,yml}"] } ================================================ FILE: docs/migration/graphiql-2.0.0.md ================================================ # Upgrading `graphiql` from `1.x` to `2.0.0` Hello GraphiQL user and thanks for upgrading! This migration guide walks you through all changes that come with `graphiql@2.0.0`, in particular the breaking ones, and will show you how to upgrade your `1.x` implementation. > If you encounter any issues while upgrading that are not covered in here, > please open an issue or PR on this repo and we will extend this guide. ## Design refresh including dark theme Arguably the biggest change in `graphiql@2` is the new design of the UI. It has been reworked from scratch to look more modern while keeping its simplistic look and feel. We also finally added a built-in dark theme. Theme selection is based on system defaults and can be changed in the new settings dialog (available by clicking on the gear icon at the bottom of the sidebar on the left of the screen). Starting with `graphiql@2`, the only officially supported way of customizing the CSS that make up the looks of GraphiQL is by overriding the design tokens defined using CSS variables. In particular, changes to class names are no longer considered breaking changes. If you use class-name based selectors to change styles your overrides might break with minor or patch version bumps. A list of all CSS variables that can be customized can be found in the [`root.css`](../../packages/graphiql-react/src/style/root.css) file of the `@graphiql/react` package. The variables for colors use a list of values that can be passed into the [`hsl`](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl) function in CSS that defines colors by hue, saturation and lightness. ## Changes to `GraphiQL` component props A couple of props of the `GraphiQL` have undergone breaking changes: - The props `defaultVariableEditorOpen` and `defaultSecondaryEditorOpen` have been merged into one prop `defaultEditorToolsVisibility`. The default behavior if this prop is not passed is that the editor tools are shown if at least one of the secondary editors has contents. You can pass the following values to the prop: - Passing `false` hides the editor tools. - Passing `true` shows the editor tools. - Passing `"variables"` explicitly shows the variables editor. - Passing `"headers"` explicitly shows the headers editor. - The props `docExplorerOpen`, `onToggleDocs` and `onToggleHistory` have been removed. They are replaced by the more generic props `visiblePlugin` (for controlling which plugin is visible) and `onTogglePluginVisibility` (which is called each time the visibility of any plugin changes). - The `headerEditorEnabled` prop has been renamed to `isHeadersEditorEnabled`. - The `ResultsTooltip` prop has been renamed to `responseTooltip`. ### Tabs enabled by default Tabs were supported opt-in starting with `@graphiql@1.8`. With `graphiql@2` tabs are now always enabled. The `tabs` prop (which previously toggled if tabs were enabled or not) has therefore been replaced with a prop `onTabChange`. If you used the `tabs` prop before to pass this function you can change your implementation like so: ```diff <GraphiQL - tabs={{ onTabChange: (tabState) => {/* do something */} }} + onTabChange={(tabState) => {/* do something */}} /> ``` As long as only one session is open, the tab bar above the editors is hidden. A plus icon next to the logo on the top right allows the user to open more tabs. With at least two tabs opened, the tab bar appears above the editors. ## Removed package exports All React components apart from the `GraphiQL` component have been moved to the `@graphiql/react` package. That's why we removed most of the exports with `graphiql@2`. Here is a list of all exported components and functions that have been removed and where you can find them now: - `QueryEditor`, `VariableEditor` and `DocExplorer`: Now exported from `@graphiql/react` under the same names - Note that the `schema` prop of the `DocExplorer` no longer exists, 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` - `onHasCompletion`: This function is only meant to be used internally, it is no longer being exported - `fillLeafs`, `getSelectedOperationName` and `mergeAst`: Now exported from `@graphiql/toolkit` under the same names - types `Fetcher`, `FetcherOpts`, `FetcherParams`, `FetcherResult`, `FetcherReturnType`, `Observable`, `Storage` and `SyncFetcherResult`: Exported from `@graphiql/toolkit` under the same names (previously just re-exported by `graphiql`) ## `GraphiQL` is now a function component The `GraphiQL` component in `graphiql@1.x` was a class component. That allowed easy access to its props, state and methods by attaching a ref to it like so: ```tsx import { createGraphiQLFetcher } from '@graphiql/toolkit'; import { GraphiQL } from 'graphiql'; import { Component } from 'react'; const fetcher = createGraphiQLFetcher({ url: 'https://my.endpoint' }); class MyComponent extends Component { _graphiql: GraphiQL; componentDidMount() { const query = this._graphiql.getQueryEditor().getValue(); } render() { return <GraphiQL ref={r => (this._graphiql = r)} fetcher={fetcher} />; } } ``` With `graphiql@2` we refactored the codebase to more "modern" React. This also meant replacing all class components with function components. The code above no longer works in `graphiql@2` as attaching refs to function components is not possible in React. All logic and state management now lives in multiple React contexts, provided by the `@graphiql/react` package. The `GraphiQL` component is now basically combining two other components, both of which are also exported by the package. - `GraphiQLProvider` (originally coming from `@graphiql/react`) will render all context providers and takes care of state management - `GraphiQLInterface` is defined in the `graphiql` package and renders the UI If you want to read or modify GraphiQL state from your custom implementation you need to render both the above components separately as the hooks for consuming the context values only work in components that are rendered inside the provider component. With all that, the example above can be refactored a such: ```jsx import { useEditorContext } from '@graphiql/react'; import { createGraphiQLFetcher } from '@graphiql/toolkit'; import { GraphiQLInterface, GraphiQLProvider } from 'graphiql'; import { useEffect } from 'react'; const fetcher = createGraphiQLFetcher({ url: 'https://my.endpoint' }); function MyComponent() { return ( <GraphiQLProvider fetcher={fetcher}> <InsideContext /> </GraphiQLProvider> ); } function InsideContext() { // Calling this hook would not work in `MyComponent` (it would return `null`) const { queryEditor } = useEditorContext(); useEffect(() => { const query = queryEditor.getValue(); }, [queryEditor]); return <GraphiQLInterface />; } ``` Here is a list of all public class methods that existed in `graphiql@1` and its replacement in `graphiql@2`. All the contexts mentioned below can be accessed using a hook exported by `@graphiql/react`. - `getQueryEditor`: Use the `queryEditor` property from the `EditorContext`. - `getVariableEditor`: Use the `variableEditor` property from the `EditorContext`. - `getHeaderEditor`: Use the `headerEditor` property from the `EditorContext`. - `refresh`: Calling this method should no longer be necessary, all editors will refresh automatically after resizing. If you really need to refresh manually you have to call the `refresh` method on all editor instances individually. - `autoCompleteLeafs`: Use the `useAutoCompleteLeafs` hook provided by `@graphiql/react` that returns this function. There are a couple more class methods that were intended to be private and were already removed starting in `graphiql@1.9.0`. Since they were not actually marked with `private`, here's an extension to the above list for these methods: - `handleClickReference`: This was a callback method triggered when clicking on a type or field. It would open the doc explorer for the clicked reference. If you want to manually mimic this behavior you can use the `push` method from the `ExplorerContext` to add an item to the navigation stack of the doc explorer, and you can use the `setVisiblePlugin` method of the `PluginContext` (use the `usePluginContext()` hook to access this) to show the doc explorer plugin (by passing the `DOC_EXPLORER_PLUGIN` object provided by `@graphiql/react`). - `handleRunQuery`: To execute a query, use the `run` method of the `ExecutionContext`. If you want to explicitly set an operation name, call the `setOperationName` method of the `EditorContext` provider before that (passing in the operation name string as argument). - `handleEditorRunQuery`: Use the `run` method of the `ExecutionContext`. - `handleStopQuery`: Use the `stop` method from the `ExecutionContext`. - `handlePrettifyQuery`: Use the `usePrettifyEditors` hook provided by `@graphiql/react` that returns this function. - `handleMergeQuery`: Use the `useMergeQuery` hook provided by `@graphiql/react` that returns this function. - `handleCopyQuery`: Use the `useCopyQuery` hook provided by `@graphiql/react` that returns this function. - `handleToggleDocs` and `handleToggleHistory`: Use the `setVisiblePlugin` method of the `PluginContext`. Some class methods were callbacks to modify state which are not intended to be called manually. All these methods don't have a successor: `handleEditQuery`, `handleEditVariables`, `handleEditHeaders`, `handleEditOperationName`, `handleSelectHistoryQuery`, `handleResetResize` and `handleHintInformationRender` ### Static properties have been removed In `graphiql@1.x` the `GraphiQL` component included a bunch of static properties that exposed utility functions and other components. Most of these have been removed in `graphiql@2` since the components and functions have been moved to the `@graphiql/react` and `@graphiql/toolkit` packages. The properties that remain on the `GraphiQL` function component are `GraphiQL.Logo`, `GraphiQL.Toolbar` and `GraphiQL.Footer`. All three are React components that can be passed as children to the `GraphiQL` components and override certain parts of the UI: - `GraphiQL.Logo`: Overrides the "logo" at the top right of the screen. By default, it contains the text "Graph*i*QL". - `GraphiQL.Toolbar`: Overrides the toolbar next to the operation editor. By default, if contains buttons for prettifying the current editor contents, merging fragment definitions into the operation definition and copying the contents of the operation editor to the clipboard. Note that the default buttons will not be shown when passing this component as child to `GraphiQL`, instead it will show the children you pass to `GraphiQL.Toolbar`. The execute button will always be shown. If you want to keep the default buttons and add additional buttons you can use the `toolbar` prop. - `GraphiQL.Footer`: Adds a section below the response editor. By default, this won't show up in the UI. Here is a list of all the static properties that have been removed and their replacements: - `GraphiQL.formatResult` and `GraphiQL.formatError`: Replaced by equally named functions from `@graphiql/toolkit` - `GraphiQL.QueryEditor`, `GraphiQL.VariableEditor` and `GraphiQL.HeaderEditor`: Replaced by equally named components from `@graphiql/react` - `GraphiQL.ResultViewer`: Replaced by the `ResponseEditor` component from `@graphiql/react` - `GraphiQL.Button`: Replaced by the `ToolbarButton` component from `@graphiql/react` - `GraphiQL.ToolbarButton`: This exposed the same component as `GraphiQL.Button`. - `GraphiQL.Menu`: Replaced by the `ToolbarMenu` component from `@graphiql/react` - `GraphiQL.MenuItem`: Replaced by the `ToolbarMenu.Item` component from `@graphiql/react` - `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 { createGraphiQLFetcher } from '@graphiql/toolkit'; import { GraphiQL } from 'graphiql'; const fetcher = createGraphiQLFetcher({ url: 'https://my.endpoint' }); function MyComponent() { return ( <GraphiQL fetcher={fetcher}> <GraphiQL.Toolbar> {/* Add custom styles for your buttons using the given class */} <div className="button-group"> <button>1</button> <button>2</button> <button>3</button> </div> </GraphiQL.Toolbar> </GraphiQL> ); } ``` ### `window.g` has been removed In `graphiql@1.x` the `GraphiQL` class component stored a reference to itself on a global property named `g`. This property has been removed as refs don't exist for function components. (Also, the property was only intended for internal use like testing in the first place.) ================================================ FILE: docs/migration/graphiql-4.0.0.md ================================================ # Upgrading `graphiql` from `3.x` to `4.0.0` --- ## `graphiql` - Dropped support for **React 16/17**, added support for **React 19** - Dropped **CommonJS** build output – now **ESM only** - Improved UI of tabs - Changed tabs behavior – tabs are always visible (even if only one) - Updated tabs tooltip usage – now use HTML `title` attribute - Removed **default export** - Removed `disableTabs` option - Improved Markdown handling – single newlines are ignored - Added `onPrettifyQuery` callback for custom formatting - ⚠️ Deprecate **UMD CDN build `index.umd.js`** - Changed **CDN paths** and **style import** > [!WARNING] > > ⚠️ **`index.umd.js` is deprecated**. Switch to the [ESM CDN example](../../examples/graphiql-cdn/index.html). ### UMD CDN path changes ```diff -https://unpkg.com/graphiql/graphiql.js -https://unpkg.com/graphiql/graphiql.min.js +https://unpkg.com/graphiql/dist/index.umd.js // ⚠️ deprecated -https://unpkg.com/graphiql/graphiql.css -https://unpkg.com/graphiql/graphiql.min.css +https://unpkg.com/graphiql/dist/style.css ``` ### Default export removed ```diff -import GraphiQL from 'graphiql' +import { GraphiQL } from 'graphiql' ``` ### Style import changed ```diff -import 'graphiql/graphiql.css' +import 'graphiql/style.css' ``` ### Toolbar API migration #### `toolbar.additionalContent` → `<GraphiQL.Toolbar>` **Before:** ```tsx <GraphiQL toolbar={{ additionalContent: <button>My button</button> }} /> ``` **After:** ```jsx <GraphiQL> <GraphiQL.Toolbar> {({ merge, prettify, copy }) => ( <> {prettify} {merge} {copy} <button>My button</button> </> )} </GraphiQL.Toolbar> </GraphiQL> ``` --- #### `toolbar.additionalComponent` → `<GraphiQL.Toolbar>` **Before:** ```jsx <GraphiQL toolbar={{ additionalComponent: function MyComponentWithAccessToContext() { return <button>My button</button>; }, }} /> ``` **After:** ```jsx <GraphiQL> <GraphiQL.Toolbar> {({ merge, prettify, copy }) => ( <> {prettify} {merge} {copy} <MyComponentWithAccessToContext /> </> )} </GraphiQL.Toolbar> </GraphiQL> ``` --- #### Customizing default toolbar buttons You can reorder or remove default toolbar buttons: ```tsx <GraphiQL> <GraphiQL.Toolbar> {({ prettify, copy }) => ( <> {copy} {/* Move copy button to the top */} {prettify} {/* Omit merge button */} </> )} </GraphiQL.Toolbar> </GraphiQL> ``` --- ## `@graphiql/react` - Dropped support for **React 16/17**, added support for **React 19** - Dropped **CommonJS** build output - Improved UI of tabs - Updated dependencies: `@radix-ui` and `@headlessui/react` - Added `onPrettifyQuery` callback for custom formatting - Improved Markdown handling (ignores single newlines) - Style import changed: ```diff -import '@graphiql/react/dist/style.css' +import '@graphiql/react/style.css' ``` --- ## `@graphiql/plugin-code-exporter` - Dropped support for **React 16/17**, added support for **React 19** - Dropped **CommonJS** build output - Updated ESM-based CDN example: [code-exporter ESM CDN example](../../packages/graphiql-plugin-code-exporter/example/index.html) - ⚠️ UMD build deprecated – migrate to ESM-based CDN - Style import changed: ```diff -import '@graphiql/plugin-code-exporter/dist/style.css' +import '@graphiql/plugin-code-exporter/style.css' ``` --- ## `@graphiql/plugin-explorer` - Dropped support for **React 16/17**, added support for **React 19** - Dropped **CommonJS** build output - Improved styles for the explorer UI - Updated ESM-based CDN example: [explorer ESM CDN example](../../examples/graphiql-cdn/index.html) - ⚠️ UMD build deprecated – migrate to ESM-based CDN - Style import changed: ```diff -import '@graphiql/plugin-explorer/dist/style.css' +import '@graphiql/plugin-explorer/style.css' ``` ================================================ FILE: docs/migration/graphiql-5.0.0.md ================================================ # Upgrading `graphiql` from `4.x` to `5.0.0` Starting from GraphiQL 5, you need to set up Monaco workers in your project: - For **Vite** projects you must: 1. Install `vite-plugin-monaco-editor` package: ```sh npm install vite-plugin-monaco-editor --save-dev ``` 2. Import and configure the plugin in your `vite.config.mjs` file: ```diff // vite.config.mjs import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' +import $monacoEditorPlugin from 'vite-plugin-monaco-editor' +const monacoEditorPlugin = $monacoEditorPlugin.default ?? $monacoEditorPlugin export default defineConfig({ plugins: [ react(), + monacoEditorPlugin({ + languageWorkers: ['editorWorkerService', 'json'], + customWorkers: [ + { + label: 'graphql', + entry: 'monaco-graphql/esm/graphql.worker.js' + } + ] + }) ] }) ``` > [!NOTE] > > See [Vite example](../../examples/graphiql-vite/src/App.jsx). - For Webpack projects such as **Next.js** you must import: ```js import 'graphiql/setup-workers/webpack'; ``` > [!NOTE] > > See [Next.js example](../../examples/graphiql-nextjs/src/app/page.tsx). - For ESM-based CDN usages, you must use [`?worker` query](https://esm.sh/#web-worker) to load the module as a web worker: ```js import createJSONWorker from 'https://esm.sh/monaco-editor/esm/vs/language/json/json.worker.js?worker'; import createGraphQLWorker from 'https://esm.sh/monaco-graphql/esm/graphql.worker.js?worker'; import createEditorWorker from 'https://esm.sh/monaco-editor/esm/vs/editor/editor.worker.js?worker'; globalThis.MonacoEnvironment = { getWorker(_workerId, label) { switch (label) { case 'json': return createJSONWorker(); case 'graphql': return createGraphQLWorker(); } return createEditorWorker(); }, }; ``` > [!NOTE] > > See [CDN example](../../examples/graphiql-cdn/index.html). ## Allow to Override All Default GraphiQL Plugins Starting from GraphiQL 5, you can override all default plugins. ### Removing All Default Plugins To remove all default plugins (currently **Doc Explorer** and **History**), set `referencePlugin={null}` and pass an empty array to the `plugins` prop: ```jsx import { GraphiQL } from 'graphiql'; const myPlugins = []; function App() { return ( <GraphiQL referencePlugin={null} // Removes Doc Explorer plugin plugins={myPlugins} // Removes History plugin /> ); } ``` > [!NOTE] > > If you're using a custom Doc Explorer, pass it to the `referencePlugin` prop — > **not** the `plugins` array. It will be automatically included and always > rendered first. ### Adding Plugins While Keeping Defaults If you're adding custom plugins (e.g., the **Explorer** plugin) and want to keep the **History** plugin, you must explicitly include it in the `plugins` array: ```jsx import { GraphiQL, HISTORY_PLUGIN } from 'graphiql'; import { explorerPlugin } from '@graphiql/plugin-explorer'; const myPlugins = [HISTORY_PLUGIN, explorerPlugin()]; function App() { return <GraphiQL plugins={myPlugins} />; } ``` --- ## `graphiql` > [!WARNING] > > ⚠️ UMD build is removed. Switch to the [ESM CDN example](../../examples/graphiql-cdn/index.html). - Migration from Codemirror to [Monaco Editor](https://github.com/microsoft/monaco-editor) - Replacing `codemirror-graphql` with [`monaco-graphql`](../../packages/monaco-graphql) - Clicking on a reference in the operation editor now works by holding `Cmd` on macOS or `Ctrl` on Windows/Linux - Support for comments in **Variables** and **Headers** editors - Added new examples: [**GraphiQL x Vite**](../../examples/graphiql-vite) and [**GraphiQL x Next.js**](../../examples/graphiql-nextjs) - Removed examples: **GraphiQL x Parcel** and **GraphiQL x Create React App** - Removed props - `query` - `variables` - `headers` - `response` - `readOnly` - `keyMap`. To use Vim or Emacs keybindings in Monaco, you can use community plugins. Monaco Vim: https://github.com/brijeshb42/monaco-vim. Monaco Emacs: https://github.com/aioutecism/monaco-emacs - `validationRules`. Use custom GraphQL worker, see https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql#custom-webworker-for-passing-non-static-config-to-worker.' > [!NOTE] > > If you used `query`, `variables` and `headers` in integration tests, you can use the new `initialQuery`, > `initialVariables` and `initialHeaders` props instead. These props will only be used for the first tab. > When opening more tabs, the operation editor will start out empty. - Added new props - `initialQuery` - `initialVariables` - `initialHeaders` - feat: allow `children: ReactNode` for `<GraphiQL.Toolbar />` component --- ## `@graphiql/react` > [!IMPORTANT] > > Clicking on a reference in the operation editor now works by holding `Cmd` on macOS or `Ctrl` on Windows/Linux. - `usePrettifyEditors`, `useCopyQuery`, `useMergeQuery`, `useExecutionContext`, `usePluginContext`, `useSchemaContext`, `useStorageContext` hooks are deprecated. - Add new `useGraphiQL` and `useGraphiQLActions` hooks instead. See updated [README](../../packages/graphiql-react/README.md#available-stores) for more details about them. - remove `useSynchronizeValue` hook - fix `defaultQuery` with empty string does not result in an empty default query - fix `defaultQuery`, when is set will only be used for the first tab. When opening more tabs, the operation editor will start out empty - fix execute query shortcut in operation editor, run it even there are no operations in the operation editor - fix plugin store, save last opened plugin in storage - remove `onClickReference` from variable editor - fix shortcut text per OS for default query and in run query in execute query button's tooltip The `ToolbarMenu` component has changed. - The `label` and `className` props were removed - The `button` prop should now be a button element ```jsx <ToolbarMenu label="Options" button={ <ToolbarButton label="Options"> <SettingsIcon className="graphiql-toolbar-icon" aria-hidden="true" /> </ToolbarButton> } > <ToolbarMenu.Item onSelect={() => console.log('Clicked!')}> Test </ToolbarMenu.Item> </ToolbarMenu> ``` ## `@graphiql/plugin-code-exporter` > [!WARNING] > > ⚠️ UMD build is removed. Switch to the [ESM CDN example](../../packages/graphiql-plugin-code-exporter/example/index.html). --- ## `@graphiql/plugin-explorer` > [!WARNING] > > ⚠️ UMD build is removed. Switch to the [ESM CDN example](../../examples/graphiql-cdn/index.html). --- ## @graphiql/plugin-doc-explorer - `useExplorerContext` hook is deprecated. Use new `useDocExplorer` and `useDocExplorerActions` hooks instead. - The shortcut to focus on the Doc Explorer search input is now `Cmd/Ctrl+Alt+K` instead of the previous `Cmd/Ctrl+K`. This was changed because monaco-editor has a built-in `Cmd/Ctrl+K` command. - push a field type on stack too before field - fix: show spinner in doc explorer based on `isIntrospecting` value, and not based on `isFetching` --- ## @graphiql/plugin-history - `useHistoryContext` hook is deprecated. Use new `useHistory` and `useHistoryActions` hooks instead. ================================================ FILE: docs/security/2021-introspection-schema-xss.md ================================================ - [1. GraphiQL introspection schema template injection attack: Advisory Statement](#1-graphiql-introspection-schema-template-injection-attack-advisory-statement) - [1.1. Impact](#11-impact) - [1.2. Scope](#12-scope) - [1.3. Patches](#13-patches) - [1.3.1 CDN bundle implementations may be automatically patched](#131-cdn-bundle-implementations-may-be-automatically-patched) - [1.4. Workarounds for Older Versions](#14-workarounds-for-older-versions) - [1.5. How to Re-create the Exploit](#15-how-to-re-create-the-exploit) - [1.6. Credit](#16-credit) - [1.7. References](#17-references) - [1.8. For more information](#18-for-more-information) - [2. More Details on the Vulnerability](#2-more-details-on-the-vulnerability) - [3. Compromised introspection Schema Example](#3-compromised-introspection-schema-example) ## 1. GraphiQL introspection schema template injection attack: Advisory Statement This is a security advisory for an XSS vulnerability in `graphiql`. A similar vulnerability affects `graphql-playground`, a fork of `graphiql`. There is a corresponding `graphql-playground` [advisory](https://github.com/graphql/graphql-playground/security/advisories/GHSA-59r9-6jp6-jcm7) and [Apollo Server advisory](https://github.com/apollographql/apollo-server/security/advisories/GHSA-qm7x-rc44-rrqw). ### 1.1. Impact All versions of `graphiql` older than [`graphiql@1.4.7`](https://github.com/graphql/graphiql/releases/tag/v1.4.7) are vulnerable to compromised HTTP schema introspection responses or `schema` prop values with malicious GraphQL type names, exposing a dynamic XSS attack surface that can allow code injection on operation autocomplete. In order for the attack to take place, the user must load a vulnerable schema in `graphiql`. There are a number of ways that can occur. By default, the schema URL is _not_ attacker-controllable in `graphiql` or in its suggested implementations or examples, leaving only very complex attack vectors. If a custom implementation of `graphiql`'s `fetcher` allows the schema URL to be set dynamically, such as a URL query parameter like `?endpoint=` in `graphql-playground`, or a database provided value, then this custom `graphiql` implementation is _vulnerable to phishing attacks_, and thus much more readily available, low or no privilege level xss attacks. The URLs could look like any generic looking graphql schema URL. Because this exposes an XSS attack surface, it would be possible for a threat actor to exfiltrate user credentials, data, etc. using arbitrary malicious scripts, without it being known to the user. ### 1.2. Scope This advisory describes the impact on the `graphiql` package. The vulnerability also affects other projects forked from `graphiql` such as [`graphql-playground`](https://github.com/graphql/graphql-playground/security/advisories/GHSA-59r9-6jp6-jcm7) and the `graphql-playground` fork distributed by Apollo Server. The impact is more severe in the `graphql-playground` implementations; see the [`graphql-playground` advisory](https://github.com/graphql/graphql-playground/security/advisories/GHSA-59r9-6jp6-jcm7) and [Apollo Server advisory](https://github.com/apollographql/apollo-server/security/advisories/GHSA-qm7x-rc44-rrqw) for details. This vulnerability does not impact `codemirror-graphql`, `monaco-graphql` or other dependents, as it exists in `onHasCompletion.ts` in `graphiql`. It does impact all forks of `graphiql`, and every released version of `graphiql`. It should be noted that desktop clients such as Altair, Insomnia, Postwoman, do not appear to be impacted by this. ### 1.3. Patches `graphiql@1.4.7` addresses this issue via defense in depth. - **HTML-escaping text** that should be treated as text rather than HTML. In most of the app, this happens automatically because React escapes all interpolated text by default. However, one vulnerable component uses the unsafe `innerHTML` API and interpolated type names directly into HTML. We now properly escape that type name, which fixes the known vulnerability. - **Validates the schema** upon receiving the introspection response or schema changes. Schemas with names that violate the GraphQL spec will no longer be loaded. (This includes preventing the Doc Explorer from loading.) This change is also sufficient to fix the known vulnerability. You can disable this validation by setting `dangerouslyAssumeSchemaIsValid={true}`, which means you are relying only on escaping values to protect you from this attack. - **Ensuring that user-generated HTML is safe**. Schemas can contain Markdown in `description` and `deprecationReason` fields, and the web app renders them to HTML using the `markdown-it` library. As part of the development of `graphiql@1.4.7`, we verified that our use of `markdown-it` prevents the inclusion of arbitrary HTML. We use `markdown-it` without setting `html: true`, so we are comfortable relying on [`markdown-it`'s HTML escaping](https://github.com/markdown-it/markdown-it/blob/master/docs/security.md) here. We considered running a second level of sanitization over all rendered Markdown using a library such as `dompurify` but believe that is unnecessary as `markdown-it`'s sanitization appears to be adequate. `graphiql@1.4.7` does update to the latest version of `markdown-it` (v12, from v10) so that any security fixes in v11 and v12 will take effect. ### 1.3.1 CDN bundle implementations may be automatically patched Note that if your implementation is depending on a CDN version of `graphiql`, and is pointed to the `latest` tag (usually the default for most cdns if no version is specified) then this issue is already mitigated, in case you were vulnerable to it before. ### 1.4. Workarounds for Older Versions If you cannot use `graphiql@1.4.7` or later - Always use a static URL to a trusted server that is serving a trusted GraphQL schema. - If you have a custom implementation that allows using user-provided schema URLs via a query parameter, database value, etc, you must either disable this customization, or only allow trusted URLs. ### 1.5. How to Re-create the Exploit You can see an example on [codesandbox](https://codesandbox.io/s/graphiql-xss-exploit-gr22f?file=/src/App.js). These are both fixed to the last `graphiql` release `1.4.6` which is the last vulnerable release; however it would work with any previous release of `graphiql`. Both of these examples are meant to demonstrate the phishing attack surface, so they are customized to accept a `url` parameter. To demonstrate the phishing attack, add `?url=https://graphql-xss-schema.netlify.app/graphql` to the in-codesandbox browser. Erase the contents of the given query and type `{u`. You will see an alert window open, showing that attacker-controlled code was executed. Note that when React is in development mode, a validation exception is thrown visibly; however that exception is usually buried in the browser console in a production build of `graphiql`. This validation exception comes from `getDiagnostics`, which invokes `graphql` `validate()` which in turn will `assertValidSchema()`, as `apollo-server-core` does on executing each operation. This validation does not prevent the exploit from being successful. Note that something like the `url` parameter is not required for the attack to happen if `graphiql`'s `fetcher` is configured in a different way to communicate with a compromised GraphQL server. ### 1.6. Credit This vulnerability was discovered by [@Ry0taK](https://github.com/Ry0taK), thank you! :1st_place_medal: Others who contributed: - [@imolorhe](https://github.com/imolorhe) - [@glasser](https://github.com/glasser) - [@divyenduz](https://github.com/divyenduz) - [@dotansimha](https://github.com/dotansimha) - [@acao](https://github.com/acao) - [@benjie](https://github.com/benjie) and many others who provided morale support ### 1.7. References **The vulnerability has always been present** [In the first commit](https://github.com/graphql/graphiql/commit/b9dec272d89d9c590727fd10d62e4a47e0317fc7#diff-855b77f6310b7e4fb1bcac779cd945092ed49fd759f4684ea391b45101166437R87) [And later moved to onHasCompletion.js in 2016](https://github.com/graphql/graphiql/commit/6701b0b626e43800e32413590a295e5c1e3d5419#diff-d45eb76aebcffd27d3a123214487116fa95e0b5a11d70a94a0ce3033ce09f879R110) (now `.ts` after the typescript migration) ### 1.8. For more information If you have any questions or comments about this advisory: - Open an issue in [graphiql repo](https://github.com/graphql/graphiql/new/issues) ## 2. More Details on the Vulnerability This section provides more details in addition to the advisory. An installation of the GraphiQL web app is vulnerable if two conditions are met: - The web app trusts information from its corresponding GraphQL server by interpolating information such as GraphQL type names directly into HTML instead of appropriately escaping or sanitizing the information. - The victim can load the web app in a way where it speaks to a GraphQL server controlled by the attacker. All versions of `graphiql` prior to 1.4.7 inappropriately trust type names provided by the GraphQL server. They additionally rely on XSS filtering in the `markdown-it` package to try to protect themselves from XSS attacks in GraphQL descriptions and deprecation reasons. By default, `graphiql` does _not_ allow the attacker to control what GraphQL server it speaks to. Therefore, many installations of `graphiql` are not affected by this advisory. Installations are only affected if the `fetcher` argument provided to GraphiQL allows arbitrary customization of the GraphQL endpoint (eg, reading a GraphQL URL from an URL parameter), or if the attacker has another way of affecting the introspection schema returned by the GraphQL server. (Note that `graphql-playground`, a project which started as a fork of `graphiql`, does this sort of URL parsing by default, so `graphql-playground` installations _are_ affected by a corresponding vulnerability in their default configuration.) One example of "another way of affecting the introspection schema" would be if you served `graphiql` as part of a PAAS platform that allows users to define their own GraphQL schemas. In this case, even though the `graphiql` installation might be hard-wired to a single GraphQL endpoint, the attacker has control over that GraphQL endpoint and could use it to inject scripts into `graphiql`. In this case, your `graphiql` installation could be vulnerable if it responds to introspection requests without first validating its schema. GraphQL servers can prevent this by refusing to execute operations (including introspection operations) on invalid schemas; any server built with `graphql-js` properly validates its schema prior to execution. ## 3. Compromised introspection Schema Example You can view the code for the exploited schema [on codesandbox](https://codesandbox.io/s/graphql-xss-compromised-schema-3wdq7?file=/src/bad-schema.js) or [in the repository](../../packages/graphiql/test/bad-schema.js) As you can see, the introspection schema must contain items with a compromised `name` value. this could be fields, input object names, enum names, variable names, etc any graphql [NamedType](https://github.com/graphql/graphql-spec/blob/main/spec/Section%202%20--%20Language.md#type-references) in the schema with it's name rendered in the autocomplete list. ```json { "kind": "OBJECT", "name": "<img src=x onerror=alert(document.domain)>", "description": null, "fields": [ { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null } ``` ================================================ FILE: examples/cm6-graphql-legacy-parcel/.gitignore ================================================ .cache/ ================================================ FILE: examples/cm6-graphql-legacy-parcel/README.md ================================================ ## Codemirror 6 Parcel Example This example demonstrates how to transpile your own custom ES6 Codemirror 6 GraphQL implementation with parcel bundler. ### Setup 1. `yarn` and `yarn start` from this folder to start parcel dev mode. 1. `yarn build` to find production ready files. ================================================ FILE: examples/cm6-graphql-legacy-parcel/package.json ================================================ { "name": "example-cm6-graphql-legacy-parcel", "version": "0.0.0", "license": "MIT", "description": "GraphiQL Parcel Example", "main": "index.js", "private": true, "scripts": { "start": "parcel src/index.html -p 8080", "build": "parcel build src/index.html --public-url /" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "dependencies": { "@codemirror/basic-setup": "^0.20.0", "@codemirror/language": "^0.20.0", "codemirror-graphql": "^2.0.2", "graphql": "^16.9.0" }, "devDependencies": { "parcel-bundler": "^1.12.4", "worker-loader": "^2.0.0", "typescript": "^4.6.3" } } ================================================ FILE: examples/cm6-graphql-legacy-parcel/src/index.html ================================================ <!doctype html> <html lang="en"> <head> <style> body { padding: 0; margin: 0; min-height: 100vh; } #root { height: 100vh; } </style> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>CM6 GraphQL Editor Example
================================================ FILE: examples/cm6-graphql-legacy-parcel/src/index.ts ================================================ import { EditorState, EditorView, basicSetup } from '@codemirror/basic-setup'; import { StreamLanguage } from '@codemirror/language'; import { graphql } from 'codemirror-graphql/cm6-legacy/mode'; import query from './sample-query'; const state = EditorState.create({ doc: query, extensions: [basicSetup, StreamLanguage.define(graphql)], }); new EditorView({ state, parent: document.querySelector('#editor')!, }); // Hot Module Replacement if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/cm6-graphql-legacy-parcel/src/sample-query.ts ================================================ const query = /* GraphQL */ ` # Copyright (c) 2021 GraphQL Contributors # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. An additional grant # of patent rights can be found in the PATENTS file in the same directory. query queryName($foo: TestInput, $site: TestEnum = RED) { testAlias: hasArgs(string: "testString") ... on Test { hasArgs( listEnum: [RED, GREEN, BLUE] int: 1 listFloat: [1.23, 1.3e-1, -1.35384e+3] boolean: true id: 123 object: $foo enum: $site ) } test @include(if: true) { union { __typename } } ...frag ... @skip(if: false) { id } ... { id } } mutation mutationName { setString(value: "newString") } subscription subscriptionName { subscribeToTest(id: "anId") { ... on Test { id } } } fragment frag on Test { test @include(if: true) { union { __typename } } } `; export default query; ================================================ FILE: examples/cm6-graphql-legacy-parcel/tsconfig.json ================================================ { "compilerOptions": { "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "module": "esnext", "sourceMap": true, "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react" }, "include": ["src"] } ================================================ FILE: examples/cm6-graphql-parcel/.gitignore ================================================ .cache/ .parcel-cache/ ================================================ FILE: examples/cm6-graphql-parcel/README.md ================================================ ## Codemirror 6 Parcel Example This example demonstrates how to transpile your own custom ES6 Codemirror 6 GraphQL implementation with parcel bundler. ### Setup 1. `yarn` and `yarn start` from this folder to start parcel dev mode. 1. `yarn build` to find production ready files. ================================================ FILE: examples/cm6-graphql-parcel/package.json ================================================ { "name": "example-cm6-graphql-parcel", "version": "0.0.0", "license": "MIT", "description": "GraphiQL Parcel Example", "main": "index.js", "private": true, "scripts": { "start": "parcel src/index.html -p 8080", "build": "parcel build src/index.html --public-url /", "build-demo": "yarn build && mkdirp ../../packages/graphiql/cm6 && cp -r dist ../../packages/graphiql/cm6/" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "dependencies": { "@codemirror/autocomplete": "6.0.0", "@codemirror/commands": "6.0.0", "@codemirror/language": "6.0.0", "@codemirror/state": "6.1.0", "@codemirror/theme-one-dark": "6.0.0", "@codemirror/view": "6.1.2", "cm6-graphql": "0.0.1", "graphql": "^16.9.0" }, "devDependencies": { "parcel": "^2.6.2", "worker-loader": "^2.0.0", "typescript": "^4.6.3" }, "resolutions": { "**/@codemirror/autocomplete": "6.0.0", "**/@codemirror/commands": "6.0.0", "**/@codemirror/view": "6.1.2", "**/@codemirror/state": "6.1.0", "**/@codemirror/language": "6.0.0" } } ================================================ FILE: examples/cm6-graphql-parcel/src/index.html ================================================ Code Mirror 6 GraphQL Editor Example
================================================ FILE: examples/cm6-graphql-parcel/src/index.ts ================================================ import { EditorState } from '@codemirror/state'; import { EditorView, lineNumbers } from '@codemirror/view'; import { history } from '@codemirror/commands'; import { autocompletion, closeBrackets } from '@codemirror/autocomplete'; import { bracketMatching, syntaxHighlighting } from '@codemirror/language'; import { oneDarkHighlightStyle, oneDark } from '@codemirror/theme-one-dark'; import { graphql } from 'cm6-graphql'; import query from './sample-query'; import { TestSchema } from './testSchema'; const state = EditorState.create({ doc: query, extensions: [ bracketMatching(), closeBrackets(), history(), autocompletion(), lineNumbers(), oneDark, syntaxHighlighting(oneDarkHighlightStyle), graphql(TestSchema, { onShowInDocs(field, type, parentType) { alert( `Showing in docs.: Field: ${field}, Type: ${type}, ParentType: ${parentType}`, ); }, onFillAllFields(view, schema, _query, cursor, token) { alert(`Filling all fields. Token: ${token}`); }, }), ], }); new EditorView({ state, parent: document.querySelector('#editor')!, }); // Hot Module Replacement if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/cm6-graphql-parcel/src/sample-query.ts ================================================ const query = /* GraphQL */ ` # Copyright (c) 2021 GraphQL Contributors # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. An additional grant # of patent rights can be found in the PATENTS file in the same directory. query queryName($foo: TestInput, $site: TestEnum = RED) { testAlias: hasArgs(string: "testString") ... on Test { hasArgs( listEnum: [RED, GREEN, BLUE] int: 1 listFloat: [1.23, 1.3e-1, -1.35384e+3] boolean: true id: 123 object: $foo enum: $site ) } test @include(if: true) { union { __typename } } ...frag ... @skip(if: false) { id } ... { id } } mutation mutationName { setString(value: "newString") } subscription subscriptionName { subscribeToTest(id: "anId") { ... on Test { id } } } fragment frag on Test { test @include(if: true) { union { __typename } } } `; export default query; ================================================ FILE: examples/cm6-graphql-parcel/src/testSchema.ts ================================================ /* istanbul ignore file */ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import { DirectiveLocation, GraphQLBoolean, GraphQLDeprecatedDirective, GraphQLDirective, GraphQLEnumType, GraphQLFloat, GraphQLID, GraphQLIncludeDirective, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLSkipDirective, GraphQLString, GraphQLUnionType, } from 'graphql'; // Test Schema export const TestEnum = new GraphQLEnumType({ name: 'TestEnum', values: { RED: {}, GREEN: {}, BLUE: {}, }, }); export const TestInputObject: GraphQLInputObjectType = new GraphQLInputObjectType({ name: 'TestInput', fields: () => ({ string: { type: GraphQLString }, int: { type: GraphQLInt }, float: { type: GraphQLFloat }, boolean: { type: GraphQLBoolean }, id: { type: GraphQLID }, enum: { type: TestEnum }, object: { type: TestInputObject }, // List listString: { type: new GraphQLList(GraphQLString) }, listInt: { type: new GraphQLList(GraphQLInt) }, listFloat: { type: new GraphQLList(GraphQLFloat) }, listBoolean: { type: new GraphQLList(GraphQLBoolean) }, listID: { type: new GraphQLList(GraphQLID) }, listEnum: { type: new GraphQLList(TestEnum) }, listObject: { type: new GraphQLList(TestInputObject) }, }), }); const TestInterface: GraphQLInterfaceType = new GraphQLInterfaceType({ name: 'TestInterface', resolveType: () => UnionFirst, fields: { scalar: { type: GraphQLString, resolve: () => ({}), }, }, }); const AnotherTestInterface: GraphQLInterfaceType = new GraphQLInterfaceType({ name: 'AnotherTestInterface', resolveType: () => UnionFirst, fields: { example: { type: GraphQLString, resolve: () => ({}), }, }, }); export const UnionFirst = new GraphQLObjectType({ name: 'First', interfaces: [TestInterface, AnotherTestInterface], fields: () => ({ scalar: { type: GraphQLString, resolve: () => ({}), }, first: { type: TestType, resolve: () => ({}), }, example: { type: GraphQLString, resolve: () => ({}), }, }), }); export const UnionSecond = new GraphQLObjectType({ name: 'Second', fields: () => ({ second: { type: TestType, resolve: () => ({}), }, }), }); export const TestUnion = new GraphQLUnionType({ name: 'TestUnion', types: [UnionFirst, UnionSecond], resolveType() { return UnionFirst; }, }); export const TestType: GraphQLObjectType = new GraphQLObjectType({ name: 'Test', fields: () => ({ test: { type: TestType, resolve: () => ({}), }, deprecatedTest: { type: TestType, deprecationReason: 'Use test instead.', resolve: () => ({}), }, union: { type: TestUnion, resolve: () => ({}), }, first: { type: UnionFirst, resolve: () => ({}), }, id: { type: GraphQLInt, resolve: () => ({}), }, isTest: { type: GraphQLBoolean, resolve() { return true; }, }, hasArgs: { type: GraphQLString, resolve(_value, args) { return JSON.stringify(args); }, args: { string: { type: GraphQLString }, int: { type: GraphQLInt }, float: { type: GraphQLFloat }, boolean: { type: GraphQLBoolean }, id: { type: GraphQLID }, enum: { type: TestEnum }, object: { type: TestInputObject }, // List listString: { type: new GraphQLList(GraphQLString) }, listInt: { type: new GraphQLList(GraphQLInt) }, listFloat: { type: new GraphQLList(GraphQLFloat) }, listBoolean: { type: new GraphQLList(GraphQLBoolean) }, listID: { type: new GraphQLList(GraphQLID) }, listEnum: { type: new GraphQLList(TestEnum) }, listObject: { type: new GraphQLList(TestInputObject) }, }, }, }), }); const TestMutationType = new GraphQLObjectType({ name: 'MutationType', description: 'This is a simple mutation type', fields: { setString: { type: GraphQLString, description: 'Set the string field', args: { value: { type: GraphQLString }, }, }, }, }); const TestSubscriptionType = new GraphQLObjectType({ name: 'SubscriptionType', description: 'This is a simple subscription type', fields: { subscribeToTest: { type: TestType, description: 'Subscribe to the test type', args: { id: { type: GraphQLString }, }, }, }, }); const OnArgDirective = new GraphQLDirective({ name: 'onArg', locations: [DirectiveLocation.ARGUMENT_DEFINITION], }); const OnAllDefsDirective = new GraphQLDirective({ name: 'onAllDefs', locations: [ DirectiveLocation.SCHEMA, DirectiveLocation.SCALAR, DirectiveLocation.OBJECT, DirectiveLocation.FIELD_DEFINITION, DirectiveLocation.INTERFACE, DirectiveLocation.UNION, DirectiveLocation.ENUM, DirectiveLocation.ENUM_VALUE, DirectiveLocation.INPUT_OBJECT, DirectiveLocation.ARGUMENT_DEFINITION, DirectiveLocation.INPUT_FIELD_DEFINITION, ], }); export const TestSchema = new GraphQLSchema({ query: TestType, mutation: TestMutationType, subscription: TestSubscriptionType, directives: [ GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, OnArgDirective, OnAllDefsDirective, ], }); ================================================ FILE: examples/cm6-graphql-parcel/tsconfig.json ================================================ { "compilerOptions": { "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "module": "esnext", "sourceMap": true, "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react" }, "include": ["src"] } ================================================ FILE: examples/graphiql-cdn/CHANGELOG.md ================================================ # Change Log All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. ## [0.0.8](https://github.com/graphql/graphiql/compare/example-graphiql-cdn@0.0.8-alpha.6...example-graphiql-cdn@0.0.8) (2020-06-11) **Note:** Version bump only for package example-graphiql-cdn ## [0.0.8-alpha.6](https://github.com/graphql/graphiql/compare/example-graphiql-cdn@0.0.8-alpha.5...example-graphiql-cdn@0.0.8-alpha.6) (2020-06-04) **Note:** Version bump only for package example-graphiql-cdn ## [0.0.8-alpha.5](https://github.com/graphql/graphiql/compare/example-graphiql-cdn@0.0.8-alpha.4...example-graphiql-cdn@0.0.8-alpha.5) (2020-04-10) **Note:** Version bump only for package example-graphiql-cdn ## [0.0.8-alpha.4](https://github.com/graphql/graphiql/compare/example-graphiql-cdn@0.0.8-alpha.3...example-graphiql-cdn@0.0.8-alpha.4) (2020-04-10) **Note:** Version bump only for package example-graphiql-cdn ## [0.0.8-alpha.3](https://github.com/graphql/graphiql/compare/example-graphiql-cdn@0.0.8-alpha.2...example-graphiql-cdn@0.0.8-alpha.3) (2020-03-20) **Note:** Version bump only for package example-graphiql-cdn ## [0.0.8-alpha.2](https://github.com/graphql/graphiql/compare/example-graphiql-cdn@0.0.8-alpha.0...example-graphiql-cdn@0.0.8-alpha.2) (2020-03-20) **Note:** Version bump only for package example-graphiql-cdn **Note:** Version bump only for package example-graphiql-cdn ## 0.0.8-alpha.1 (2020-01-18) ## [0.0.7](https://github.com/graphql/graphiql/compare/graphiql-example-cdn@0.0.6...graphiql-example-cdn@0.0.7) (2019-12-03) **Note:** Version bump only for package graphiql-example-cdn ## [0.0.6](https://github.com/graphql/graphiql/compare/graphiql-example-cdn@0.0.5...graphiql-example-cdn@0.0.6) (2019-11-26) **Note:** Version bump only for package graphiql-example-cdn ## [0.0.5](https://github.com/graphql/graphiql/compare/graphiql-example-cdn@0.0.4...graphiql-example-cdn@0.0.5) (2019-10-19) **Note:** Version bump only for package graphiql-example-cdn ================================================ FILE: examples/graphiql-cdn/README.md ================================================ # GraphiQL CDN Example This is a simple example of using **GraphiQL** directly from a CDN, including the [GraphiQL Explorer plugin](../../packages/graphiql-plugin-explorer/README.md). It loads the latest GraphiQL version from [esm.sh](https://esm.sh), an ESM-based CDN that serves npm packages as ES modules. ## Setup No installation or build step is required — just open the `index.html` file in your browser: - macOS: ```sh open index.html ``` - Linux: ```sh firefox index.html # or chromium index.html ``` ================================================ FILE: examples/graphiql-cdn/index.html ================================================ GraphiQL 5 with React 19 and GraphiQL Explorer
Loading…
================================================ FILE: examples/graphiql-cdn/package.json ================================================ { "name": "example-graphiql-cdn", "version": "0.0.0", "private": true, "license": "MIT", "description": "An example using GraphiQL", "scripts": { "build-demo": "copy index.html ../../packages/graphiql/cdn/" } } ================================================ FILE: examples/graphiql-create-react-app/README.md ================================================ # GraphiQL `create-react-app` Example > [!WARNING] > > This example has been removed. You can find its last version [here](https://github.com/graphql/graphiql/tree/3b93d27f7568d93db5cd146157220b127eeea737/examples/graphiql-create-react-app). > We recommend using the [GraphiQL Vite](../graphiql-vite) or [GraphiQL Next.js](../graphiql-nextjs) examples instead. ================================================ FILE: examples/graphiql-nextjs/README.md ================================================ This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). ## Getting Started First, run the development server: ```bash npm run dev # or yarn dev # or pnpm dev # or bun dev ``` Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. ================================================ FILE: examples/graphiql-nextjs/next-env.d.ts ================================================ /// /// // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. ================================================ FILE: examples/graphiql-nextjs/next.config.ts ================================================ import type { NextConfig } from 'next'; const nextConfig: NextConfig = { /* config options here */ }; export default nextConfig; ================================================ FILE: examples/graphiql-nextjs/package.json ================================================ { "name": "example-graphiql-nextjs", "version": "0.0.0", "private": true, "scripts": { "types:check": "tsc --noEmit", "dev": "next", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { "graphiql": "^5.0.0-rc.0", "next": "15.4.0", "react": "^19.1.0", "react-dom": "^19.1.0" }, "devDependencies": { "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", "typescript": "^5" } } ================================================ FILE: examples/graphiql-nextjs/src/app/globals.css ================================================ body { margin: 0; } .graphiql-container { height: 100dvh !important; } ================================================ FILE: examples/graphiql-nextjs/src/app/graphiql.tsx ================================================ 'use client'; import type { FC } from 'react'; import { GraphiQL } from 'graphiql'; import 'graphiql/setup-workers/webpack'; import 'graphiql/style.css'; async function fetcher(graphQLParams: Record) { const response = await fetch('https://graphql.earthdata.nasa.gov/api', { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify(graphQLParams), }); return response.json(); } export const GraphiQLPage: FC = () => { return ; }; ================================================ FILE: examples/graphiql-nextjs/src/app/layout.tsx ================================================ import type { FC, ReactNode } from 'react'; import type { Metadata } from 'next'; import './globals.css'; export const metadata: Metadata = { description: 'Example of using GraphiQL with the Next.js App Router', // Empty object adds open graph and twitter meta-tags openGraph: {}, }; const RootLayout: FC> = ({ children }) => { return ( {children} ); }; export default RootLayout; ================================================ FILE: examples/graphiql-nextjs/src/app/page.ts ================================================ import type { Metadata } from 'next'; export { GraphiQLPage as default } from './graphiql'; export const metadata: Metadata = { title: 'GraphiQL Next.js Example', }; ================================================ FILE: examples/graphiql-nextjs/tsconfig.json ================================================ { "compilerOptions": { "target": "ES2017", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, "plugins": [ { "name": "next" } ] }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "exclude": ["node_modules"] } ================================================ FILE: examples/graphiql-parcel/README.md ================================================ # GraphiQL Parcel Example > [!WARNING] > > This example has been removed. You can find its last version [here](https://github.com/graphql/graphiql/tree/3b93d27f7568d93db5cd146157220b127eeea737/examples/graphiql-parcel). > We recommend using the [GraphiQL Vite](../graphiql-vite) or [GraphiQL Next.js](../graphiql-nextjs) examples instead. ================================================ FILE: examples/graphiql-vite/README.md ================================================ # GraphiQL Vite Example This example demonstrates how to use GraphiQL with Vite. ## Setup 1. `yarn dev` to start Vite dev server. 1. `yarn build` to build production ready transpiled files. Find the output in `dist` folder. ================================================ FILE: examples/graphiql-vite/index.html ================================================ GraphiQL Vite Example
Loading…
================================================ FILE: examples/graphiql-vite/package.json ================================================ { "name": "example-graphiql-vite", "version": "0.0.0", "private": true, "dependencies": { "graphiql": "^5.2.2", "graphql": "^16.11.0", "react": "^19.1.0", "react-dom": "^19.1.0" }, "devDependencies": { "@vitejs/plugin-react": "^4.4.1", "vite": "^6.3.4", "vite-plugin-monaco-editor": "^1.1.0" }, "scripts": { "dev": "vite", "build": "vite build", "start": "vite preview" } } ================================================ FILE: examples/graphiql-vite/src/App.jsx ================================================ import { GraphiQL } from 'graphiql'; import 'graphiql/style.css'; async function fetcher(graphQLParams) { const response = await fetch('https://graphql.earthdata.nasa.gov/api', { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify(graphQLParams), }); return response.json(); } function App() { return ; } export default App; ================================================ FILE: examples/graphiql-vite/src/index.jsx ================================================ import { createRoot } from 'react-dom/client'; import App from './App'; const root = createRoot(document.getElementById('graphiql')); root.render(); ================================================ FILE: examples/graphiql-vite/vite.config.mjs ================================================ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import $monacoEditorPlugin from 'vite-plugin-monaco-editor'; const monacoEditorPlugin = $monacoEditorPlugin.default ?? $monacoEditorPlugin; export default defineConfig({ plugins: [ react(), monacoEditorPlugin({ languageWorkers: ['editorWorkerService', 'json'], customWorkers: [ { label: 'graphql', entry: 'monaco-graphql/esm/graphql.worker.js', }, ], }), ], }); ================================================ FILE: examples/graphiql-vite-react-router/README.md ================================================ # Usage GraphiQL with Vite, React Router and `ssr: true` When using GraphiQL with [React Router’s SSR mode](https://reactrouter.com/api/framework-conventions/react-router.config.ts#ssr), you need to mark the GraphiQL component as a [client module](https://reactrouter.com/api/framework-conventions/client-modules) by adding `.client` to the file name. ```tsx // graphiql.client.tsx import { GraphiQL } from 'graphiql'; import { createGraphiQLFetcher } from '@graphiql/toolkit'; const fetcher = createGraphiQLFetcher({ url: 'https://my.backend/graphql' }); export const graphiql = ; ``` ```ts // route.ts import type { FC } from 'react'; import type { LinksFunction, MetaFunction } from 'react-router'; import graphiqlStyles from 'graphiql/style.css?url'; import { graphiql } from './graphiql.client'; export const meta: MetaFunction = () => { return [{ title: 'API Explorer' }]; }; export const links: LinksFunction = () => { return [{ rel: 'stylesheet', href: graphiqlStyles }]; }; const Route: FC = () => { return graphiql; }; export default Route; ``` ## Setup 1. `yarn dev` to start Vite dev server. 1. `yarn build` to build production ready transpiled files. Find the output in `dist` folder. ================================================ FILE: examples/graphiql-vite-react-router/app/root.tsx ================================================ import type { FC } from 'react'; import { Links, Meta, Outlet, Scripts, ScrollRestoration } from 'react-router'; const Root: FC = () => { return ( ); }; export default Root; ================================================ FILE: examples/graphiql-vite-react-router/app/routes/_index/create-fetcher.ts ================================================ import type { GraphiQLProps } from 'graphiql'; export function createFetcher(apiUrl: string): GraphiQLProps['fetcher'] { return async function (graphQLParams, opts) { const response = await fetch(apiUrl, { method: 'POST', headers: { ...opts?.headers, 'Content-Type': 'application/json', }, body: JSON.stringify(graphQLParams), }); return response.json(); }; } ================================================ FILE: examples/graphiql-vite-react-router/app/routes/_index/globals.css ================================================ body { margin: 0; } .graphiql-container { height: 100dvh; } ================================================ FILE: examples/graphiql-vite-react-router/app/routes/_index/graphiql.client.tsx ================================================ import type { FC } from 'react'; import { GraphiQL } from 'graphiql'; import { ToolbarButton, useGraphiQL } from '@graphiql/react'; import { createFetcher } from './create-fetcher'; import 'graphiql/setup-workers/esm.sh'; export const graphiql = ( API Explorer {({ prettify, copy, merge }) => ( <> {prettify} {copy} {merge} {fetchError && (
There was an error fetching your schema:
{JSON.parse(fetchError).errors.map(({ message }) => message)}
)} {isIntrospecting ? (
Schema loading...
) : ( schema && !fetchError && (
Schema retrieved successfully
) )}
Previous Severs
    {previousUrls.map(prev => { return (
  • { storage.set(LAST_URL_KEY, prev); inputRef.current.value = prev; setError(null); setUrl(prev); setInputValue(prev); }} title={`Switch to ${prev}`} > {prev}
  • ); })}
); }; export function serverSelectPlugin({ url, setUrl }) { return { title: 'Select Server', icon: () => ( ), content() { return ; }, }; } ================================================ FILE: examples/graphiql-webpack/src/snippets.js ================================================ const removeQueryName = query => query.replace( /^[^{(]+([{(])/, (_match, openingCurlyBracketsOrParenthesis) => `query ${openingCurlyBracketsOrParenthesis}`, ); const getQuery = (arg, spaceCount) => { const { operationDataList } = arg; console.log(arg); const { query } = operationDataList[0]; const anonymousQuery = removeQueryName(query); return ( ' '.repeat(spaceCount) + anonymousQuery.replaceAll('\n', '\n' + ' '.repeat(spaceCount)) ); }; export const getSnippets = ({ serverUrl }) => { const exampleSnippetZero = { name: 'cURL', language: 'shell', codeMirrorMode: 'shell', options: [], generate: arg => `curl -g \ -X POST \ -H "Content-Type: application/json" \ -d '{"query": "${arg.operationDataList[0].query.replaceAll('\n', ' ')}"}' \ ${serverUrl}`, }; const exampleSnippetOne = { name: 'Example One', language: 'JavaScript', codeMirrorMode: 'jsx', options: [], generate: arg => `export const query = graphql\` ${getQuery(arg, 2)} \` `, }; const exampleSnippetTwo = { name: 'Example Two', language: 'JavaScript', codeMirrorMode: 'jsx', options: [], generate: arg => `import { graphql } from 'graphql' export const query = graphql\` ${getQuery(arg, 2)} \` `, }; return [exampleSnippetZero, exampleSnippetOne, exampleSnippetTwo]; }; ================================================ FILE: examples/graphiql-webpack/webpack.config.js ================================================ const { GenerateSW } = require('workbox-webpack-plugin'); const { WebpackManifestPlugin } = require('webpack-manifest-plugin'); const CopyPlugin = require('copy-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const path = require('node:path'); const isDev = process.env.NODE_ENV === 'development'; const isHMR = process.env.WEBPACK_SERVE; const prodPlugins = []; if (!isHMR) { prodPlugins.push( new GenerateSW({ maximumFileSizeToCacheInBytes: 1024 * 1024 * 20, }), ); } /** * @type {import('webpack').Configuration} */ module.exports = { entry: isDev ? [ 'react-hot-loader/patch', // activate HMR for React 'webpack-dev-server/client?http://localhost:8080', // bundle the client for webpack-dev-server and connect to the provided endpoint 'webpack/hot/only-dev-server', // bundle the client for hot reloading, `only-` means to only hot reload for successful updates './src/index.jsx', // the entry point of our app ] : './src/index.jsx', mode: process.env.NODE_ENV ?? 'development', devtool: 'inline-source-map', performance: { hints: false, }, output: { filename: '[name].[contenthash].js', clean: true, }, module: { rules: [ { test: /\.html$/, use: ['file?name=[name].[ext]'], }, // for graphql module, which uses mjs still { type: 'javascript/auto', test: /\.mjs$/, use: [], include: /node_modules/, }, { test: /\.(js|jsx)$/, use: [ { loader: 'babel-loader', options: { presets: [ ['@babel/preset-env', { modules: false }], '@babel/preset-react', ], }, }, ], }, { test: /\.css$/, use: ['style-loader', 'css-loader'], }, { test: /\.svg$/, use: [{ loader: 'svg-inline-loader' }], }, { test: /\.(woff|woff2|eot|ttf|otf)$/, use: ['file-loader'], }, ], }, resolve: { extensions: ['.js', '.json', '.jsx', '.css', '.mjs'], }, plugins: [ ...prodPlugins, new CopyPlugin({ patterns: [{ from: 'public' }], }), new HtmlWebpackPlugin({ template: path.join(__dirname, '/index.html.ejs'), }), new WebpackManifestPlugin({ seed: { name: 'GraphiQL PWA', icons: [ { src: 'logo.svg', sizes: '48x48 72x72 96x96 128x128 256x256 512x512', type: 'image/svg+xml', purpose: 'any', }, ], background_color: '#ffffff', theme_color: '#D60590', start_url: './index.html', display: 'standalone', display_override: ['fullscreen', 'minimal-ui'], 'logo.svg': 'auto/logo.svg', }, }), ], devServer: { hot: true, // bypass simple localhost CORS restrictions by setting // these to 127.0.0.1 in /etc/hosts allowedHosts: ['local.test.com', 'graphiql.com'], }, }; ================================================ FILE: examples/monaco-graphql-nextjs/README.md ================================================ # Monaco GraphQL Next.js Example ## Getting Started This is a working example of `monaco-editor` and `monaco-graphql` using Next.js 15 with Turbopack. It shows how to use the latest monaco-editor with next.js and a custom webworker, without using `@monaco/react` or `monaco-editor-react`'s approach of cdn (AMD) bundles. These approaches avoid using ESM `monaco-editor` or web workers, which prevents introducing custom web workers like with `monaco-graphql`. For lazy loading, we use `next/dynamic` with `{ssr: false}`, but any similar client-side-only loading (with or without dynamic import) should be fine. For more information on loading `monaco-editor` in esm contexts, you can [read their docs](https://github.com/microsoft/monaco-editor/blob/main/docs/integrate-esm.md) This work was sponsored by [Grafbase](https://grafbase.com)! ## Setup 1. In monorepo root directory run `yarn` and `yarn build`. 1. In this directory run `yarn dev`. ================================================ FILE: examples/monaco-graphql-nextjs/next-env.d.ts ================================================ /// /// // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. ================================================ FILE: examples/monaco-graphql-nextjs/next.config.ts ================================================ import type { NextConfig } from 'next'; const nextConfig: NextConfig = {}; export default nextConfig; ================================================ FILE: examples/monaco-graphql-nextjs/package.json ================================================ { "name": "example-monaco-graphql-nextjs", "version": "0.0.0", "private": true, "type": "module", "scripts": { "types:check": "tsc --noEmit", "dev": "next", "build": "next build", "start": "next start" }, "dependencies": { "@graphiql/toolkit": "^0.11.3", "graphql": "^16.9.0", "jsonc-parser": "^3.2.0", "monaco-editor": "^0.52.2", "monaco-graphql": "^1.7.3", "next": "15.4.0", "react": "^19.1.0", "react-dom": "^19.1.0" }, "devDependencies": { "@types/node": "^16.18.4", "@types/react": "^19.1.2", "typescript": "^4.6.3" } } ================================================ FILE: examples/monaco-graphql-nextjs/src/app/env.d.ts ================================================ declare namespace globalThis { import type { Environment } from 'monaco-editor/esm/monaco-editor'; var MonacoEnvironment: Environment; } ================================================ FILE: examples/monaco-graphql-nextjs/src/app/globals.css ================================================ body { margin: 0; height: 100vh; } #root { display: flex; height: inherit; } .pane { width: 50%; } .left-editor { height: 50%; } ================================================ FILE: examples/monaco-graphql-nextjs/src/app/layout.tsx ================================================ import type { FC, ReactNode } from 'react'; import type { Metadata } from 'next'; import './globals.css'; export const metadata: Metadata = { title: 'Monaco Next.js Example', }; const RootLayout: FC> = ({ children }) => { return ( {children} ); }; export default RootLayout; ================================================ FILE: examples/monaco-graphql-nextjs/src/app/page.tsx ================================================ 'use client'; import type { FC } from 'react'; import dynamic from 'next/dynamic'; // dynamically import our GraphiQL component const DynamicEditor = dynamic(() => import('../editor'), { ssr: false }); /** * Setup Monaco Editor workers for Webpack/Turbopack projects like Next.js. */ globalThis.MonacoEnvironment = { getWorker(_workerId: string, label: string) { console.info('setup-workers/webpack', { label }); switch (label) { case 'json': return new Worker( new URL( 'monaco-editor/esm/vs/language/json/json.worker.js', import.meta.url, ), ); case 'graphql': return new Worker( new URL('monaco-graphql/esm/graphql.worker.js', import.meta.url), ); case 'typescript': return new Worker( new URL( 'monaco-editor/esm/vs/language/typescript/ts.worker.js', import.meta.url, ), ); } return new Worker( new URL('monaco-editor/esm/vs/editor/editor.worker.js', import.meta.url), ); }, }; const Page: FC = () => { return (
); }; export default Page; ================================================ FILE: examples/monaco-graphql-nextjs/src/constants.ts ================================================ import { editor, Uri, languages } from 'monaco-graphql/esm/monaco-editor'; import { initializeMode } from 'monaco-graphql/esm/initializeMode'; import { parse, print } from 'graphql'; type ModelType = 'operations' | 'variables' | 'response' | 'ts'; export const GRAPHQL_URL = 'https://countries.trevorblades.com'; export const DEFAULT_EDITOR_OPTIONS: editor.IStandaloneEditorConstructionOptions = { theme: 'vs-dark', minimap: { enabled: false, }, }; export const STORAGE_KEY = { operations: 'operations', variables: 'variables', }; // allow a typo to test validation on schema load /* cSpell:disable */ const operations = localStorage.getItem(STORAGE_KEY.operations) ?? `# CMD/CTRL + Return/Enter will execute the operation, # same in the variables editor below # also available via context menu & F1 command palette query Example($code: ID!, $filter: LanguageFilterInput!) { country(code: $code) { awsRegion native phone emoj } languages(filter: $filter) { name } }`; /* cSpell:enable */ let prettyOp = ''; export const makeOpTemplate = (op: string) => { try { prettyOp = print(parse(op)); return `const graphql = (arg: TemplateStringsArray): string => arg[0] const op = graphql\`\n${prettyOp}\n\``; } catch { return prettyOp; } }; export const DEFAULT_VALUE: Record = { operations, variables: localStorage.getItem(STORAGE_KEY.variables) ?? `{ "code": "UA" }`, response: '', ts: makeOpTemplate(operations), }; export const OPERATIONS_URI = Uri.file('operations.graphql'); export const VARIABLES_URI = Uri.file('variables.json'); export const RESPONSE_URI = Uri.file('response.json'); export const TS_URI = Uri.file('typescript.ts'); // set these early on so that initial variables with comments don't flash an error languages.json.jsonDefaults.setDiagnosticsOptions({ allowComments: true, trailingCommas: 'ignore', }); export const MONACO_GRAPHQL_API = initializeMode({ diagnosticSettings: { validateVariablesJSON: { [OPERATIONS_URI.toString()]: [VARIABLES_URI.toString()], }, jsonDiagnosticSettings: { validate: true, schemaValidation: 'error', // set these again, because we are entirely re-setting them here allowComments: true, trailingCommas: 'ignore', }, }, }); export function getOrCreateModel({ uri, value }: { uri: Uri; value: string }) { const { path } = uri; let language = path.split('.').at(-1)!; if (language === 'ts') { language = 'typescript'; } return editor.getModel(uri) ?? editor.createModel(value, language, uri); } ================================================ FILE: examples/monaco-graphql-nextjs/src/editor.tsx ================================================ import { ReactElement, useEffect, useRef, useState } from 'react'; import { getIntrospectionQuery, IntrospectionQuery } from 'graphql'; import { editor, KeyMod, KeyCode } from 'monaco-graphql/esm/monaco-editor'; // to get typescript mode working import 'monaco-editor/esm/vs/basic-languages/typescript/typescript.contribution'; import 'monaco-editor/esm/vs/editor/contrib/peekView/browser/peekView'; import 'monaco-editor/esm/vs/editor/contrib/parameterHints/browser/parameterHints'; import 'monaco-editor/esm/vs/language/typescript/monaco.contribution'; import { createGraphiQLFetcher } from '@graphiql/toolkit'; import * as JSONC from 'jsonc-parser'; import { DEFAULT_EDITOR_OPTIONS, MONACO_GRAPHQL_API, STORAGE_KEY, GRAPHQL_URL, OPERATIONS_URI, VARIABLES_URI, RESPONSE_URI, TS_URI, DEFAULT_VALUE, makeOpTemplate, getOrCreateModel, } from './constants'; const fetcher = createGraphiQLFetcher({ url: GRAPHQL_URL }); async function getSchema(): Promise { const data = await fetcher({ query: getIntrospectionQuery(), operationName: 'IntrospectionQuery', }); const introspectionJSON = 'data' in data && (data.data as unknown as IntrospectionQuery); if (!introspectionJSON) { throw new Error( 'this demo does not support subscriptions or http multipart yet', ); } return introspectionJSON; } function debounce any>(duration: number, fn: F) { let timeout = 0; return (...args: Parameters) => { if (timeout) { clearTimeout(timeout); } timeout = window.setTimeout(() => { timeout = 0; fn(args); }, duration); }; } export default function Editor(): ReactElement { const operationsRef = useRef(null!); const variablesRef = useRef(null!); const responseRef = useRef(null!); const tsRef = useRef(null!); const [schema, setSchema] = useState(); const [loading, setLoading] = useState(false); /** * Create the models & editors */ useEffect(() => { const MODEL = { operations: getOrCreateModel({ uri: OPERATIONS_URI, value: DEFAULT_VALUE.operations, }), variables: getOrCreateModel({ uri: VARIABLES_URI, value: DEFAULT_VALUE.variables, }), response: getOrCreateModel({ uri: RESPONSE_URI, value: DEFAULT_VALUE.response, }), ts: getOrCreateModel({ uri: TS_URI, value: DEFAULT_VALUE.ts, }), }; const EDITOR = { operations: editor.create(operationsRef.current, { model: MODEL.operations, ...DEFAULT_EDITOR_OPTIONS, }), variables: editor.create(variablesRef.current, { model: MODEL.variables, ...DEFAULT_EDITOR_OPTIONS, }), response: editor.create(responseRef.current, { model: MODEL.response, ...DEFAULT_EDITOR_OPTIONS, readOnly: true, smoothScrolling: true, }), ts: editor.create(tsRef.current, { model: MODEL.ts, ...DEFAULT_EDITOR_OPTIONS, smoothScrolling: true, 'semanticHighlighting.enabled': true, language: 'typescript', }), }; const queryAction: editor.IActionDescriptor = { id: 'graphql-run', label: 'Run Operation', contextMenuOrder: 0, contextMenuGroupId: 'graphql', // eslint-disable-next-line no-bitwise keybindings: [KeyMod.CtrlCmd | KeyCode.Enter], async run() { const result = await fetcher({ query: MODEL.operations.getValue(), variables: JSONC.parse(MODEL.variables.getValue()), }); // TODO: this demo only supports a single iteration for http GET/POST, // no multipart or subscriptions yet. // @ts-expect-error const data = await result.next(); MODEL.response.setValue(JSON.stringify(data.value, null, 2)); }, }; const disposables = [ EDITOR.operations.addAction(queryAction), MODEL.operations.onDidChangeContent( debounce(300, () => { localStorage.setItem( STORAGE_KEY.operations, MODEL.operations.getValue(), ); }), ), MODEL.operations.onDidChangeContent(() => { const value = MODEL.operations.getValue(); MODEL.ts.setValue(makeOpTemplate(value)); }), EDITOR.variables.addAction(queryAction), MODEL.variables.onDidChangeContent( debounce(300, () => { localStorage.setItem( STORAGE_KEY.variables, MODEL.variables.getValue(), ); }), ), ...Object.values(EDITOR), ...Object.values(MODEL), ]; // Clean‑up on unmount return () => { for (const disposable of disposables) { disposable.dispose(); // remove the listener } }; }, []); /** * Handle the initial schema load */ useEffect(() => { if (schema || loading) { return; } setLoading(true); void getSchema().then(async introspectionJSON => { MONACO_GRAPHQL_API.setSchemaConfig([ { introspectionJSON, uri: 'my-schema.graphql' }, ]); setSchema(introspectionJSON); setLoading(false); }); }, [schema, loading]); return ( <>
); } ================================================ FILE: examples/monaco-graphql-nextjs/tsconfig.json ================================================ { "compilerOptions": { "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, "forceConsistentCasingInFileNames": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, "baseUrl": ".", "paths": { "@/*": ["./src/*"] }, "plugins": [ { "name": "next" } ] }, "include": ["**/*.ts", "**/*.tsx", "next-env.d.ts", ".next/types/**/*.ts"], "exclude": ["node_modules"] } ================================================ FILE: examples/monaco-graphql-react-vite/README.md ================================================ # Monaco-GraphQL React Vite Example ## Getting Started This is an extremely naive & minimalist implementation of `monaco-graphql` with `react` using `vite` as a bundler. This workspace could be used to help us prototype components & hooks for `@graphiql/react` [Here is a StackBlitz demo of this example](https://stackblitz.com/edit/monaco-graphql-react-vite?file=src/App.tsx) ## Setup 1. In monorepo root directory run `yarn` and `yarn build`. 1. In this directory run `yarn dev`. ================================================ FILE: examples/monaco-graphql-react-vite/index.html ================================================ Monaco React Vite Example
Loading…
================================================ FILE: examples/monaco-graphql-react-vite/package.json ================================================ { "name": "example-monaco-graphql-react-vite", "private": true, "version": "0.0.0", "dependencies": { "@graphiql/toolkit": "^0.11.3", "graphql": "^16.11.0", "graphql-language-service": "^5.5.0", "jsonc-parser": "^3.2.0", "monaco-editor": "^0.52.2", "monaco-graphql": "^1.7.3", "react": "^19.1.0", "react-dom": "^19.1.0" }, "devDependencies": { "@vitejs/plugin-react": "^4.4.1", "vite": "^6.3.4" }, "scripts": { "dev": "vite", "build": "vite build", "start": "vite preview" } } ================================================ FILE: examples/monaco-graphql-react-vite/src/env.d.ts ================================================ declare namespace globalThis { import type { Environment } from 'monaco-editor/esm/monaco-editor'; var MonacoEnvironment: Environment; } ================================================ FILE: examples/monaco-graphql-react-vite/src/index.tsx ================================================ /* eslint-disable import-x/default */ import { createRoot } from 'react-dom/client'; import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker.js?worker'; import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker.js?worker'; import TSWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker.js?worker'; import GraphQLWorker from 'monaco-graphql/esm/graphql.worker.js?worker'; import Editor from './editor'; import './globals.css'; /** * Setup Monaco Editor workers for Vite. * * Vite doesn’t support instantiating web workers directly from bare module imports like this: * ``` * new Worker(new URL('monaco-editor/esm/vs/language/json/json.worker.js', import.meta.url)) * ``` * Vite needs to know ahead of time that you are loading a web worker. */ globalThis.MonacoEnvironment = { getWorker(_workerId: string, label: string) { console.info('setup-workers/vite', { label }); switch (label) { case 'json': return new JsonWorker(); case 'graphql': return new GraphQLWorker(); case 'typescript': return new TSWorker(); } return new EditorWorker(); }, }; const root = createRoot(document.getElementById('root')!); root.render(); ================================================ FILE: examples/monaco-graphql-react-vite/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "lib": ["DOM", "DOM.Iterable", "ESNext"], "allowJs": false, "skipLibCheck": false, "esModuleInterop": false, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "module": "ESNext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx" }, "include": ["src"] } ================================================ FILE: examples/monaco-graphql-react-vite/vite.config.ts ================================================ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ build: { minify: false, rollupOptions: { output: { entryFileNames: '[name].js', chunkFileNames: 'assets/[name].js', assetFileNames: 'assets/[name].[ext]', }, }, }, plugins: [ react(), watchPackages(['monaco-graphql', 'graphql-language-service']), ], worker: { format: 'es', rollupOptions: { output: { entryFileNames: 'workers/[name].js', chunkFileNames: 'workers/[name].js', }, }, }, }); function watchPackages(packageNames: string[]) { let isWatching = false; return { name: 'vite-plugin-watch-packages', buildStart() { if (!isWatching) { for (const packageName of packageNames) { this.addWatchFile(require.resolve(packageName)); } isWatching = true; } }, }; } ================================================ FILE: examples/monaco-graphql-webpack/CHANGELOG.md ================================================ # Change Log ## 1.1.1 ### Patch Changes - Updated dependencies [[`e68cb8bc`](https://github.com/graphql/graphiql/commit/e68cb8bcaf9baddf6fca747abab871ecd1bc7a4c), [`f788e65a`](https://github.com/graphql/graphiql/commit/f788e65aff267ec873237034831d1fd936222a9b), [`bdc966cb`](https://github.com/graphql/graphiql/commit/bdc966cba6134a72ff7fe40f76543c77ba15d4a4), [`db2a0982`](https://github.com/graphql/graphiql/commit/db2a0982a17134f0069483ab283594eb64735b7d), [`8725d1b6`](https://github.com/graphql/graphiql/commit/8725d1b6b686139286cf05dec6a84d89942128ba)]: - graphql-language-service@5.1.2 - monaco-graphql@1.1.8 All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. ## [1.1.1-alpha.7](https://github.com/graphql/graphiql/compare/example-monaco-graphql-webpack@1.1.1-alpha.6...example-monaco-graphql-webpack@1.1.1-alpha.7) (2021-01-07) **Note:** Version bump only for package example-monaco-graphql-webpack ## [1.1.1-alpha.6](https://github.com/graphql/graphiql/compare/example-monaco-graphql-webpack@1.1.1-alpha.5...example-monaco-graphql-webpack@1.1.1-alpha.6) (2021-01-07) **Note:** Version bump only for package example-monaco-graphql-webpack ## [1.1.1-alpha.5](https://github.com/graphql/graphiql/compare/example-monaco-graphql-webpack@1.1.1-alpha.4...example-monaco-graphql-webpack@1.1.1-alpha.5) (2021-01-07) **Note:** Version bump only for package example-monaco-graphql-webpack ## [1.1.1-alpha.4](https://github.com/graphql/graphiql/compare/example-monaco-graphql-webpack@1.1.1-alpha.3...example-monaco-graphql-webpack@1.1.1-alpha.4) (2021-01-03) **Note:** Version bump only for package example-monaco-graphql-webpack ## [1.1.1-alpha.3](https://github.com/graphql/graphiql/compare/example-monaco-graphql-webpack@1.1.1-alpha.2...example-monaco-graphql-webpack@1.1.1-alpha.3) (2020-12-28) **Note:** Version bump only for package example-monaco-graphql-webpack ## [1.1.1-alpha.2](https://github.com/graphql/graphiql/compare/example-monaco-graphql-webpack@1.1.1-alpha.1...example-monaco-graphql-webpack@1.1.1-alpha.2) (2020-08-22) ### Bug Fixes - improve setSchema & schema loading, allow primitive schema ([#1648](https://github.com/graphql/graphiql/issues/1648)) ([975f29e](https://github.com/graphql/graphiql/commit/975f29ed6e21c7354c42ed778dfd1b52287f70c6)) ## [1.1.1-alpha.1](https://github.com/graphql/graphiql/compare/example-monaco-graphql-webpack@1.1.1-alpha.0...example-monaco-graphql-webpack@1.1.1-alpha.1) (2020-08-12) **Note:** Version bump only for package example-monaco-graphql-webpack ## [1.1.1-alpha.0](https://github.com/graphql/graphiql/compare/example-monaco-graphql-webpack@1.1.0...example-monaco-graphql-webpack@1.1.1-alpha.0) (2020-08-10) **Note:** Version bump only for package example-monaco-graphql-webpack # [1.1.0](https://github.com/graphql/graphiql/compare/example-monaco-graphql-webpack@1.0.0...example-monaco-graphql-webpack@1.1.0) (2020-08-06) ### Features - [RFC] GraphiQL rewrite for monaco editor, react context and redesign, i18n ([#1523](https://github.com/graphql/graphiql/issues/1523)) ([ad730cd](https://github.com/graphql/graphiql/commit/ad730cdc2e3cb7216d821a01725c60475989ee20)) # [1.0.0](https://github.com/graphql/graphiql/compare/example-monaco-graphql-webpack@1.0.0-alpha.8...example-monaco-graphql-webpack@1.0.0) (2020-06-11) ### Features - standalone monaco API ([#1575](https://github.com/graphql/graphiql/issues/1575)) ([954aa3d](https://github.com/graphql/graphiql/commit/954aa3d7159fd26bba9650824e0f668e417ca64f)) # [1.0.0-alpha.8](https://github.com/graphql/graphiql/compare/example-monaco-graphql-webpack@1.0.0-alpha.7...example-monaco-graphql-webpack@1.0.0-alpha.8) (2020-06-04) **Note:** Version bump only for package example-monaco-graphql-webpack # [1.0.0-alpha.7](https://github.com/graphql/graphiql/compare/example-monaco-graphql-webpack@1.0.0-alpha.6...example-monaco-graphql-webpack@1.0.0-alpha.7) (2020-06-04) **Note:** Version bump only for package example-monaco-graphql-webpack # [1.0.0-alpha.6](https://github.com/graphql/graphiql/compare/example-monaco-graphql-webpack@1.0.0-alpha.5...example-monaco-graphql-webpack@1.0.0-alpha.6) (2020-05-28) **Note:** Version bump only for package example-monaco-graphql-webpack # [1.0.0-alpha.5](https://github.com/graphql/graphiql/compare/example-monaco-graphql-webpack@1.0.0-alpha.4...example-monaco-graphql-webpack@1.0.0-alpha.5) (2020-05-19) **Note:** Version bump only for package example-monaco-graphql-webpack # 1.0.0-alpha.4 (2020-05-17) ### Features - Monaco Mode - Phase 2 - Mode & Worker ([#1459](https://github.com/graphql/graphiql/issues/1459)) ([bc95fb4](https://github.com/graphql/graphiql/commit/bc95fb46459a4437ff9471ff43c98e1c5c50f51e)) - monaco-graphql docs, api, improvements ([#1521](https://github.com/graphql/graphiql/issues/1521)) ([c79158c](https://github.com/graphql/graphiql/commit/c79158c72e976ab286e7ec3fded7f3e2d24e50d0)) ================================================ FILE: examples/monaco-graphql-webpack/README.md ================================================ A simple example of `monaco-graphql` using webpack 4 [live demo](https://monaco-graphql.netlify.com) of the monaco webpack example ### Setup `yarn` and `yarn start` from this folder to start webpack dev server ### JS only If you want to learn how to bundle `monaco-graphql` using webpack without typescript, these steps will help: 1. rename .ts files to .js 1. rename .ts to .js in webpack.config.js 1. remove fork ts checker plugin from webpack.config.js 1. remove typescript annotations from the renamed files ================================================ FILE: examples/monaco-graphql-webpack/babel.config.js ================================================ module.exports = { presets: [ require.resolve('@babel/preset-env'), require.resolve('@babel/preset-typescript'), require.resolve('@babel/preset-react'), ], plugins: [ require.resolve('@babel/plugin-proposal-class-properties'), require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'), require.resolve('@babel/plugin-transform-class-static-block'), ], }; ================================================ FILE: examples/monaco-graphql-webpack/package.json ================================================ { "name": "example-monaco-graphql-webpack", "version": "0.0.0", "private": true, "license": "MIT", "description": "A simple monaco example with webpack and typescript", "scripts": { "build": "cross-env NODE_ENV=production webpack-cli", "start": "cross-env NODE_ENV=development webpack-cli serve", "build-demo": "yarn build && mkdirp ../../packages/graphiql/monaco && cp -r dist/* ../../packages/graphiql/monaco/" }, "dependencies": { "graphql": "^16.9.0", "graphql-language-service": "^5.5.0", "json-schema": "^0.4.0", "jsonc-parser": "^3.2.0", "monaco-editor": "^0.52.2", "monaco-graphql": "^1.7.3", "prettier": "3.3.2" }, "devDependencies": { "@babel/core": "^7.21.0", "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-transform-class-static-block": "^7.27.1", "@babel/preset-env": "^7.20.2", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.21.0", "@webpack-cli/serve": "^2.0.1", "babel-loader": "^9.1.2", "cross-env": "^7.0.2", "css-loader": "^6.7.3", "file-loader": "6.2.0", "fork-ts-checker-webpack-plugin": "7.3.0", "html-webpack-plugin": "^5.5.0", "monaco-editor-webpack-plugin": "^7.0.1", "style-loader": "^3.3.1", "typescript": "^4.6.3", "webpack": "5.76.0", "webpack-bundle-analyzer": "^3.6.1", "webpack-cli": "^5.0.1", "webpack-dev-server": "^5.2.1" } } ================================================ FILE: examples/monaco-graphql-webpack/src/editors.ts ================================================ import { editor, Uri } from 'monaco-graphql/esm/monaco-editor'; const GRAPHQL_LANGUAGE_ID = 'graphql'; const operationString = localStorage.getItem('operations') ?? ` # right click to view context menu # F1 for command palette # enjoy prettier formatting, autocompletion, # validation, hinting and more for GraphQL SDL and operations! query Example( $owner: String! $name: String! $reviewEvent: PullRequestReviewEvent! $user: FollowUserInput! ) { repository(owner: $owner, name: $name) { stargazerCount } } `; const variablesString = localStorage.getItem('variables') ?? `{ "reviewEvent": "graphql", "name": true }`; const resultsString = '{}'; const schemaSdlString = localStorage.getItem('schema-sdl') ?? ''; const THEME = 'vs-dark'; export function createEditors() { const variablesModel = editor.createModel( variablesString, 'json', Uri.file('/1/variables.json'), ); const variablesEditor = editor.create(document.getElementById('variables'), { model: variablesModel, language: 'json', formatOnPaste: true, formatOnType: true, theme: THEME, comments: { insertSpace: true, ignoreEmptyLines: true, }, }); const operationModel = editor.createModel( operationString, GRAPHQL_LANGUAGE_ID, Uri.file('/1/operation.graphql'), ); const operationEditor = editor.create(document.getElementById('operation'), { model: operationModel, formatOnPaste: true, formatOnType: true, folding: true, theme: THEME, language: GRAPHQL_LANGUAGE_ID, }); const schemaModel = editor.createModel( schemaSdlString, GRAPHQL_LANGUAGE_ID, Uri.file('/1/schema.graphqls'), ); const schemaEditor = editor.create(document.getElementById('schema-sdl'), { model: schemaModel, formatOnPaste: true, formatOnType: true, folding: true, theme: THEME, language: GRAPHQL_LANGUAGE_ID, }); const resultsModel = editor.createModel( resultsString, 'json', Uri.file('/1/results.json'), ); const resultsEditor = editor.create(document.getElementById('results'), { model: resultsModel, language: 'json', theme: THEME, wordWrap: 'on', readOnly: true, showFoldingControls: 'always', }); return { operationEditor, variablesEditor, resultsEditor, schemaEditor, operationModel, variablesModel, schemaModel, }; } ================================================ FILE: examples/monaco-graphql-webpack/src/index.html.ejs ================================================ Monaco Example!
================================================ FILE: examples/monaco-graphql-webpack/src/index.ts ================================================ /* global netlify */ import { editor, KeyMod, KeyCode } from 'monaco-graphql/esm/monaco-editor'; import * as JSONC from 'jsonc-parser'; import { initializeMode } from 'monaco-graphql/esm/initializeMode'; import { createEditors } from './editors'; import { schemaFetcher, schemaOptions } from './schema'; import './style.css'; import type { MonacoGraphQLAPI } from 'monaco-graphql'; const SITE_ID = '46a6b3c8-992f-4623-9a76-f1bd5d40505c'; let monacoGraphQLAPI: MonacoGraphQLAPI | null = null; void render(); async function render() { if (!schemaFetcher.token) { renderGithubLoginButton(); return; } monacoGraphQLAPI ||= initializeMode({ formattingOptions: { prettierConfig: { printWidth: 120, }, }, }); document.getElementById('github-login-wrapper')?.remove(); document .getElementById('session-editor') ?.setAttribute('style', 'display: flex'); document .getElementById('toolbar') ?.setAttribute('style', 'display: inline-flex'); const toolbar = document.getElementById('toolbar'); const editors = createEditors(); const { operationModel, operationEditor, variablesEditor, schemaEditor, resultsEditor, variablesModel, schemaModel, } = editors; const { schemaReloadButton, executeOpButton, schemaPicker } = renderToolbar(toolbar); renderGithubLoginButton(); const operationUri = operationModel.uri.toString(); const schema = await schemaFetcher.loadSchema(); if (schema) { console.log('loaded schema', schema); monacoGraphQLAPI.setSchemaConfig([ { ...schema, fileMatch: [operationUri, schemaModel.uri.toString()] }, ]); schemaEditor.setValue(schema.documentString || ''); } monacoGraphQLAPI.setDiagnosticSettings({ validateVariablesJSON: { [operationUri]: [variablesModel.uri.toString()], }, jsonDiagnosticSettings: { // jsonc tip! allowComments: true, schemaValidation: 'error', // this is nice too trailingCommas: 'warning', }, }); operationModel.onDidChangeContent(() => { setTimeout(() => { localStorage.setItem('operations', operationModel.getValue()); }, 200); }); variablesModel.onDidChangeContent(() => { setTimeout(() => { localStorage.setItem('variables', variablesModel.getValue()); }, 200); }); schemaModel.onDidChangeContent(() => { setTimeout(async () => { const value = schemaModel.getValue(); localStorage.setItem('schema-sdl', value); const nextSchema = await schemaFetcher.overrideSchema(value); if (nextSchema) { monacoGraphQLAPI?.setSchemaConfig([ { ...nextSchema, fileMatch: [operationUri, schemaModel.uri.toString()], }, ]); } }, 200); }); /** * Choosing a new schema */ schemaPicker.addEventListener( 'input', async function SchemaSelectionHandler(_ev: Event) { if (schemaPicker.value === schemaFetcher.currentSchema.value) { return; } const schemaResult = await schemaFetcher.changeSchema(schemaPicker.value); if (schemaResult && monacoGraphQLAPI) { monacoGraphQLAPI.setSchemaConfig([ { ...schemaResult, fileMatch: [operationModel.uri.toString()], }, ]); schemaEditor.setValue(schemaResult.documentString || ''); } }, ); /** * Reloading your schema */ schemaReloadButton.addEventListener('click', async () => { const schemaResult = await schemaFetcher.loadSchema(); if (schemaResult) { schemaEditor.setValue(schemaResult.documentString || ''); } }); /** * Execute GraphQL operations, for reference! * monaco-graphql itself doesn't do anything with handling operations yet, but it may soon! */ const getOperationHandler = () => async () => { try { const operation = operationEditor.getValue(); const variables = variablesEditor.getValue(); const body: { variables?: string; query: string } = { query: operation, }; // parse the variables with JSONC, so we can have comments! const parsedVariables = JSONC.parse(variables); if (parsedVariables && Object.keys(parsedVariables).length) { body.variables = JSON.stringify(parsedVariables, null, 2); } const result = await fetch(schemaFetcher.currentSchema.value, { method: 'POST', headers: { 'content-type': 'application/json', ...schemaFetcher.currentSchema?.headers, }, body: JSON.stringify(body, null, 2), }); const resultText = await result.text(); resultsEditor.setValue(JSON.stringify(JSON.parse(resultText), null, 2)); } catch (err) { if (err instanceof Error) { resultsEditor.setValue(err.toString()); } } }; const operationHandler = getOperationHandler(); executeOpButton.addEventListener('click', operationHandler); executeOpButton.addEventListener('touchend', operationHandler); /** * Add an editor operation to the command palette & keyboard shortcuts */ const opAction: editor.IActionDescriptor = { id: 'graphql-run', label: 'Run Operation', contextMenuOrder: 0, contextMenuGroupId: 'graphql', keybindings: [ // eslint-disable-next-line no-bitwise KeyMod.CtrlCmd | KeyCode.Enter, ], run: operationHandler, }; /** * Add a reload operation to the command palette & keyboard shortcuts */ const reloadAction: editor.IActionDescriptor = { id: 'graphql-reload', label: 'Reload Schema', contextMenuOrder: 0, contextMenuGroupId: 'graphql', keybindings: [ KeyMod.CtrlCmd | KeyCode?.KeyR, // eslint-disable-line no-bitwise ], async run() { await schemaFetcher.loadSchema(); }, }; operationEditor.addAction(opAction); variablesEditor.addAction(opAction); resultsEditor.addAction(opAction); operationEditor.addAction(reloadAction); } function renderToolbar(toolbar: HTMLElement) { toolbar.innerHTML = ''; const schemaStatus = document.createElement('div'); const schemaReloadButton = document.createElement('button'); const executeOpButton = document.createElement('button'); const schemaPicker = getSchemaPicker(); const executionTray = document.createElement('div'); executionTray.id = 'execution-tray'; executionTray.append(executeOpButton); executionTray.classList.add('align-right'); executeOpButton.id = 'execute-op'; executeOpButton.textContent = 'Run Operation ➤'; executeOpButton.title = 'Execute the active GraphQL Operation'; schemaReloadButton.classList.add('reload-button'); schemaReloadButton.innerHTML = '🔄'; schemaReloadButton.title = 'Reload the graphql schema'; schemaStatus.id = 'schema-status'; schemaStatus.innerHTML = 'Schema Empty'; toolbar.append( schemaPicker, schemaReloadButton, schemaStatus, executeOpButton, ); return { schemaReloadButton, executeOpButton, schemaStatus, schemaPicker }; } function getSchemaPicker(): HTMLSelectElement { const schemaPicker = document.createElement('select'); schemaPicker.id = 'schema-picker'; for (const option of schemaOptions) { const optEl = document.createElement('option'); optEl.value = option.value; optEl.label = option.label; if (option.default) { optEl.selected = true; } schemaPicker.append(optEl); } return schemaPicker; } /** * login using the provided netlify API for oauth */ export function renderGithubLoginButton() { const githubLoginWrapper = document.createElement('div'); githubLoginWrapper.id = 'github-login-wrapper'; githubLoginWrapper.innerHTML = "

Using Netlify's OAuth client to retrieve your token, you'll see a simple GitHub graphql monaco-graphql Demo.

"; const githubButton = document.createElement('button'); const logoutButton = document.createElement('button'); logoutButton.innerHTML = 'Logout'; logoutButton.onclick = async e => { e.preventDefault(); schemaFetcher.logout(); await render(); document .getElementById('session-editor') ?.setAttribute('style', 'display: none'); document.getElementById('toolbar')?.setAttribute('style', 'display: none'); }; if (schemaFetcher.token) { document.getElementById('github-login-wrapper')?.remove(); const toolbar = document.getElementById('toolbar'); toolbar?.append(logoutButton); } else { githubLoginWrapper.append(githubButton); document.getElementById('flex-wrapper')?.prepend(githubLoginWrapper); } githubButton.id = 'login'; githubButton.innerHTML = 'GitHub Login'; githubButton.onclick = e => { e.preventDefault(); // @ts-expect-error const authenticator = new netlify.default({ site_id: SITE_ID }); authenticator.authenticate( { provider: 'github', scope: ['user'] }, async (err: Error, data: { token: string }) => { if (err) { console.error('Error authenticating with GitHub:', err); } else { await schemaFetcher.setApiToken(data.token); await render(); } }, ); }; } ================================================ FILE: examples/monaco-graphql-webpack/src/schema.ts ================================================ import { buildClientSchema, getIntrospectionQuery, printSchema, parse, buildASTSchema, } from 'graphql'; import type { SchemaConfig } from 'monaco-graphql'; import { Uri } from 'monaco-graphql/esm/monaco-editor'; const SCHEMA_URL = 'https://api.github.com/graphql'; const API_TOKEN = localStorage.getItem('ghapi') || null; const localStorageKey = 'ghapi'; export const schemaOptions = [ { value: SCHEMA_URL, label: 'Github API', default: true, headers: Object.create(null), }, { value: 'https://api.spacex.land/graphql', label: 'SpaceX GraphQL API', headers: Object.create(null), }, ]; const setSchemaStatus = (message: string) => { const schemaStatus = document.getElementById('schema-status'); if (schemaStatus) { const html = message; schemaStatus.innerHTML = html; } }; class MySchemaFetcher { private _options: typeof schemaOptions; private _currentSchema: (typeof schemaOptions)[0]; private _schemaCache = new Map(); private _schemaOverride = new Map(); constructor(options = schemaOptions) { this._options = options; this._currentSchema = schemaOptions[0]; if (API_TOKEN) { this._currentSchema.headers.authorization = `Bearer ${API_TOKEN}`; } } public get currentSchema() { return this._currentSchema; } public get token() { return this._currentSchema.headers.authorization; } async getSchema() { const cacheItem = this._schemaCache.get(this._currentSchema.value); if (cacheItem) { return { ...cacheItem, documentString: this.getOverride() || cacheItem.documentString, }; } return this.loadSchema(); } async setApiToken(token: string) { this._currentSchema.headers.authorization = `Bearer ${token}`; localStorage.setItem(localStorageKey, token); } logout() { this._currentSchema.headers.authorization = undefined; localStorage.removeItem(localStorageKey); } async loadSchema() { try { setSchemaStatus('Schema Loading...'); const url = this._currentSchema.value; const headers = { 'content-type': 'application/json', }; const result = await fetch(url, { method: 'POST', headers: { ...headers, ...this._currentSchema.headers, }, body: JSON.stringify( { query: getIntrospectionQuery(), operationName: 'IntrospectionQuery', }, null, 2, ), }); const introspectionJSON = (await result.json()).data; const documentString = printSchema(buildClientSchema(introspectionJSON)); this._schemaCache.set(url, { introspectionJSON, documentString, uri: Uri.parse(url).toString(), }); this.clearOverride(); setSchemaStatus('Schema Loaded'); } catch { setSchemaStatus('Schema error'); } return this._schemaCache.get(this._currentSchema.value); } async changeSchema(uri: string) { this._currentSchema = this._options.find(opt => opt.value === uri)!; this.clearOverride(); return this.getSchema(); } getOverride() { return this._schemaOverride.get(this._currentSchema.value); } clearOverride() { this._schemaOverride.delete(this._currentSchema.value); } async overrideSchema(sdl: string) { if (isValid(sdl)) { this._schemaOverride.set(this._currentSchema.value, sdl); return this.getSchema(); } } } function isValid(sdl: string) { try { const ast = parse(sdl); buildASTSchema(ast); return true; } catch { return false; } } export const schemaFetcher = new MySchemaFetcher(schemaOptions); ================================================ FILE: examples/monaco-graphql-webpack/src/style.css ================================================ body { background-color: #1e1e1e; margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } .div { margin: 0; padding: 0; } .full-height { height: 100vh; } .half-width { width: 50%; } .column { display: flex; flex-direction: column; align-items: stretch; } .row { display: flex; flex-direction: row; } .align-right { /* align-self: stretch; */ margin-left: auto; align-self: stretch; } /* Editors */ #flex-wrapper { display: flex; align-items: stretch; } #operation { height: 60vh; min-height: 260px; } #variables { height: 30vh; align-items: stretch; } #results { align-items: stretch; height: 45vh; } #schema-sdl { align-items: stretch; height: 45vh; } /* Toolbar */ #toolbar { min-height: 40px; background-color: #1e1e1e; display: inline-flex; align-items: stretch; } #toolbar > button, #toolbar > select, #toolbar > div, button#execute-op { margin: 0px 4px; padding: 4px; } #toolbar button, #toolbar select { background-color: #1e1e1e; color: #eee; border: 1px solid #eee; border-radius: 4px; } #toolbar button:hover, select:hover, button:focus, select:focus { background-color: darkslategrey; } #execution-tray { align-items: flex-end; } #toolbar #schema-status { color: #eee; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; padding: 11px 4px; font-size: small; } #toolbar button.reload-button { border: 0 none; padding: 4px; width: 30px; text-align: center; } #github-login-wrapper { text-align: center; color: white; flex-direction: row; width: 100%; height: 200px; } ================================================ FILE: examples/monaco-graphql-webpack/tsconfig.json ================================================ { "compilerOptions": { "target": "esnext", "module": "esnext", "rootDir": "./src", "outDir": "./dist", "composite": true, "baseUrl": ".", "strictPropertyInitialization": false, "types": ["node", "jest"], "typeRoots": ["../../node_modules/@types", "node_modules/@types"], "lib": ["dom", "ESNext"], "moduleResolution": "node" }, "references": [{ "path": "../../packages/monaco-graphql" }], "include": ["src"], "exclude": ["**/__tests__/**", "**/build/**.*", "../../node_modules"] } ================================================ FILE: examples/monaco-graphql-webpack/webpack.config.js ================================================ const path = require('node:path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); const isDev = process.env.NODE_ENV === 'development'; const relPath = (...args) => path.resolve(__dirname, ...args); const rootPath = (...args) => relPath(...args); const resultConfig = { mode: process.env.NODE_ENV, entry: './index.ts', context: rootPath('src'), output: { path: rootPath('dist'), filename: '[name].js', }, module: { rules: [ // you can also use ts-loader of course // i prefer to use babel-loader & @babel/plugin-typescript // so we can experiment with how changing browserslistrc targets impacts // monaco-graphql bundling { test: /\.(js|jsx|ts|tsx)$/, use: [{ loader: 'babel-loader' }], }, { test: /\.css$/, use: ['style-loader', 'css-loader'], }, { test: /\.svg$/, use: [{ loader: 'svg-inline-loader' }], }, { test: /\.(woff|woff2|eot|ttf|otf)$/, type: 'asset/resource', }, ], }, resolve: { extensions: ['.ts', '.js'], }, plugins: [ // in order to prevent async modules for CDN builds // until we can guarantee it will work with the CDN properly // and so that `index.umd.js` can retain parity new HtmlWebpackPlugin({ template: relPath('src/index.html.ejs'), filename: 'index.html', }), // critical! make sure that webpack can consume the exported modules and types new ForkTsCheckerWebpackPlugin({ async: isDev, typescript: { configFile: rootPath('tsconfig.json') }, }), new MonacoWebpackPlugin({ languages: ['json', 'graphql'], publicPath: '/', customLanguages: [ { label: 'graphql', worker: { id: 'graphql', entry: require.resolve('monaco-graphql/esm/graphql.worker.js'), }, }, ], }), ], }; if (process.env.ANALYZE) { resultConfig.plugins.push( new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false, reportFilename: rootPath('build/analyzer.html'), }), ); } module.exports = resultConfig; ================================================ FILE: functions/graphql.ts ================================================ import { createHandler as createRawHandler, HandlerOptions as RawHandlerOptions, OperationContext, } from 'graphql-http'; import type { Handler as NetlifyHandler, HandlerEvent as NetlifyHandlerEvent, HandlerContext as NetlifyHandlerContext, } from '@netlify/functions'; import * as graphql from 'graphql'; import { createSchema } from '../packages/graphiql/test/schema.js'; import { createExecute } from '../packages/graphiql/test/execute.js'; /** * Handler options when using the netlify adapter * * @category Server/@netlify/functions */ type HandlerOptions = RawHandlerOptions; /** * Create a GraphQL over HTTP spec compliant request handler for netlify functions * * @category Server/@netlify/functions */ export function createHandler( options: HandlerOptions, ): NetlifyHandler { const handler = createRawHandler(options); return async function handleRequest(req, ctx) { try { const [body, init] = await handler({ method: req.httpMethod, url: req.rawUrl, headers: req.headers, body: req.body, raw: req, context: ctx, }); return { // if body is null, return undefined body: body ?? undefined, statusCode: init.status, }; } catch (err) { // The handler shouldn't throw errors. // If you wish to handle them differently, consider implementing your own request handler. console.error( 'Internal error occurred during request handling. Please check your implementation.', err, ); return { statusCode: 500, body: JSON.stringify({ errors: [{ message: err.message }] }), }; } }; } export const handler = createHandler({ schema: createSchema(graphql), execute: createExecute(graphql), }); ================================================ FILE: functions/package.json ================================================ { "name": "netlify-function", "private": true, "dependencies": { "graphql": "^16.11.0", "graphql-http": "^1.22.4" } } ================================================ FILE: jest.config.base.js ================================================ module.exports = dir => { const package = require(`${dir}/package.json`); return { globals: { 'ts-jest': { tsConfig: `${__dirname}/resources/tsconfig.base.esm.json`, }, }, clearMocks: true, collectCoverage: true, coverageDirectory: `${__dirname}/coverage/jest`, moduleNameMapper: { '^graphql-language-service-([^/]+)': `${__dirname}/packages/graphql-language-service/src/$1`, '^graphql-language-([^/]+)': `${__dirname}/packages/graphql-language-$1/src`, // because of the svelte compiler's export patterns i guess? 'svelte/compiler': `${__dirname}/node_modules/svelte/compiler.cjs`, }, testMatch: ['**/*[-.](spec|test).[jt]s?(x)', '!**/cypress/**'], testEnvironment: 'node', testPathIgnorePatterns: ['node_modules', 'dist', 'cypress'], collectCoverageFrom: ['**/src/**/*.{js,jsx,ts,tsx}'], transformIgnorePatterns: ['node_modules/(!@astrojs/compiler)'], coveragePathIgnorePatterns: [ 'dist', 'esm', 'node_modules', '__tests__', 'resources', 'examples', '.d.ts', 'types.ts', ], roots: [''], rootDir: dir, name: package.name, displayName: package.name, }; }; ================================================ FILE: jest.config.js ================================================ module.exports = { projects: ['/packages/*/jest.config.js'], }; ================================================ FILE: js-green-licenses.json ================================================ { "packageAllowlist": [ // MIT, just lacking SPDX in manifest "valid-url", "argparse" ], "dev": false } ================================================ FILE: netlify.toml ================================================ # Settings in the [build] context are global and are applied to # all contexts unless otherwise overridden by more specific contexts. [build] publish = "packages/graphiql" # Default build command. command = "yarn build && yarn build-bundles && yarn build-docs && yarn build-demo" environment = { YARN_FLAGS = "--frozen-lockfile --immutable"} ================================================ FILE: package.json ================================================ { "name": "graphiql-monorepo", "version": "0.0.0", "private": true, "license": "MIT", "workspaces": { "packages": [ "packages/*", "functions", "packages/graphiql/test", "examples/monaco-graphql-webpack", "examples/monaco-graphql-nextjs", "examples/monaco-graphql-react-vite", "examples/graphiql-vite", "examples/graphiql-vite-react-router", "examples/graphiql-webpack" ] }, "packageManager": "yarn@4.9.1", "scripts": { "types:check": "turbo run types:check", "dev:graphiql": "turbo run dev --filter=graphiql...", "dev:example-nextjs": "turbo run dev --filter=example-graphiql-nextjs...", "dev:example-vite": "turbo run dev --filter=example-graphiql-vite...", "build:graphiql": "turbo run build --filter=graphiql...", "build": "yarn build-clean && yarn tsc && yarn build:nontsc", "build-bundles": "yarn prebuild-bundles && yarn wsrun:noexamples --stages build-bundles", "build-bundles-clean": "rimraf '{packages,examples}/**/{bundle,cdn,webpack}'", "build-clean": "yarn tsc --clean", "build-docs": "rimraf packages/graphiql/typedoc && typedoc packages", "build:nontsc": "yarn wsrun:noexamples --exclude-missing --serial build", "build:clean": "yarn tsc --clean", "build:watch": "yarn tsc --watch", "build-demo": "wsrun -m build-demo", "watch": "yarn build:watch", "watch-vscode": "yarn tsc && yarn workspace vscode-graphql compile", "watch-vscode-exec": "yarn workspace vscode-graphql-execution compile", "check": "yarn tsc --noEmit", "cypress-open": "concurrently 'yarn dev:graphiql' 'yarn workspace graphiql cypress-open'", "e2e": "yarn workspace graphiql e2e", "eslint": "NODE_OPTIONS=--max-old-space-size=4096 ESLINT_USE_FLAT_CONFIG=false eslint --max-warnings=0 --ignore-path .gitignore --cache .", "format": "yarn eslint --fix && yarn pretty", "jest": "jest", "license-check": "jsgl --local packages/*", "lint": "yarn eslint && yarn pretty-check && yarn lint-cspell", "lint-cspell": "cspell --unique --no-progress --no-must-find-files", "lint-fix": "yarn eslint --fix", "postinstall": "patch-package --patch-dir resources/patches", "prebuild-bundles": "yarn build-bundles-clean", "prepublishOnly": "./scripts/prepublish.sh", "postbuild": "wsrun --exclude-missing postbuild", "pretty": "yarn pretty-check --write", "pretty-check": "prettier --cache --check --ignore-path .gitignore --ignore-path resources/prettierignore --ignore-path .eslintignore .", "ci:version": "yarn changeset version && yarn build && yarn format", "release": "yarn build && yarn build-bundles && (wsrun release --exclude-missing --serial --recursive --changedSince main -- || true) && yarn changeset publish", "release:canary": "(node scripts/canary-release.js && yarn build-bundles && yarn changeset publish --tag canary) || echo Skipping Canary...", "repo:lint": "manypkg check", "repo:fix": "manypkg fix", "repo:resolve": "node scripts/set-resolution.js", "t": "yarn test", "test": "yarn jest", "test:ci": "yarn build && jest --coverage && yarn vitest", "test:coverage": "yarn jest --coverage", "test:watch": "yarn jest --watch", "tsc": "tsc --build && node resources/patch-monaco-editor-type.mjs", "vitest": "turbo run test", "wsrun:noexamples": "wsrun --exclude-missing --exclude example-monaco-graphql-react-vite --exclude example-monaco-graphql-nextjs --exclude example-monaco-graphql-webpack --exclude example-graphiql-webpack", "gen-agenda": "wgutils agenda gen" }, "dependencies": { "@babel/cli": "^7.21.0", "@babel/core": "^7.21.0", "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", "@babel/plugin-proposal-optional-chaining": "^7.21.0", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/polyfill": "^7.12.1", "@babel/preset-env": "^7.20.2", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.21.0", "@babel/register": "^7.21.0", "@changesets/changelog-github": "0.5.0", "@changesets/cli": "2.27.7", "@manypkg/get-packages": "^1.1.3", "@shopify/eslint-plugin": "^48.0.2", "@strictsoftware/typedoc-plugin-monorepo": "^0.3.1", "@types/codemirror": "^0.0.90", "@types/express": "^4.17.11", "@types/fetch-mock": "^7.3.2", "@types/jest": "^29.5.2", "@types/node": "^16.18.4", "@types/ws": "8.2.2", "@typescript-eslint/eslint-plugin": "^8.32.0", "@typescript-eslint/parser": "^8.32.0", "babel-plugin-macros": "^3.1.0", "babel-plugin-transform-import-meta": "^2.2.1", "concurrently": "^7.0.0", "copy": "^0.3.2", "cspell": "^5.15.2", "eslint": "9.25.1", "eslint-config-prettier": "^10.1.2", "eslint-import-resolver-typescript": "^4.3.4", "eslint-plugin-cypress": "^4.3.0", "eslint-plugin-import-x": "^4.11.0", "eslint-plugin-jest": "^28.11.0", "eslint-plugin-mdx": "^3.4.1", "eslint-plugin-promise": "^7.2.1", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^6.0.0-rc.1", "eslint-plugin-sonarjs": "^3.0.2", "eslint-plugin-unicorn": "^56.0.0", "execa": "^7.1.1", "fetch-mock": "6.5.2", "jest": "^27.5.1", "js-green-licenses": "4.0.0", "mkdirp": "^1.0.4", "patch-package": "^7.0.2", "postinstall-postinstall": "^2.1.0", "prettier": "3.3.2", "rimraf": "^3.0.2", "ts-jest": "^27.1.5", "turbo": "^2.5.2", "typedoc": "^0.19.2", "typescript": "^4.6.3", "vitest": "^2.1.9", "wgutils": "^1.2.5", "wsrun": "^5.2.4" }, "resolutions": { "@babel/traverse": "^7.23.2", "vscode-languageserver-types": "3.17.3", "markdown-it": "14.1.0", "react": "18.3.1", "react-dom": "18.3.1", "vite": "6.3.4" } } ================================================ FILE: packages/cm6-graphql/.gitignore ================================================ /node_modules package-lock.json /dist /src/*.js /src/*.d.ts !syntax.grammar.d.ts ================================================ FILE: packages/cm6-graphql/.npmignore ================================================ /src /test /node_modules rollup.config.js tsconfig.json ================================================ FILE: packages/cm6-graphql/CHANGELOG.md ================================================ # cm6-graphql ## 0.2.1 ### Patch Changes - [#3920](https://github.com/graphql/graphiql/pull/3920) [`c6fddac`](https://github.com/graphql/graphiql/commit/c6fddac4b0e639be846dd8a23ebfd3e334410178) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove unneeded rollup/esbuild dev dependencies ## 0.2.0 ### Minor Changes - [#3762](https://github.com/graphql/graphiql/pull/3762) [`76b3cc8`](https://github.com/graphql/graphiql/commit/76b3cc872dedd667504f58c9313a86bada7688d6) Thanks [@mavenskylab](https://github.com/mavenskylab)! - The cm6-graphql package currently specifies exact versions for its peer dependencies on @codemirror packages. This is causing conflicts when projects use newer versions of these packages, leading to multiple instances being installed. ## 0.1.1 ### Patch Changes - [#3751](https://github.com/graphql/graphiql/pull/3751) [`b8538d8`](https://github.com/graphql/graphiql/commit/b8538d87421edb086b32d4eb2e30a3f7d9d9e893) Thanks [@dimaMachina](https://github.com/dimaMachina)! - replace deprecated `navigator.platform` with `navigator.userAgent` fix placeholder `⌘ K` in doc explorer search input for non mac devices, replace by `Ctrl K` ## 0.1.0 ### Minor Changes - [#3682](https://github.com/graphql/graphiql/pull/3682) [`6c9f0df`](https://github.com/graphql/graphiql/commit/6c9f0df83ea4afe7fa59f84d83d59fba73dc3931) Thanks [@yaacovCR](https://github.com/yaacovCR)! - Support v17 of `graphql-js` from `17.0.0-alpha.2` forward. Includes support for the latest incremental delivery response format. For further details, see https://github.com/graphql/defer-stream-wg/discussions/69. ### Patch Changes - Updated dependencies [[`6c9f0df`](https://github.com/graphql/graphiql/commit/6c9f0df83ea4afe7fa59f84d83d59fba73dc3931)]: - graphql-language-service@5.3.0 ## 0.0.15 ### Patch Changes - [#3521](https://github.com/graphql/graphiql/pull/3521) [`aa6dbbb4`](https://github.com/graphql/graphiql/commit/aa6dbbb45bf51c1966537640fbe5c4f375735c8d) Thanks [@acao](https://github.com/acao)! - Fixes several issues with Type System (SDL) completion across the ecosystem: - restores completion for object and input type fields when the document context is not detectable or parseable - correct top-level completions for either of the unknown, type system or executable definitions. this leads to mixed top level completions when the document is unparseable, but now you are not seemingly restricted to only executable top level definitions - `.graphqls` ad-hoc standard functionality remains, but is not required, as it is not part of the official spec, and the spec also allows mixed mode documents in theory, and this concept is required when the type is unknown - Updated dependencies [[`aa6dbbb4`](https://github.com/graphql/graphiql/commit/aa6dbbb45bf51c1966537640fbe5c4f375735c8d)]: - graphql-language-service@5.2.1 ## 0.0.14 ### Patch Changes - [#3534](https://github.com/graphql/graphiql/pull/3534) [`f4c98c1f`](https://github.com/graphql/graphiql/commit/f4c98c1f7c6df5a918479e641631e8fbc5b5a92e) Thanks [@johndcollett](https://github.com/johndcollett)! - fix: multiple argument syntax highlighting ## 0.0.13 ### Patch Changes - [#3505](https://github.com/graphql/graphiql/pull/3505) [`a562c96f`](https://github.com/graphql/graphiql/commit/a562c96fa3953d0301ad7b610028fa6c4a779bf6) Thanks [@Gasser-Aly](https://github.com/Gasser-Aly)! - fix: block strings syntax highlighting ## 0.0.12 ### Patch Changes - [#3463](https://github.com/graphql/graphiql/pull/3463) [`e45ba17c`](https://github.com/graphql/graphiql/commit/e45ba17cb2f13e5a79d3e87b0f30ef92ec55d861) Thanks [@imolorhe](https://github.com/imolorhe)! - Create a lint diagnostic from invalid schema ## 0.0.11 ### Patch Changes - [#3461](https://github.com/graphql/graphiql/pull/3461) [`129666a9`](https://github.com/graphql/graphiql/commit/129666a9a86690bb72226674d40215f24dc5f7ea) Thanks [@imolorhe](https://github.com/imolorhe)! - Wrap cm6-graphql lint logic in try..catch ## 0.0.10 ### Patch Changes - [#3405](https://github.com/graphql/graphiql/pull/3405) [`3d4b9b75`](https://github.com/graphql/graphiql/commit/3d4b9b7551fd9bb38ef9f4a7c6c330366d43bbfa) Thanks [@imolorhe](https://github.com/imolorhe)! - relint when schema changes - Updated dependencies [[`7b00774a`](https://github.com/graphql/graphiql/commit/7b00774affad1f25253ce49f1f48c9e3f372808c), [`7b00774a`](https://github.com/graphql/graphiql/commit/7b00774affad1f25253ce49f1f48c9e3f372808c)]: - graphql-language-service@5.2.0 ## 0.0.9 ### Patch Changes - Updated dependencies [[`5971d528`](https://github.com/graphql/graphiql/commit/5971d528b0608e76d9d109103f64857a790a99b9), [`d9e5089f`](https://github.com/graphql/graphiql/commit/d9e5089f78f85cd50c3e3e3ba8510f7dda3d06f5)]: - graphql-language-service@5.1.7 ## 0.0.9-alpha.0 ### Patch Changes - Updated dependencies [[`5971d528`](https://github.com/graphql/graphiql/commit/5971d528b0608e76d9d109103f64857a790a99b9), [`d9e5089f`](https://github.com/graphql/graphiql/commit/d9e5089f78f85cd50c3e3e3ba8510f7dda3d06f5)]: - graphql-language-service@5.1.7-alpha.0 ## 0.0.8 ### Patch Changes - [#3118](https://github.com/graphql/graphiql/pull/3118) [`431b7fe1`](https://github.com/graphql/graphiql/commit/431b7fe1efefa4867f0ea617adc436b1117052e8) Thanks [@B2o5T](https://github.com/B2o5T)! - Prefer `.textContent` over `.innerText` ## 0.0.7 ### Patch Changes - Updated dependencies [[`06007498`](https://github.com/graphql/graphiql/commit/06007498880528ed75dd4d705dcbcd7c9e775939)]: - graphql-language-service@5.1.6 ## 0.0.6 ### Patch Changes - Updated dependencies [[`4d33b221`](https://github.com/graphql/graphiql/commit/4d33b2214e941f171385a1b72a1fa995714bb284)]: - graphql-language-service@5.1.5 ## 0.0.5 ### Patch Changes - [#3127](https://github.com/graphql/graphiql/pull/3127) [`0d2bb2bc`](https://github.com/graphql/graphiql/commit/0d2bb2bcc6522e156e2d70f3be553bd4b60c8ee1) Thanks [@imolorhe](https://github.com/imolorhe)! - Updated cm6-graphql package README - Updated dependencies [[`2e477eb2`](https://github.com/graphql/graphiql/commit/2e477eb24672a242ae4a4f2dfaeaf41152ed7ee9)]: - graphql-language-service@5.1.4 ## 0.0.4 ### Patch Changes - [#3075](https://github.com/graphql/graphiql/pull/3075) [`9c1a02db`](https://github.com/graphql/graphiql/commit/9c1a02dbff4a39fe999873912daec7dcd1d39b5c) Thanks [@acao](https://github.com/acao)! - another manual release attempt to trigger versioning - [#3074](https://github.com/graphql/graphiql/pull/3074) [`7cb2a2f1`](https://github.com/graphql/graphiql/commit/7cb2a2f156d918fd57b7d3757ee1ecc0f4dab4ce) Thanks [@acao](https://github.com/acao)! - Fix release bug, trigger changeset release action - [#3069](https://github.com/graphql/graphiql/pull/3069) [`d922e930`](https://github.com/graphql/graphiql/commit/d922e930f77dff879212ad39191ad6a1b8f7dd8a) Thanks [@sergeichestakov](https://github.com/sergeichestakov)! - Added graphql-language-service as a direct dep of cm6-graphql and update peer dependencies - Updated dependencies [[`b9c13328`](https://github.com/graphql/graphiql/commit/b9c13328f3d28c0026ee0f0ecc7213065c9b016d), [`881a2024`](https://github.com/graphql/graphiql/commit/881a202497d5a58eb5260a5aa54c0c88930d69a0)]: - graphql-language-service@5.1.3 ## 0.0.3 ### Patch Changes - [#2995](https://github.com/graphql/graphiql/pull/2995) [`5f276c41`](https://github.com/graphql/graphiql/commit/5f276c415ad93350382fec873025ffecc9a29d9d) Thanks [@imolorhe](https://github.com/imolorhe)! - fix(cm6-graphql): Fix query token used as field name - [#2962](https://github.com/graphql/graphiql/pull/2962) [`db2a0982`](https://github.com/graphql/graphiql/commit/db2a0982a17134f0069483ab283594eb64735b7d) Thanks [@B2o5T](https://github.com/B2o5T)! - clean all ESLint warnings, add `--max-warnings=0` and `--cache` flags - [#2940](https://github.com/graphql/graphiql/pull/2940) [`8725d1b6`](https://github.com/graphql/graphiql/commit/8725d1b6b686139286cf05dec6a84d89942128ba) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `unicorn/prefer-node-protocol` rule ## 0.0.2 ### Patch Changes - [#2931](https://github.com/graphql/graphiql/pull/2931) [`f7addb20`](https://github.com/graphql/graphiql/commit/f7addb20c4a558fbfb4112c8ff095bbc8f9d9147) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `no-negated-condition` and `no-else-return` rules - [#2922](https://github.com/graphql/graphiql/pull/2922) [`d1fcad72`](https://github.com/graphql/graphiql/commit/d1fcad72607e2789517dfe4936b5ec604e46762b) Thanks [@B2o5T](https://github.com/B2o5T)! - extends `plugin:import/recommended` and fix warnings - [#2992](https://github.com/graphql/graphiql/pull/2992) [`cc245246`](https://github.com/graphql/graphiql/commit/cc2452467688f3cdcd7a196dddf47e3b81367d62) Thanks [@acao](https://github.com/acao)! - fix tsconfig reference, new netlify deploy ## 0.0.1 ### Patch Changes - [#2867](https://github.com/graphql/graphiql/pull/2867) [`9fd12838`](https://github.com/graphql/graphiql/commit/9fd128381a86220a7c658f21d72baa8eea45a8af) Thanks [@imolorhe](https://github.com/imolorhe)! - fix: fixed "Mark decorations may not be empty" error ## 0.0.0 ### Patch Changes - [#2852](https://github.com/graphql/graphiql/pull/2852) [`20869583`](https://github.com/graphql/graphiql/commit/20869583eff563f5d6494e93302a835f0e034f4b) Thanks [@acao](https://github.com/acao)! - First release of a modern codemirror 6 mode for graphql by @imolorhe! ================================================ FILE: packages/cm6-graphql/LICENSE ================================================ MIT License Copyright (C) 2021 by GraphQL Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/cm6-graphql/README.md ================================================ # CodeMirror 6 GraphQL Language extension [![NPM](https://img.shields.io/npm/v/cm6-graphql.svg?style=flat-square)](https://npmjs.com/cm6-graphql) ![npm downloads](https://img.shields.io/npm/dm/cm6-graphql?label=npm%20downloads) [![License](https://img.shields.io/npm/l/cm6-graphql.svg?style=flat-square)](LICENSE) [Discord Channel](https://discord.gg/cffZwk8NJW) Provides CodeMirror 6 extension with a parser mode for GraphQL along with autocomplete and linting powered by your GraphQL Schema. ### Getting Started ```sh npm install cm6-graphql ``` [CodeMirror 6](https://codemirror.net/) customization is done through [extensions](https://codemirror.net/docs/guide/#extension). This package is an extension that customizes CodeMirror 6 for GraphQL. ```js import { basicSetup, EditorView } from 'codemirror'; import { graphql } from 'cm6-graphql'; const view = new EditorView({ doc: `mutation mutationName { setString(value: "newString") }`, extensions: [basicSetup, graphql(myGraphQLSchema)], parent: document.body, }); ``` _**Note:** You have to provide a theme to CodeMirror 6 for the styling you want. You can take a look at [this example](https://github.com/graphql/graphiql/blob/main/examples/cm6-graphql-parcel/src/index.ts) or see the CodeMirror 6 [documentation examples](https://codemirror.net/examples/styling/) for more details._ ### Updating schema If you need to dynamically update the GraphQL schema used in the editor, you can call `updateSchema` with the CodeMirror `EditorView` instance and the new schema ```js import { updateSchema } from 'cm6-graphql'; const onNewSchema = schema => { updateSchema(view, schema); }; ``` ================================================ FILE: packages/cm6-graphql/__tests__/cases.txt ================================================ # Simple query { hello } ==> Document(OperationDefinition(SelectionSet("{",Selection(Field(FieldName)),"}"))) # Named query query a { hello } ==> Document(OperationDefinition(OperationType,Name,SelectionSet("{",Selection(Field(FieldName)),"}"))) # Nested query query { node { id } } ==> Document(OperationDefinition(OperationType,SelectionSet("{",Selection(Field(FieldName,SelectionSet("{",Selection(Field(FieldName)),"}"))),"}"))) # Query with argument { node(id: 4) { id, name } } ==> Document( OperationDefinition( SelectionSet("{",Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,IntValue),")"),SelectionSet("{",Selection(Field(FieldName)),Selection(Field(FieldName)),"}"))),"}") ) ) # Multiple query nesting { categories(id: "1") { name products { name vendor { products { name } } } } } ==> Document(OperationDefinition(SelectionSet("{",Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,StringValue),")"),SelectionSet("{",Selection(Field(FieldName)),Selection(Field(FieldName,SelectionSet("{",Selection(Field(FieldName)),Selection(Field(FieldName,SelectionSet("{",Selection(Field(FieldName,SelectionSet("{",Selection(Field(FieldName)),"}"))),"}"))),"}"))),"}"))),"}"))) # Query of fields with arguments { vendors(productname: "Coconut") { name } products(price:9.99) { id } categories(id: ALL) { parent } } ==> Document(OperationDefinition(SelectionSet("{",Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,StringValue),")"),SelectionSet("{",Selection(Field(FieldName)),"}"))),Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,FloatValue),")"),SelectionSet("{",Selection(Field(FieldName)),"}"))),Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,EnumValue),")"),SelectionSet("{",Selection(Field(FieldName)),"}"))),"}"))) # Multiple named queries query a { hello } query b { bye } mutation c($val: String!) { addAnother(value: $val) { name } } ==> Document( OperationDefinition(OperationType,Name,SelectionSet("{",Selection(Field(FieldName)),"}")), OperationDefinition(OperationType,Name,SelectionSet("{",Selection(Field(FieldName)),"}")), OperationDefinition(OperationType,Name,VariableDefinitions("(",VariableDefinition(Variable,NonNullType(NamedType(Name))),")"),SelectionSet("{",Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,Variable),")"),SelectionSet("{",Selection(Field(FieldName)),"}"))),"}")) ) # Query with a `query` field { other query { inner } } ==> Document( OperationDefinition(SelectionSet("{",Selection(Field(FieldName)),Selection(Field(FieldName,SelectionSet("{",Selection(Field(FieldName)),"}"))),"}")) ) # Test case for blockStringCharacter in a Description """ This is a block string description with multiple lines. It can contain any character except for \""". """ type Example { id: ID } ==> Document( TypeSystemDefinition( TypeDefinition( ObjectTypeDefinition( Description(StringValue), TypeKeyword(type), Name, FieldsDefinition( "{", FieldDefinition(Name, NamedType(Name)), "}" ) ) ) ) ) # multiple arguments separated by a commas { picture(width: 200, height: 100) } ==> Document(OperationDefinition(SelectionSet("{",Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,IntValue),Argument(ArgumentAttributeName,IntValue),")"))),"}"))) ================================================ FILE: packages/cm6-graphql/__tests__/test.spec.ts ================================================ import { describe, it } from 'vitest'; import { graphqlLanguage } from '../dist/index.js'; import { fileTests } from '@lezer/generator/dist/test'; import * as fs from 'node:fs'; import * as path from 'node:path'; // because of the babel transformations, __dirname is the package root (cm6-graphql) const caseDir = path.resolve(path.dirname(__dirname), '__tests__'); describe('codemirror 6 language', () => { for (const file of fs.readdirSync(caseDir)) { if (!/\.txt$/.test(file)) { continue; } const describeName = /^[^.]*/.exec(file)![0]; describe(`${describeName}`, () => { for (const { name, run } of fileTests( fs.readFileSync(path.join(caseDir, file), 'utf8'), file, )) { it(`${name}`, () => { try { run(graphqlLanguage.parser); } catch (err) { require('node:console').log(name, err); throw err; } }); } }); } }); ================================================ FILE: packages/cm6-graphql/__tests__/types.txt ================================================ # String { test(v1: "abc") } ==> Document(OperationDefinition(SelectionSet("{",Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,StringValue),")"))),"}"))) # Enum { test(v1: ABC) } ==> Document(OperationDefinition(SelectionSet("{",Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,EnumValue),")"))),"}"))) # Numbers { test(v1: 123) } { test(v1: 123.01) } { test(v1: -1.35384e+3) } ==> Document( OperationDefinition(SelectionSet("{",Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,IntValue),")"))),"}")), OperationDefinition(SelectionSet("{",Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,FloatValue),")"))),"}")), OperationDefinition(SelectionSet("{",Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,FloatValue),")"))),"}")) ) # List { test(v1: []) } { test(v1: ["abc", "def"]) } { test(v1: ["abc", ABC, 123, 213.01, true, null]) } ==> Document( OperationDefinition(SelectionSet("{",Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,ListValue("[","]")),")"))),"}")), OperationDefinition(SelectionSet("{",Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,ListValue("[",StringValue,StringValue,"]")),")"))),"}")), OperationDefinition(SelectionSet("{",Selection(Field(FieldName,Arguments("(",Argument(ArgumentAttributeName,ListValue("[",StringValue,EnumValue,IntValue,FloatValue,BooleanValue,NullValue,"]")),")"))),"}")) ) ================================================ FILE: packages/cm6-graphql/package.json ================================================ { "name": "cm6-graphql", "version": "0.2.1", "description": "GraphQL language support for CodeMirror 6", "scripts": { "types:check": "tsc --noEmit", "build": "cm-buildhelper src/index.ts", "prepare": "yarn build", "test": "vitest run" }, "main": "dist/index.cjs", "module": "dist/index.js", "exports": { "import": "./dist/index.js", "require": "./dist/index.cjs" }, "types": "dist/index.d.ts", "sideEffects": false, "dependencies": { "graphql-language-service": "^5.3.0" }, "devDependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/buildhelper": "^0.1.16", "@codemirror/language": "^6.0.0", "@codemirror/lint": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@lezer/common": "^1.0.0", "@lezer/generator": "^1.1.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0", "graphql": "^16.9.0", "typescript": "^4.6.3" }, "peerDependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/lint": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@lezer/highlight": "^1.0.0", "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0" }, "license": "MIT" } ================================================ FILE: packages/cm6-graphql/src/commands.ts ================================================ import { EditorView } from '@codemirror/view'; import { getTokenAtPosition, getTypeInfo } from 'graphql-language-service'; import { offsetToPos } from './helpers'; import { getOpts, getSchema } from './state'; export const fillAllFieldsCommands = (view: EditorView) => { const schema = getSchema(view.state); if (!schema) { return true; } const opts = getOpts(view.state); const currentPosition = view.state.selection.main.head; const pos = offsetToPos(view.state.doc, currentPosition); const token = getTokenAtPosition(view.state.doc.toString(), pos); if (schema && opts?.onFillAllFields) { opts.onFillAllFields(view, schema, view.state.doc.toString(), pos, token); } return true; }; export const showInDocsCommand = (view: EditorView) => { const schema = getSchema(view.state); if (!schema) { return true; } const opts = getOpts(view.state); const currentPosition = view.state.selection.main.head; const pos = offsetToPos(view.state.doc, currentPosition); const token = getTokenAtPosition(view.state.doc.toString(), pos); if (schema && opts?.onShowInDocs) { const tInfo = getTypeInfo(schema, token.state); opts.onShowInDocs( tInfo.fieldDef?.name, tInfo.type?.toString(), tInfo.parentType?.toString(), ); } return true; }; ================================================ FILE: packages/cm6-graphql/src/completions.ts ================================================ import { Completion, CompletionContext } from '@codemirror/autocomplete'; import { getAutocompleteSuggestions } from 'graphql-language-service'; import { getOpts, getSchema } from './state'; import { offsetToPos } from './helpers'; import { graphqlLanguage } from './language'; const AUTOCOMPLETE_CHARS = /^[a-zA-Z0-9_@(]$/; export const completion = graphqlLanguage.data.of({ autocomplete(ctx: CompletionContext) { const schema = getSchema(ctx.state); const opts = getOpts(ctx.state); if (!schema) { return null; } const word = ctx.matchBefore(/\w*/); if (!word) { return null; } const lastWordChar = word.text.split('').pop()!; if (!AUTOCOMPLETE_CHARS.test(lastWordChar) && !ctx.explicit) { return null; } const val = ctx.state.doc.toString(); const pos = offsetToPos(ctx.state.doc, ctx.pos); const results = getAutocompleteSuggestions( schema, val, pos, undefined, undefined, opts?.autocompleteOptions, ); if (results.length === 0) { return null; } return { from: word.from, options: results.map(item => { return { label: item.label, detail: item.detail || '', info(completionData: Completion) { if (opts?.onCompletionInfoRender) { return opts.onCompletionInfoRender(item, ctx, completionData); } if ( item.documentation || (item.isDeprecated && item.deprecationReason) ) { const el = document.createElement('div'); el.textContent = item.documentation || item.deprecationReason || ''; return el; } }, }; }), }; }, }); ================================================ FILE: packages/cm6-graphql/src/graphql.ts ================================================ import { Extension } from '@codemirror/state'; import { GraphQLSchema } from 'graphql'; import { completion } from './completions'; import { GqlExtensionsOptions } from './interfaces'; import { jump } from './jump'; import { graphqlLanguageSupport } from './language'; import { lint } from './lint'; import { stateExtensions } from './state'; export function graphql( schema?: GraphQLSchema, opts?: GqlExtensionsOptions, ): Extension[] { return [ graphqlLanguageSupport(), completion, lint, jump, stateExtensions(schema, opts), ]; } ================================================ FILE: packages/cm6-graphql/src/helpers.ts ================================================ import { Text } from '@codemirror/state'; export function posToOffset(doc: Text, pos: IPosition) { return doc.line(pos.line + 1).from + pos.character; } export function offsetToPos(doc: Text, offset: number): Position { const line = doc.lineAt(offset); return new Position(line.number - 1, offset - line.from); } export interface IPosition { line: number; character: number; setLine(line: number): void; setCharacter(character: number): void; lessThanOrEqualTo(position: IPosition): boolean; } export class Position implements IPosition { constructor( public line: number, public character: number, ) {} setLine(line: number) { this.line = line; } setCharacter(character: number) { this.character = character; } lessThanOrEqualTo(position: IPosition) { return ( this.line < position.line || (this.line === position.line && this.character <= position.character) ); } } const isMac = () => navigator.userAgent.includes('Mac'); export const isMetaKeyPressed = (e: MouseEvent) => isMac() ? e.metaKey : e.ctrlKey; ================================================ FILE: packages/cm6-graphql/src/index.ts ================================================ export * from './commands'; export * from './completions'; export * from './graphql'; export * from './helpers'; export * from './jump'; export * from './language'; export * from './lint'; export * from './state'; ================================================ FILE: packages/cm6-graphql/src/interfaces.ts ================================================ import { Completion, CompletionContext } from '@codemirror/autocomplete'; import { EditorView } from '@codemirror/view'; import { GraphQLSchema } from 'graphql'; import { ContextToken, CompletionItem, AutocompleteSuggestionOptions, } from 'graphql-language-service'; import { Position } from './helpers'; export interface GqlExtensionsOptions { showErrorOnInvalidSchema?: boolean; onShowInDocs?: (field?: string, type?: string, parentType?: string) => void; onFillAllFields?: ( view: EditorView, schema: GraphQLSchema, query: string, cursor: Position, token: ContextToken, ) => void; onCompletionInfoRender?: ( gqlCompletionItem: CompletionItem, ctx: CompletionContext, item: Completion, ) => Node | Promise | null; autocompleteOptions?: AutocompleteSuggestionOptions; } ================================================ FILE: packages/cm6-graphql/src/jump.ts ================================================ import { EditorView } from '@codemirror/view'; import { getTokenAtPosition, getTypeInfo } from 'graphql-language-service'; import { isMetaKeyPressed, offsetToPos } from './helpers'; import { getOpts, getSchema } from './state'; export const jump = EditorView.domEventHandlers({ click(evt, view) { const schema = getSchema(view.state); if (!schema) { return; } // TODO: Set class on cm-editor when mod key is pressed, to style cursor and tokens const currentPosition = view.state.selection.main.head; const pos = offsetToPos(view.state.doc, currentPosition); const token = getTokenAtPosition(view.state.doc.toString(), pos); const tInfo = getTypeInfo(schema, token.state); const opts = getOpts(view.state); if (opts?.onShowInDocs && isMetaKeyPressed(evt)) { opts.onShowInDocs( tInfo.fieldDef?.name, tInfo.type?.toString(), tInfo.parentType?.toString(), ); } }, }); ================================================ FILE: packages/cm6-graphql/src/language.ts ================================================ import { parser } from './syntax.grammar'; import { LRLanguage, LanguageSupport, indentNodeProp, foldNodeProp, foldInside, delimitedIndent, } from '@codemirror/language'; import { styleTags, tags as t } from '@lezer/highlight'; const nodesWithBraces = 'RootTypeDefinition InputFieldsDefinition EnumValuesDefinition FieldsDefinition SelectionSet { }'; const keywords = 'scalar type interface union enum input implements fragment extend schema directive on repeatable'; const punctuations = '( ) { } : [ ]'; export const graphqlLanguage = LRLanguage.define({ parser: parser.configure({ props: [ styleTags({ Variable: t.variableName, BooleanValue: t.bool, Description: t.string, StringValue: t.string, Comment: t.lineComment, IntValue: t.integer, FloatValue: t.float, EnumValue: t.special(t.name), NullValue: t.null, DirectiveName: t.modifier, [keywords]: t.keyword, OperationType: t.definitionKeyword, FieldName: t.propertyName, Field: t.propertyName, ArgumentAttributeName: t.attributeName, Name: t.atom, '( )': t.paren, '{ }': t.brace, ',': t.separator, [punctuations]: t.punctuation, }), // https://codemirror.net/docs/ref/#language.indentNodeProp indentNodeProp.add({ [nodesWithBraces]: delimitedIndent({ closing: '}', align: true }), }), foldNodeProp.add({ [nodesWithBraces]: foldInside, }), ], }), languageData: { commentTokens: { line: '#' }, indentOnInput: /^\s*(\{|\})$/, }, }); export function graphqlLanguageSupport() { return new LanguageSupport(graphqlLanguage); } ================================================ FILE: packages/cm6-graphql/src/lint.ts ================================================ import { Diagnostic, linter } from '@codemirror/lint'; import { getDiagnostics } from 'graphql-language-service'; import { Position, posToOffset } from './helpers'; import { getOpts, getSchema, optionsStateField, schemaStateField, } from './state'; import { Extension } from '@codemirror/state'; import { validateSchema } from 'graphql'; const SEVERITY = ['error', 'warning', 'info'] as const; export const lint: Extension = linter( view => { const schema = getSchema(view.state); const options = getOpts(view.state); if (!schema) { return []; } const validationErrors = validateSchema(schema); if (validationErrors.length) { if (!options?.showErrorOnInvalidSchema) { return []; } const combinedError = validationErrors.map(error => { return error.message; }); return [ { from: 0, to: view.state.doc.length, severity: 'error', message: combinedError.join('\n'), actions: [], // TODO: }, ]; } const results = getDiagnostics(view.state.doc.toString(), schema); return results .map((item): Diagnostic | null => { if (!item.severity || !item.source) { return null; } const calculatedFrom = posToOffset( view.state.doc, new Position(item.range.start.line, item.range.start.character), ); const from = Math.max( 0, Math.min(calculatedFrom, view.state.doc.length), ); const calculatedRo = posToOffset( view.state.doc, new Position(item.range.end.line, item.range.end.character - 1), ); const to = Math.min( Math.max(from + 1, calculatedRo), view.state.doc.length, ); return { from, to: from === to ? to + 1 : to, severity: SEVERITY[item.severity - 1], // source: item.source, // TODO: message: item.message, actions: [], // TODO: }; }) .filter((_): _ is Diagnostic => Boolean(_)); }, { needsRefresh(vu) { return ( vu.startState.field(schemaStateField) !== vu.state.field(schemaStateField) || vu.startState.field(optionsStateField) !== vu.state.field(optionsStateField) ); }, }, ); ================================================ FILE: packages/cm6-graphql/src/state.ts ================================================ import { EditorState, StateField, StateEffect } from '@codemirror/state'; import { EditorView } from '@codemirror/view'; import { GraphQLSchema } from 'graphql'; import { GqlExtensionsOptions } from './interfaces'; const schemaEffect = StateEffect.define(); export const schemaStateField = StateField.define({ create() {}, update(schema, tr) { for (const e of tr.effects) { if (e.is(schemaEffect)) { return e.value; } } return schema; }, }); const optionsEffect = StateEffect.define(); export const optionsStateField = StateField.define( { create() {}, update(opts, tr) { for (const e of tr.effects) { if (e.is(optionsEffect)) { return e.value; } } return opts; }, }, ); export const updateSchema = (view: EditorView, schema?: GraphQLSchema) => { view.dispatch({ effects: schemaEffect.of(schema), }); }; export const updateOpts = (view: EditorView, opts?: GqlExtensionsOptions) => { view.dispatch({ effects: optionsEffect.of(opts), }); }; export const getSchema = (state: EditorState) => { return state.field(schemaStateField); }; export const getOpts = (state: EditorState) => { return state.field(optionsStateField); }; const defaultOpts: GqlExtensionsOptions = { showErrorOnInvalidSchema: true, }; export const stateExtensions = ( schema?: GraphQLSchema, opts?: GqlExtensionsOptions, ) => [ schemaStateField.init(() => schema), optionsStateField.init(() => ({ ...defaultOpts, ...opts })), ]; ================================================ FILE: packages/cm6-graphql/src/syntax.grammar ================================================ // https://spec.graphql.org/October2021/#sec-Document-Syntax // https://github.com/antlr/grammars-v4/blob/49469cb6906f4514be3c04ac0c61c78bc5a6e35a/graphql/GraphQL.g4 @precedence { vDef } @skip { whitespace | Comment } // https://spec.graphql.org/October2021/#Document @top Document { definition+ } // https://spec.graphql.org/October2021/#Definition definition { executableDefinition | typeSystemDefinitionOrExtension } // https://spec.graphql.org/October2021/#TypeSystemDefinitionOrExtension typeSystemDefinitionOrExtension { TypeSystemDefinition | TypeSystemExtension } // https://spec.graphql.org/October2021/#TypeSystemExtension TypeSystemExtension { SchemaExtension | TypeExtension } // https://spec.graphql.org/October2021/#SchemaExtension SchemaExtension { ExtendKeyword SchemaKeyword Directives? RootTypeDefinition | ExtendKeyword SchemaKeyword Directives } // https://spec.graphql.org/October2021/#TypeExtension TypeExtension { ScalarTypeExtension | ObjectTypeExtension | InterfaceTypeExtension | UnionTypeExtension | EnumTypeExtension | InputObjectTypeExtension } // https://spec.graphql.org/October2021/#ScalarTypeExtension ScalarTypeExtension { ExtendKeyword ScalarKeyword Name Directives } // https://spec.graphql.org/October2021/#ObjectTypeExtension ObjectTypeExtension { ExtendKeyword TypeKeyword Name ImplementsInterfaces? Directives? FieldsDefinition | ExtendKeyword TypeKeyword Name ImplementsInterfaces? Directives | ExtendKeyword TypeKeyword Name ImplementsInterfaces } // https://spec.graphql.org/October2021/#InterfaceTypeExtension InterfaceTypeExtension { ExtendKeyword InterfaceKeyword Name ImplementsInterfaces? Directives? FieldsDefinition | ExtendKeyword InterfaceKeyword Name ImplementsInterfaces? Directives | ExtendKeyword InterfaceKeyword Name ImplementsInterfaces } // https://spec.graphql.org/October2021/#UnionTypeExtension UnionTypeExtension { ExtendKeyword UnionKeyword Name Directives? UnionMemberTypes | ExtendKeyword UnionKeyword Name Directives } // https://spec.graphql.org/October2021/#EnumTypeExtension EnumTypeExtension { ExtendKeyword EnumKeyword Name Directives? EnumValuesDefinition | ExtendKeyword EnumKeyword Name Directives } // https://spec.graphql.org/October2021/#InputObjectTypeExtension InputObjectTypeExtension { ExtendKeyword InputKeyword Name Directives? InputFieldsDefinition | ExtendKeyword InputKeyword Name Directives } // https://spec.graphql.org/October2021/#ExecutableDefinition executableDefinition { OperationDefinition | FragmentDefinition } // https://spec.graphql.org/October2021/#OperationDefinition OperationDefinition { OperationType Name? VariableDefinitions? Directives? SelectionSet | SelectionSet } // https://spec.graphql.org/October2021/#TypeSystemDefinition TypeSystemDefinition { SchemaDefinition | TypeDefinition | DirectiveDefinition } // https://spec.graphql.org/October2021/#SchemaDefinition SchemaDefinition { Description? SchemaKeyword Directives? RootTypeDefinition } RootTypeDefinition { scopedBraces } // https://spec.graphql.org/October2021/#Description Description { StringValue } // https://spec.graphql.org/October2021/#RootOperationTypeDefinition RootOperationTypeDefinition { OperationType ":" NamedType } // https://spec.graphql.org/October2021/#TypeDefinition TypeDefinition { ScalarTypeDefinition | ObjectTypeDefinition | InterfaceTypeDefinition | UnionTypeDefinition | EnumTypeDefinition | InputObjectTypeDefinition } // https://spec.graphql.org/October2021/#DirectiveDefinition DirectiveDefinition { Description? DirectiveKeyword DirectiveName ArgumentsDefinition? RepeatableKeyword? OnKeyword DirectiveLocations } // https://spec.graphql.org/October2021/#DirectiveLocations DirectiveLocations { DirectiveLocations "|" DirectiveLocation | "|"? DirectiveLocation } // https://spec.graphql.org/October2021/#DirectiveLocation DirectiveLocation { ExecutableDirectiveLocation | TypeSystemDirectiveLocation } ExecutableDirectiveLocation { "QUERY" | "MUTATION" | "SUBSCRIPTION" | "FIELD" | "FRAGMENT_DEFINITION" | "FRAGMENT_SPREAD" | "INLINE_FRAGMENT" | "VARIABLE_DEFINITION" } TypeSystemDirectiveLocation { "SCHEMA" | "SCALAR" | "OBJECT" | "FIELD_DEFINITION" | "ARGUMENT_DEFINITION" | "INTERFACE" | "UNION" | "ENUM" | "ENUM_VALUE" | "INPUT_OBJECT" | "INPUT_FIELD_DEFINITION" } // https://spec.graphql.org/October2021/#ScalarTypeDefinition ScalarTypeDefinition { Description ScalarKeyword Name Directives? } // https://spec.graphql.org/October2021/#ObjectTypeDefinition ObjectTypeDefinition { Description? TypeKeyword Name ImplementsInterfaces? Directives? FieldsDefinition? } // https://spec.graphql.org/October2021/#InterfaceTypeDefinition InterfaceTypeDefinition { Description? InterfaceKeyword Name ImplementsInterfaces? Directives? FieldsDefinition? } // https://spec.graphql.org/October2021/#UnionTypeDefinition UnionTypeDefinition { Description? UnionKeyword Name Directives? UnionMemberTypes? } // https://spec.graphql.org/October2021/#EnumTypeDefinition EnumTypeDefinition { Description? EnumKeyword Name Directives? EnumValuesDefinition? } // https://spec.graphql.org/October2021/#InputObjectTypeDefinition InputObjectTypeDefinition { Description? InputKeyword Name Directives? InputFieldsDefinition? } // https://spec.graphql.org/October2021/#InputFieldsDefinition InputFieldsDefinition { scopedBraces } // https://spec.graphql.org/October2021/#EnumValuesDefinition EnumValuesDefinition { scopedBraces } // https://spec.graphql.org/October2021/#EnumValueDefinition EnumValueDefinition { Description? EnumValue Directives? } // https://spec.graphql.org/October2021/#UnionMemberTypes UnionMemberTypes { UnionMemberTypes "|" NamedType | "=" "|"? NamedType } // https://spec.graphql.org/October2021/#ImplementsInterfaces ImplementsInterfaces { ImplementsInterfaces "&" NamedType | ImplementsKeyword "&"? NamedType } // https://spec.graphql.org/October2021/#FieldsDefinition FieldsDefinition { scopedBraces } // https://spec.graphql.org/October2021/#FieldDefinition FieldDefinition { Description? Name ArgumentsDefinition? ":" type Directives? } // https://spec.graphql.org/October2021/#ArgumentsDefinition ArgumentsDefinition { InputValueDefinition+ } // https://spec.graphql.org/October2021/#InputValueDefinition InputValueDefinition { Description? Name ":" type DefaultValue? Directives? } // https://spec.graphql.org/October2021/#FragmentDefinition FragmentDefinition { FragmentKeyword FragmentName TypeCondition Directives? SelectionSet } // https://spec.graphql.org/October2021/#FragmentSpread FragmentSpread { "..." FragmentName Directives? } // https://spec.graphql.org/October2021/#FragmentName FragmentName { Name // TODO: not `on` } // https://spec.graphql.org/October2021/#InlineFragment InlineFragment { "..." TypeCondition? Directives? SelectionSet } // https://spec.graphql.org/October2021/#TypeCondition TypeCondition { OnKeyword NamedType } // https://spec.graphql.org/October2021/#OperationType OperationType { operation<"query"> | operation<"mutation"> | operation<"subscription"> } // https://spec.graphql.org/October2021/#VariableDefinitions VariableDefinitions { "(" VariableDefinition+ ")" } // TODO: Directives[Const] // https://spec.graphql.org/October2021/#VariableDefinition VariableDefinition { Variable ":" type DefaultValue? Directives? comma? } // https://spec.graphql.org/October2021/#Type type { NamedType | ListType | NonNullType } // https://spec.graphql.org/October2021/#NamedType NamedType { Name } // https://spec.graphql.org/October2021/#ListType ListType { "[" type "]" } // https://spec.graphql.org/October2021/#NonNullType NonNullType { NamedType "!" | ListType "!" } // https://spec.graphql.org/October2021/#Directives Directives { Directive+ } // https://spec.graphql.org/October2021/#Directive Directive { DirectiveName Arguments? } // https://spec.graphql.org/October2021/#Arguments Arguments { "(" Argument+ ")"} // https://spec.graphql.org/October2021/#Argument Argument { ArgumentAttributeName ":" value comma? } ArgumentAttributeName { name } // https://spec.graphql.org/October2021/#SelectionSet SelectionSet { "{" Selection+ "}" } // https://spec.graphql.org/October2021/#Selection Selection { (Field | FragmentSpread | InlineFragment) comma? } // https://spec.graphql.org/October2021/#Field Field { Alias? FieldName Arguments? Directives? SelectionSet? } FieldName { name } // https://spec.graphql.org/October2021/#Alias Alias { Name ":" } // TODO: Value[Const] // https://spec.graphql.org/October2021/#DefaultValue DefaultValue { "=" value } // https://spec.graphql.org/October2021/#Value value { Variable | // TODO: [if not Const] IntValue | FloatValue | StringValue | BooleanValue | NullValue | EnumValue | ListValue | // TODO: [?Const] ObjectValue // TODO: [?Const] } // https://spec.graphql.org/October2021/#ListValue ListValue { "[" (value comma?)* "]" } // TODO: ObjectField[Const] // https://spec.graphql.org/October2021/#ObjectValue ObjectValue { "{" objectField* "}" } // https://spec.graphql.org/October2021/#ObjectField objectField { Name ":" value comma? } Name { name } @tokens { @precedence { FloatValue, IntValue } @precedence { NullValue, EnumValue } @precedence { BooleanValue, EnumValue } DirectiveName { "@" name } // https://spec.graphql.org/October2021/#Variable Variable { "$" name } // https://spec.graphql.org/October2021/#IntValue IntValue { "-"? @digit+ } // https://spec.graphql.org/October2021/#FloatValue FloatValue { IntValue fractionalPart exponentPart | IntValue fractionalPart | IntValue exponentPart } fractionalPart { "." @digit+ } exponentPart { $[eE] $[+\-]? @digit+ } // https://spec.graphql.org/October2021/#StringValue StringValue { '"' stringCharacter* '"' | '"""' blockStringCharacter* '"""' } // https://spec.graphql.org/October2021/#StringCharacter stringCharacter { !["\\\r\n] | "\\u" escapedUnicode | "\\" escapedCharacter } // https://spec.graphql.org/October2021/#BlockStringCharacter blockStringCharacter { '\\"""' | '"' '"'? !["] | stringCharacter | '\n' | '\r\n' } // https://spec.graphql.org/October2021/#EscapedUnicode escapedUnicode { $[0-9A-Fa-f] $[0-9A-Fa-f] $[0-9A-Fa-f] $[0-9A-Fa-f] } // https://spec.graphql.org/October2021/#EscapedCharacter escapedCharacter { "\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t"} // https://spec.graphql.org/October2021/#BooleanValue BooleanValue { "true" | "false" } // https://spec.graphql.org/October2021/#NullValue NullValue { "null" } // TODO: Value but not true or false or null // https://spec.graphql.org/October2021/#EnumValue EnumValue { name } // https://spec.graphql.org/October2021/#Name name { $[_A-Za-z] $[_0-9A-Za-z]* } // Name { name } Comment { "#" ![\n]* } "{" "}" "(" ")" "[" "]" comma { "," } whitespace { @whitespace+ } } scopedBraces { !vDef "{" expr "}" } // keywords kw { @specialize[@name={term}] } operation { @extend } ScalarKeyword { kw<"scalar"> } TypeKeyword { kw<"type"> } InterfaceKeyword { kw<"interface"> } UnionKeyword { kw<"union"> } EnumKeyword { kw<"enum"> } InputKeyword { kw<"input"> } ImplementsKeyword { kw<"implements"> } FragmentKeyword { kw<"fragment"> } ExtendKeyword { kw<"extend"> } SchemaKeyword { kw<"schema"> } DirectiveKeyword { kw<"directive"> } OnKeyword { kw<"on"> } RepeatableKeyword { kw<"repeatable"> } @detectDelim ================================================ FILE: packages/cm6-graphql/src/syntax.grammar.d.ts ================================================ import { LRParser } from '@lezer/lr'; export declare const parser: LRParser; ================================================ FILE: packages/cm6-graphql/tsconfig.esm.json ================================================ { "extends": "../../resources/tsconfig.base.esm.json", "compilerOptions": { "strict": true, "newLine": "lf", "outDir": "dist" }, "include": ["src/*.ts"], "references": [ { "path": "../graphql-language-service" } ] } ================================================ FILE: packages/cm6-graphql/tsconfig.json ================================================ { "extends": "../../resources/tsconfig.base.cjs.json", "compilerOptions": { "strict": true, "target": "es6", "module": "es2020", "newLine": "lf", "declaration": true, "moduleResolution": "node", "outDir": "dist" }, "include": ["src", "__tests__"], "exclude": ["**/__tests__/**", "**/dist/**.*"], "references": [ { "path": "../graphql-language-service" } ] } ================================================ FILE: packages/codemirror-graphql/.npmignore ================================================ babel.config.js .gitignore resources src ================================================ FILE: packages/codemirror-graphql/CHANGELOG.md ================================================ # Change Log ## 2.2.4 ### Patch Changes - Updated dependencies [[`3a0a755`](https://github.com/graphql/graphiql/commit/3a0a75569c6b318f5dc27d62000bcc9b0536c6fd)]: - graphql-language-service@5.5.0 ## 2.2.3 ### Patch Changes - [#3949](https://github.com/graphql/graphiql/pull/3949) [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - prefer `getComputedStyle` over `window.getComputedStyle` ## 2.2.3-rc.0 ### Patch Changes - [#3949](https://github.com/graphql/graphiql/pull/3949) [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - prefer `getComputedStyle` over `window.getComputedStyle` ## 2.2.2 ### Patch Changes - Updated dependencies [[`9498dee`](https://github.com/graphql/graphiql/commit/9498deea7636fd82602f230b6b21c743ca5705a7)]: - graphql-language-service@5.4.0 ## 2.2.1 ### Patch Changes - [#3896](https://github.com/graphql/graphiql/pull/3896) [`1adc40c`](https://github.com/graphql/graphiql/commit/1adc40cc56dbf79296bb857156e6adce1c44dcbe) Thanks [@dimaMachina](https://github.com/dimaMachina)! - bump eslint, eslint-plugins and fix new warnings - Updated dependencies [[`1adc40c`](https://github.com/graphql/graphiql/commit/1adc40cc56dbf79296bb857156e6adce1c44dcbe)]: - graphql-language-service@5.3.1 ## 2.2.0 ### Minor Changes - [#3825](https://github.com/graphql/graphiql/pull/3825) [`7cdcabf`](https://github.com/graphql/graphiql/commit/7cdcabf9d401683e90c995476b187c6f8ea70f63) Thanks [@dimaMachina](https://github.com/dimaMachina)! - migrate `graphiql` from `jest` to `vitest` ## 2.1.1 ### Patch Changes - [#3751](https://github.com/graphql/graphiql/pull/3751) [`b8538d8`](https://github.com/graphql/graphiql/commit/b8538d87421edb086b32d4eb2e30a3f7d9d9e893) Thanks [@dimaMachina](https://github.com/dimaMachina)! - replace deprecated `navigator.platform` with `navigator.userAgent` fix placeholder `⌘ K` in doc explorer search input for non mac devices, replace by `Ctrl K` ## 2.1.0 ### Minor Changes - [#3682](https://github.com/graphql/graphiql/pull/3682) [`6c9f0df`](https://github.com/graphql/graphiql/commit/6c9f0df83ea4afe7fa59f84d83d59fba73dc3931) Thanks [@yaacovCR](https://github.com/yaacovCR)! - Support v17 of `graphql-js` from `17.0.0-alpha.2` forward. Includes support for the latest incremental delivery response format. For further details, see https://github.com/graphql/defer-stream-wg/discussions/69. ### Patch Changes - Updated dependencies [[`6c9f0df`](https://github.com/graphql/graphiql/commit/6c9f0df83ea4afe7fa59f84d83d59fba73dc3931)]: - graphql-language-service@5.3.0 ## 2.0.13 ### Patch Changes - [#3637](https://github.com/graphql/graphiql/pull/3637) [`fdec377`](https://github.com/graphql/graphiql/commit/fdec377f28ac0d918a219b78dfa2d8f0996ff84d) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update eslint plugins and fix errors - Updated dependencies [[`fdec377`](https://github.com/graphql/graphiql/commit/fdec377f28ac0d918a219b78dfa2d8f0996ff84d)]: - graphql-language-service@5.2.2 ## 2.0.12 ### Patch Changes - [#3521](https://github.com/graphql/graphiql/pull/3521) [`aa6dbbb4`](https://github.com/graphql/graphiql/commit/aa6dbbb45bf51c1966537640fbe5c4f375735c8d) Thanks [@acao](https://github.com/acao)! - Fixes several issues with Type System (SDL) completion across the ecosystem: - restores completion for object and input type fields when the document context is not detectable or parseable - correct top-level completions for either of the unknown, type system or executable definitions. this leads to mixed top level completions when the document is unparseable, but now you are not seemingly restricted to only executable top level definitions - `.graphqls` ad-hoc standard functionality remains, but is not required, as it is not part of the official spec, and the spec also allows mixed mode documents in theory, and this concept is required when the type is unknown - Updated dependencies [[`aa6dbbb4`](https://github.com/graphql/graphiql/commit/aa6dbbb45bf51c1966537640fbe5c4f375735c8d)]: - graphql-language-service@5.2.1 ## 2.0.11 ### Patch Changes - [#3567](https://github.com/graphql/graphiql/pull/3567) [`fc7de5a7`](https://github.com/graphql/graphiql/commit/fc7de5a75f4b23dd62dd630b705895b5fa5d0a03) Thanks [@retrodaredevil](https://github.com/retrodaredevil)! - tooltip a tag's click listener calls event.preventDefault() to stop navigating away from page ## 2.0.10 ### Patch Changes - Updated dependencies [[`7b00774a`](https://github.com/graphql/graphiql/commit/7b00774affad1f25253ce49f1f48c9e3f372808c), [`7b00774a`](https://github.com/graphql/graphiql/commit/7b00774affad1f25253ce49f1f48c9e3f372808c)]: - graphql-language-service@5.2.0 ## 2.0.9 ### Patch Changes - [#3203](https://github.com/graphql/graphiql/pull/3203) [`61986469`](https://github.com/graphql/graphiql/commit/619864691941c46cc0b0848e8713028e20212c36) Thanks [@lesleydreyer](https://github.com/lesleydreyer)! - fix info tooltips to work when Graphiql is not used as full page - Updated dependencies [[`5971d528`](https://github.com/graphql/graphiql/commit/5971d528b0608e76d9d109103f64857a790a99b9), [`d9e5089f`](https://github.com/graphql/graphiql/commit/d9e5089f78f85cd50c3e3e3ba8510f7dda3d06f5)]: - graphql-language-service@5.1.7 ## 2.0.9-alpha.1 ### Patch Changes - Updated dependencies [[`5971d528`](https://github.com/graphql/graphiql/commit/5971d528b0608e76d9d109103f64857a790a99b9), [`d9e5089f`](https://github.com/graphql/graphiql/commit/d9e5089f78f85cd50c3e3e3ba8510f7dda3d06f5)]: - graphql-language-service@5.1.7-alpha.0 ## 2.0.9-alpha.0 ### Patch Changes - [#3203](https://github.com/graphql/graphiql/pull/3203) [`61986469`](https://github.com/graphql/graphiql/commit/619864691941c46cc0b0848e8713028e20212c36) Thanks [@lesleydreyer](https://github.com/lesleydreyer)! - fix info tooltips to work when Graphiql is not used as full page ## 2.0.8 ### Patch Changes - Updated dependencies [[`06007498`](https://github.com/graphql/graphiql/commit/06007498880528ed75dd4d705dcbcd7c9e775939)]: - graphql-language-service@5.1.6 ## 2.0.7 ### Patch Changes - Updated dependencies [[`4d33b221`](https://github.com/graphql/graphiql/commit/4d33b2214e941f171385a1b72a1fa995714bb284)]: - graphql-language-service@5.1.5 ## 2.0.6 ### Patch Changes - [#3113](https://github.com/graphql/graphiql/pull/3113) [`2e477eb2`](https://github.com/graphql/graphiql/commit/2e477eb24672a242ae4a4f2dfaeaf41152ed7ee9) Thanks [@B2o5T](https://github.com/B2o5T)! - replace `.forEach` with `for..of` - [#3109](https://github.com/graphql/graphiql/pull/3109) [`51007002`](https://github.com/graphql/graphiql/commit/510070028b7d8e98f2ba25f396519976aea5fa4b) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `no-floating-promises` eslint rule - Updated dependencies [[`2e477eb2`](https://github.com/graphql/graphiql/commit/2e477eb24672a242ae4a4f2dfaeaf41152ed7ee9)]: - graphql-language-service@5.1.4 ## 2.0.5 ### Patch Changes - [#3046](https://github.com/graphql/graphiql/pull/3046) [`b9c13328`](https://github.com/graphql/graphiql/commit/b9c13328f3d28c0026ee0f0ecc7213065c9b016d) Thanks [@B2o5T](https://github.com/B2o5T)! - Prefer .at() method for index access - Updated dependencies [[`b9c13328`](https://github.com/graphql/graphiql/commit/b9c13328f3d28c0026ee0f0ecc7213065c9b016d), [`881a2024`](https://github.com/graphql/graphiql/commit/881a202497d5a58eb5260a5aa54c0c88930d69a0)]: - graphql-language-service@5.1.3 ## 2.0.4 ### Patch Changes - [#2993](https://github.com/graphql/graphiql/pull/2993) [`bdc966cb`](https://github.com/graphql/graphiql/commit/bdc966cba6134a72ff7fe40f76543c77ba15d4a4) Thanks [@B2o5T](https://github.com/B2o5T)! - add `unicorn/consistent-destructuring` rule - [#2962](https://github.com/graphql/graphiql/pull/2962) [`db2a0982`](https://github.com/graphql/graphiql/commit/db2a0982a17134f0069483ab283594eb64735b7d) Thanks [@B2o5T](https://github.com/B2o5T)! - clean all ESLint warnings, add `--max-warnings=0` and `--cache` flags - [#2940](https://github.com/graphql/graphiql/pull/2940) [`8725d1b6`](https://github.com/graphql/graphiql/commit/8725d1b6b686139286cf05dec6a84d89942128ba) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `unicorn/prefer-node-protocol` rule - Updated dependencies [[`e68cb8bc`](https://github.com/graphql/graphiql/commit/e68cb8bcaf9baddf6fca747abab871ecd1bc7a4c), [`f788e65a`](https://github.com/graphql/graphiql/commit/f788e65aff267ec873237034831d1fd936222a9b), [`bdc966cb`](https://github.com/graphql/graphiql/commit/bdc966cba6134a72ff7fe40f76543c77ba15d4a4), [`db2a0982`](https://github.com/graphql/graphiql/commit/db2a0982a17134f0069483ab283594eb64735b7d), [`8725d1b6`](https://github.com/graphql/graphiql/commit/8725d1b6b686139286cf05dec6a84d89942128ba)]: - graphql-language-service@5.1.2 ## 2.0.3 ### Patch Changes - [#2931](https://github.com/graphql/graphiql/pull/2931) [`f7addb20`](https://github.com/graphql/graphiql/commit/f7addb20c4a558fbfb4112c8ff095bbc8f9d9147) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `no-negated-condition` and `no-else-return` rules - [#2922](https://github.com/graphql/graphiql/pull/2922) [`d1fcad72`](https://github.com/graphql/graphiql/commit/d1fcad72607e2789517dfe4936b5ec604e46762b) Thanks [@B2o5T](https://github.com/B2o5T)! - extends `plugin:import/recommended` and fix warnings - [#2941](https://github.com/graphql/graphiql/pull/2941) [`4a8b2e17`](https://github.com/graphql/graphiql/commit/4a8b2e1766a38eb4828cf9a81bf9d767070041de) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `unicorn/prefer-logical-operator-over-ternary` rule - [#2937](https://github.com/graphql/graphiql/pull/2937) [`c70d9165`](https://github.com/graphql/graphiql/commit/c70d9165cc1ef8eb1cd0d6b506ced98c626597f9) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `unicorn/prefer-includes` - [#2936](https://github.com/graphql/graphiql/pull/2936) [`18f8e80a`](https://github.com/graphql/graphiql/commit/18f8e80ae12edfd0c36adcb300cf9e06ac27ea49) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `lonely-if`/`unicorn/lonely-if` rules - [#2963](https://github.com/graphql/graphiql/pull/2963) [`f263f778`](https://github.com/graphql/graphiql/commit/f263f778cb95b9f413bd09ca56a43f5b9c2f6215) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `prefer-destructuring` rule - Updated dependencies [[`f7addb20`](https://github.com/graphql/graphiql/commit/f7addb20c4a558fbfb4112c8ff095bbc8f9d9147), [`d1fcad72`](https://github.com/graphql/graphiql/commit/d1fcad72607e2789517dfe4936b5ec604e46762b), [`4a8b2e17`](https://github.com/graphql/graphiql/commit/4a8b2e1766a38eb4828cf9a81bf9d767070041de), [`c70d9165`](https://github.com/graphql/graphiql/commit/c70d9165cc1ef8eb1cd0d6b506ced98c626597f9), [`c44ea4f1`](https://github.com/graphql/graphiql/commit/c44ea4f1917b97daac815c08299b934c8ca57ed9), [`0669767e`](https://github.com/graphql/graphiql/commit/0669767e1e2196a78cbefe3679a52bcbb341e913), [`18f8e80a`](https://github.com/graphql/graphiql/commit/18f8e80ae12edfd0c36adcb300cf9e06ac27ea49), [`f263f778`](https://github.com/graphql/graphiql/commit/f263f778cb95b9f413bd09ca56a43f5b9c2f6215), [`6a9d913f`](https://github.com/graphql/graphiql/commit/6a9d913f0d1b847124286b3fa1f3a2649d315171)]: - graphql-language-service@5.1.1 ## 2.0.2 ### Patch Changes - [#2852](https://github.com/graphql/graphiql/pull/2852) [`20869583`](https://github.com/graphql/graphiql/commit/20869583eff563f5d6494e93302a835f0e034f4b) Thanks [@acao](https://github.com/acao)! - increment @codemirror/language peer dependency to 6.0.0 ## 2.0.1 ### Patch Changes - [#2847](https://github.com/graphql/graphiql/pull/2847) [`353f434e`](https://github.com/graphql/graphiql/commit/353f434e5f6bfd1bf6f8ee97d4ae8ce4f897085f) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Don't show error in variable editor linting for missing input objects that have a default value ## 2.0.0 ### Major Changes - [#2694](https://github.com/graphql/graphiql/pull/2694) [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279) Thanks [@acao](https://github.com/acao)! - BREAKING: Change the implementation of the info popup when hovering items in the code editor: - For fields the type prefix was removed, i.e. `MyType.myField` -> `myField` - For args, the type and field was removed, i.e. `MyType.myField(myArg: MyArgType)` -> `myArg: MyArgType` - The DOM structure of the info tooltip changed to enable more flexible styling: - The first section (i.e. the clickable parts like type and field name) are wrapped in an additional div - The markdown content for deprecation reasons is wrapped in an additional div ## 1.3.3 ### Patch Changes - Updated dependencies [[`d6ff4d7a`](https://github.com/graphql/graphiql/commit/d6ff4d7a5d535a0c43fe5914016bac9ef0c2b782)]: - graphql-language-service@5.1.0 ## 1.3.2 ### Patch Changes - Updated dependencies [[`cccefa70`](https://github.com/graphql/graphiql/commit/cccefa70c0466d60e8496e1df61aeb1490af723c)]: - graphql-language-service@5.0.6 ## 1.3.1 ### Patch Changes - Updated dependencies [[`c9c51b8a`](https://github.com/graphql/graphiql/commit/c9c51b8a98e1f0427272d3e9ad60989b32f1a1aa)]: - graphql-language-service@5.0.5 ## 1.3.0 ### Minor Changes - [#2369](https://github.com/graphql/graphiql/pull/2369) [`2dec55f2`](https://github.com/graphql/graphiql/commit/2dec55f2c5e979cc7bb1adadff4fb063775b088c) Thanks [@sergeichestakov](https://github.com/sergeichestakov)! - Moved @codemirror/language to peer dependencies and upgraded to 0.20.0 ### Patch Changes - Updated dependencies [[`d22f6111`](https://github.com/graphql/graphiql/commit/d22f6111a60af25727d8dbc1058c79607df76af2)]: - graphql-language-service@5.0.4 ## 1.2.17 ### Patch Changes - Updated dependencies [[`45cbc759`](https://github.com/graphql/graphiql/commit/45cbc759c732999e8b1eb4714d6047ab77c17902)]: - graphql-language-service@5.0.3 ## 1.2.16 ### Patch Changes - Updated dependencies [[`c36504a8`](https://github.com/graphql/graphiql/commit/c36504a804d8cc54a5136340152999b4a1a2c69f)]: - graphql-language-service@5.0.2 ## 1.2.15 ### Patch Changes - [#2261](https://github.com/graphql/graphiql/pull/2261) [`261f2044`](https://github.com/graphql/graphiql/commit/261f2044066412e40f9962bef55295f7c9c35aec) Thanks [@acao](https://github.com/acao)! - Fix typescript path resolution bug in codemirror-graphql ## 1.2.14 ### Patch Changes - Updated dependencies [[`3626f8d5`](https://github.com/graphql/graphiql/commit/3626f8d5012ee77a39e984ae347396cb00fcc6fa), [`3626f8d5`](https://github.com/graphql/graphiql/commit/3626f8d5012ee77a39e984ae347396cb00fcc6fa)]: - graphql-language-service@5.0.1 ## 1.2.13 ### Patch Changes - Updated dependencies [[`2502a364`](https://github.com/graphql/graphiql/commit/2502a364b74dc754d92baa1579b536cf42139958)]: - graphql-language-service@5.0.0 ## 1.2.12 ### Patch Changes - Updated dependencies [[`484c0523`](https://github.com/graphql/graphiql/commit/484c0523cdd529f9e261d61a38616b6745075c7f), [`5852ba47`](https://github.com/graphql/graphiql/commit/5852ba47c720a2577817aed512bef9a262254f2c), [`48c5df65`](https://github.com/graphql/graphiql/commit/48c5df654e323cee3b8c57d7414247465235d1b5)]: - graphql-language-service@4.1.5 ## 1.2.11 ### Patch Changes - Updated dependencies []: - graphql-language-service@4.1.4 ## 1.2.10 ### Patch Changes - Updated dependencies [[`a44772d6`](https://github.com/graphql/graphiql/commit/a44772d6af97254c4f159ea7237e842a3e3719e8)]: - graphql-language-service@4.1.3 ## 1.2.9 ### Patch Changes - Updated dependencies [[`e20760fb`](https://github.com/graphql/graphiql/commit/e20760fbd95c13d6d549cba3faa15a59aee9a2c0)]: - graphql-language-service@4.1.2 ## 1.2.8 ### Patch Changes - [#2091](https://github.com/graphql/graphiql/pull/2091) [`ff9cebe5`](https://github.com/graphql/graphiql/commit/ff9cebe515a3539f85b9479954ae644dfeb68b63) Thanks [@acao](https://github.com/acao)! - Fix graphql 15 related issues. Should now build & test interchangeably. - Updated dependencies []: - graphql-language-service@4.1.1 ## 1.2.7 ### Patch Changes - Updated dependencies [[`0f1f90ce`](https://github.com/graphql/graphiql/commit/0f1f90ce8f4a25ddebdaf7a9ddbe136214aa64a3)]: - graphql-language-service@4.1.0 ## 1.2.6 ### Patch Changes - Updated dependencies [[`9df315b4`](https://github.com/graphql/graphiql/commit/9df315b44896efa313ed6744445fc8f9e702ebc3)]: - graphql-language-service@4.0.0 ## 1.2.5 ### Patch Changes - Updated dependencies [[`df57cd25`](https://github.com/graphql/graphiql/commit/df57cd2556302d6aa5dd140e7bee3f7bdab4deb1)]: - graphql-language-service@3.2.5 ## 1.2.4 ### Patch Changes - Updated dependencies []: - graphql-language-service@3.2.4 ## 1.2.3 ### Patch Changes - [`c42b145f`](https://github.com/graphql/graphiql/commit/c42b145fffeaefbd1103bc7addee1873e939bc83) [#2052](https://github.com/graphql/graphiql/pull/2052) Thanks [@imolorhe](https://github.com/imolorhe)! - Added cm6-legacy to published files list ## 1.2.2 ### Patch Changes - [`bdd57312`](https://github.com/graphql/graphiql/commit/bdd573129844168749aba0aaa20e31b9da81aacf) [#2047](https://github.com/graphql/graphiql/pull/2047) Thanks [@willstott101](https://github.com/willstott101)! - Source code included in all packages to fix source maps. codemirror-graphql includes esm build in package. * [`8b486555`](https://github.com/graphql/graphiql/commit/8b486555e2aa4d90891070a1bbc52b59d9c670c4) [#2046](https://github.com/graphql/graphiql/pull/2046) Thanks [@willstott101](https://github.com/willstott101)! - Further resolves #1944, replaces graphql-language-service-parser with graphql-language-service in codemirror-graphql * Updated dependencies [[`bdd57312`](https://github.com/graphql/graphiql/commit/bdd573129844168749aba0aaa20e31b9da81aacf)]: - graphql-language-service@3.2.3 ## 1.2.1 ### Patch Changes - [`858907d2`](https://github.com/graphql/graphiql/commit/858907d2106742a65ec52eb017f2e91268cc37bf) [#2045](https://github.com/graphql/graphiql/pull/2045) Thanks [@acao](https://github.com/acao)! - fix graphql-js peer dependencies - [#2044](https://github.com/graphql/graphiql/pull/2044) - Updated dependencies [[`858907d2`](https://github.com/graphql/graphiql/commit/858907d2106742a65ec52eb017f2e91268cc37bf)]: - graphql-language-service@3.2.2 ## 1.2.0 ### Minor Changes - [`d0c22c4f`](https://github.com/graphql/graphiql/commit/d0c22c4fce5ea39611c7ecee553943fdf27fd03e) [#2035](https://github.com/graphql/graphiql/pull/2035) Thanks [@imolorhe](https://github.com/imolorhe)! - Added Codemirror 6 legacy support ### Patch Changes - [`b79bf304`](https://github.com/graphql/graphiql/commit/b79bf304045add4b5c3b2539dd6b551a64e6ed87) [#2037](https://github.com/graphql/graphiql/pull/2037) Thanks [@acao](https://github.com/acao)! - Resolves #1944, replaces graphql-language-service-utils with graphql-language-service in codemirror-graphql ## 1.1.0 ### Minor Changes - [`716cf786`](https://github.com/graphql/graphiql/commit/716cf786aea6af42ea637ca3c56ae6c6ebc17c7a) [#2010](https://github.com/graphql/graphiql/pull/2010) Thanks [@acao](https://github.com/acao)! - upgrade to `graphql@16.0.0-experimental-stream-defer.5`. thanks @saihaj! ### Patch Changes - Updated dependencies [[`8869c4b1`](https://github.com/graphql/graphiql/commit/8869c4b18c900b9b35556255587ef5130a96a4d5), [`716cf786`](https://github.com/graphql/graphiql/commit/716cf786aea6af42ea637ca3c56ae6c6ebc17c7a)]: - graphql-language-service-interface@2.9.0 - graphql-language-service-parser@1.10.0 ## 1.0.3 ### Patch Changes - [`75dbb0b1`](https://github.com/graphql/graphiql/commit/75dbb0b18e2102d271a5cfe78faf54fe22e83ac8) [#1777](https://github.com/graphql/graphiql/pull/1777) Thanks [@dwwoelfel](https://github.com/dwwoelfel)! - adopt block string parsing for variables in language parser - Updated dependencies [[`75dbb0b1`](https://github.com/graphql/graphiql/commit/75dbb0b18e2102d271a5cfe78faf54fe22e83ac8)]: - graphql-language-service-parser@1.9.3 ## 1.0.2 ### Patch Changes - [`5b8a057d`](https://github.com/graphql/graphiql/commit/5b8a057dd64ebecc391be32176a2403bb9d9ff92) [#1838](https://github.com/graphql/graphiql/pull/1838) Thanks [@acao](https://github.com/acao)! - Set all cross-runtime build targets to es6 ## 1.0.1 ### Patch Changes - [`6869ce77`](https://github.com/graphql/graphiql/commit/6869ce7767050787db5f1017abf82fa5a52fc97a) [#1816](https://github.com/graphql/graphiql/pull/1816) Thanks [@acao](https://github.com/acao)! - improve peer resolutions for graphql 14 & 15. `14.5.0` minimum is for built-in typescript types, and another method only available in `14.4.0` ## 1.0.0 ### Major Changes - [`b4fc16c0`](https://github.com/graphql/graphiql/commit/b4fc16c025da6f466727dc17cab6026d14c6e7fe) Thanks [@imolorhe](https://github.com/imolorhe)! - BREAKING CHANGE Migrate to Typescript - [@imolorhe](https://github.com/imolorhe) All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. ## [0.15.2](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.15.1...codemirror-graphql@0.15.2) (2021-01-07) **Note:** Version bump only for package codemirror-graphql ## [0.15.1](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.15.0...codemirror-graphql@0.15.1) (2021-01-07) ### Bug Fixes - bug with externalFragments in codemirror ([#1751](https://github.com/graphql/graphiql/issues/1751)) ([f423e61](https://github.com/graphql/graphiql/commit/f423e615330bf8529f4068889d6760501b732527)) ## [0.15.0](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.14.0...codemirror-graphql@0.15.0) (2021-01-07) ### Features - implied or external fragments, for [#612](https://github.com/graphql/graphiql/issues/612) ([#1750](https://github.com/graphql/graphiql/issues/1750)) ([cfed265](https://github.com/graphql/graphiql/commit/cfed265e3cf31875b39ea517781a217fcdfcadc2)) ## [0.14.0](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.13.1...codemirror-graphql@0.14.0) (2021-01-03) ### Features - merge completion logic (for implements &, variables) ([#1747](https://github.com/graphql/graphiql/issues/1747)) ([0ac0a85](https://github.com/graphql/graphiql/commit/0ac0a856cfc715d7885a9965a9a9114ef2ca4b1a)) ## [0.13.1](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.13.0...codemirror-graphql@0.13.1) (2020-12-28) **Note:** Version bump only for package codemirror-graphql ## [0.13.0](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.4...codemirror-graphql@0.13.0) (2020-12-08) ### Features - provide validation rules via props ([#1716](https://github.com/graphql/graphiql/issues/1716)) ([0c5785c](https://github.com/graphql/graphiql/commit/0c5785c82adbd4affb25300ae2d128b42c9b81fe)) ## [0.12.4](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.3...codemirror-graphql@0.12.4) (2020-11-28) **Note:** Version bump only for package codemirror-graphql ## [0.12.3](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.2...codemirror-graphql@0.12.3) (2020-10-20) ### Bug Fixes - **codemirror-graphql:** give interface field name suggestions ([#1695](https://github.com/graphql/graphiql/issues/1695)) ([669b301](https://github.com/graphql/graphiql/commit/669b3013fc679eca7c4e5c8ed6b0cd2fb2dbf2dc)) ## [0.12.2](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.2-alpha.2...codemirror-graphql@0.12.2) (2020-09-18) **Note:** Version bump only for package codemirror-graphql ## [0.12.2-alpha.2](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.2-alpha.1...codemirror-graphql@0.12.2-alpha.2) (2020-09-11) **Note:** Version bump only for package codemirror-graphql ## [0.12.2-alpha.1](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.2-alpha.0...codemirror-graphql@0.12.2-alpha.1) (2020-08-12) **Note:** Version bump only for package codemirror-graphql ## [0.12.2-alpha.0](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.1...codemirror-graphql@0.12.2-alpha.0) (2020-08-10) **Note:** Version bump only for package codemirror-graphql ## [0.12.1](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.0...codemirror-graphql@0.12.1) (2020-08-06) **Note:** Version bump only for package codemirror-graphql ## [0.12.0](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.0-alpha.11...codemirror-graphql@0.12.0) (2020-06-11) ### Bug Fixes - value of documentation in completion list ([#1567](https://github.com/graphql/graphiql/issues/1567)) ([39c00a5](https://github.com/graphql/graphiql/commit/39c00a55d7af43ce4e57ad9b1d5cd55393beb0d0)) ## [0.12.0-alpha.11](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.0-alpha.10...codemirror-graphql@0.12.0-alpha.11) (2020-06-04) **Note:** Version bump only for package codemirror-graphql ## [0.12.0-alpha.10](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.0-alpha.9...codemirror-graphql@0.12.0-alpha.10) (2020-06-04) ### Bug Fixes - cleanup cache entry from lerna publish ([4a26218](https://github.com/graphql/graphiql/commit/4a2621808a1aea8b30d5d27b8d86a60bf2b44b01)) - make list type and non-nullable type available ([#902](https://github.com/graphql/graphiql/issues/902)) ([cea837f](https://github.com/graphql/graphiql/commit/cea837ff77c36dadb01b4302282821b00d7f5f2f)) ## [0.12.0-alpha.9](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.0-alpha.8...codemirror-graphql@0.12.0-alpha.9) (2020-05-28) **Note:** Version bump only for package codemirror-graphql ## [0.12.0-alpha.8](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.0-alpha.7...codemirror-graphql@0.12.0-alpha.8) (2020-05-17) **Note:** Version bump only for package codemirror-graphql ## [0.12.0-alpha.7](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.0-alpha.6...codemirror-graphql@0.12.0-alpha.7) (2020-04-10) **Note:** Version bump only for package codemirror-graphql ## [0.12.0-alpha.6](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.0-alpha.5...codemirror-graphql@0.12.0-alpha.6) (2020-04-10) **Note:** Version bump only for package codemirror-graphql ## [0.12.0-alpha.5](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.0-alpha.4...codemirror-graphql@0.12.0-alpha.5) (2020-04-06) ### Features - upgrade to graphql@15.0.0 for [#1191](https://github.com/graphql/graphiql/issues/1191) ([#1204](https://github.com/graphql/graphiql/issues/1204)) ([f13c8e9](https://github.com/graphql/graphiql/commit/f13c8e9d0e66df4b051b332c7d02f4bb83e07ffd)) ## [0.12.0-alpha.4](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.0-alpha.3...codemirror-graphql@0.12.0-alpha.4) (2020-04-03) **Note:** Version bump only for package codemirror-graphql ## [0.12.0-alpha.3](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.0-alpha.2...codemirror-graphql@0.12.0-alpha.3) (2020-03-20) **Note:** Version bump only for package codemirror-graphql ## [0.12.0-alpha.2](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.12.0-alpha.0...codemirror-graphql@0.12.0-alpha.2) (2020-03-20) **Note:** Version bump only for package codemirror-graphql ## [0.12.0-alpha.1](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.11.6...codemirror-graphql@0.12.0-alpha.1) (2020-01-18) ### Bug Fixes - linting issues, trailingCommas: all ([#1099](https://github.com/graphql/graphiql/issues/1099)) ([de4005b](https://github.com/graphql/graphiql/commit/de4005b)) - screenshot/gif urls ([e3ea2fc](https://github.com/graphql/graphiql/commit/e3ea2fc)) ### Features - convert LSP Server to Typescript, remove watchman ([#1138](https://github.com/graphql/graphiql/issues/1138)) ([8e33dbb](https://github.com/graphql/graphiql/commit/8e33dbb)) ## [0.11.6](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.11.5...codemirror-graphql@0.11.6) (2019-12-09) ### Bug Fixes - codemirror results bundle ([dd06eb5](https://github.com/graphql/graphiql/commit/dd06eb5)) ## [0.11.5](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.11.4...codemirror-graphql@0.11.5) (2019-12-09) ### Bug Fixes - a few more tweaks to babel ignore ([e0ad2c6](https://github.com/graphql/graphiql/commit/e0ad2c6)) ## [0.11.4](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.11.3...codemirror-graphql@0.11.4) (2019-12-03) ### Bug Fixes - convert browserify build to webpack, fixes [#976](https://github.com/graphql/graphiql/issues/976) ([#1001](https://github.com/graphql/graphiql/issues/1001)) ([3caf041](https://github.com/graphql/graphiql/commit/3caf041)) - csp headers violation [@gracenoah](https://github.com/gracenoah) graphql/codemirror-graphql[#246](https://github.com/graphql/graphiql/issues/246) ([#1044](https://github.com/graphql/graphiql/issues/1044)) ([3c9dfa5](https://github.com/graphql/graphiql/commit/3c9dfa5)) ## [0.11.3](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.11.2...codemirror-graphql@0.11.3) (2019-11-26) **Note:** Version bump only for package codemirror-graphql ## [0.11.2](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.11.1...codemirror-graphql@0.11.2) (2019-10-19) **Note:** Version bump only for package codemirror-graphql ## [0.11.1](https://github.com/graphql/graphiql/compare/codemirror-graphql@0.11.0...codemirror-graphql@0.11.1) (2019-10-04) ### Bug Fixes - build tweaks ([0bc6a7c](https://github.com/graphql/graphiql/commit/0bc6a7c)) # 0.11.0 (2019-10-04) ### Features - convert LSP from flow to typescript ([#957](https://github.com/graphql/graphiql/issues/957)) [@acao](https://github.com/acao) @Neitsch [@benjie](https://github.com/benjie) ([36ed669](https://github.com/graphql/graphiql/commit/36ed669)) # 0.10.0 (2019-10-04) ### Features - convert LSP from flow to typescript ([#957](https://github.com/graphql/graphiql/issues/957)) [@acao](https://github.com/acao) @Neitsch [@benjie](https://github.com/benjie) ([36ed669](https://github.com/graphql/graphiql/commit/36ed669)) ## 0.9.1-alpha.1 (2019-09-01) **Note:** Version bump only for package codemirror-graphql ## 0.9.1-alpha.0 (2019-09-01) **Note:** Version bump only for package codemirror-graphql ## 0.9.1 (2019-09-01) **Note:** Version bump only for package codemirror-graphql ================================================ FILE: packages/codemirror-graphql/LICENSE ================================================ MIT License Copyright (c) 2021 GraphQL Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/codemirror-graphql/README.md ================================================ # GraphQL mode for CodeMirror [![NPM](https://img.shields.io/npm/v/codemirror-graphql.svg?style=flat-square)](https://npmjs.com/codemirror-graphql) ![npm downloads](https://img.shields.io/npm/dm/codemirror-graphql?label=npm%20downloads) [![License](https://img.shields.io/npm/l/codemirror-graphql.svg?style=flat-square)](LICENSE) [Discord Channel](https://discord.gg/cffZwk8NJW) **NOTE: For CodeMirror 6, use [cm6-graphql](/packages/cm6-graphql/) instead** Provides CodeMirror with a parser mode for GraphQL along with a live linter and typeahead hinter powered by your GraphQL Schema. ![Demo .gif of GraphQL Codemirror Mode](https://raw.githubusercontent.com/graphql/graphiql/main/packages/codemirror-graphql/resources/example.gif) ### Getting Started ```sh npm install codemirror-graphql ``` CodeMirror helpers install themselves to the global CodeMirror when they are imported. ```ts import type { ValidationContext, SDLValidationContext } from 'graphql'; import CodeMirror from 'codemirror'; import 'codemirror/addon/hint/show-hint'; import 'codemirror/addon/lint/lint'; import 'codemirror-graphql/hint'; import 'codemirror-graphql/lint'; import 'codemirror-graphql/mode'; CodeMirror.fromTextArea(myTextarea, { mode: 'graphql', lint: { schema: myGraphQLSchema, validationRules: [ExampleRule], }, hintOptions: { schema: myGraphQLSchema, }, }); ``` ## External Fragments Example If you want to have autocompletion for external fragment definitions, there's a new configuration setting available ```ts import CodeMirror from 'codemirror'; import 'codemirror/addon/hint/show-hint'; import 'codemirror/addon/lint/lint'; import 'codemirror-graphql/hint'; import 'codemirror-graphql/lint'; import 'codemirror-graphql/mode'; const externalFragments = /* GraphQL */ ` fragment MyFragment on Example { id: ID! name: String! } fragment AnotherFragment on Example { id: ID! title: String! } `; CodeMirror.fromTextArea(myTextarea, { mode: 'graphql', lint: { schema: myGraphQLSchema, }, hintOptions: { schema: myGraphQLSchema, // here we use a string, but // you can also provide an array of FragmentDefinitionNodes externalFragments, }, }); ``` ### Custom Validation Rules If you want to show custom validation, you can do that too! It uses the `ValidationRule` interface. ```ts import type { ValidationRule } from 'graphql'; import CodeMirror from 'codemirror'; import 'codemirror/addon/hint/show-hint'; import 'codemirror/addon/lint/lint'; import 'codemirror-graphql/hint'; import 'codemirror-graphql/lint'; import 'codemirror-graphql/mode'; const ExampleRule: ValidationRule = context => { // your custom rules here const schema = context.getSchema(); const document = context.getDocument(); return { NamedType(node) { if (node.name.value !== node.name.value.toLowercase()) { context.reportError('only lowercase type names allowed!'); } }, }; }; CodeMirror.fromTextArea(myTextarea, { mode: 'graphql', lint: { schema: myGraphQLSchema, validationRules: [ExampleRule], }, hintOptions: { schema: myGraphQLSchema, }, }); ``` Build for the web with [webpack](http://webpack.github.io) or [browserify](http://browserify.org). ================================================ FILE: packages/codemirror-graphql/babel.config.js ================================================ module.exports = require('../../babel.config'); ================================================ FILE: packages/codemirror-graphql/package.json ================================================ { "name": "codemirror-graphql", "version": "2.2.4", "description": "GraphQL mode and helpers for CodeMirror.", "contributors": [ "Hyohyeon Jeong ", "Lee Byron (https://leebyron.com)", "Angel Gomez Salazar " ], "homepage": "https://github.com/graphql/graphiql/tree/main/packages/codemirror-graphql#readme", "repository": { "type": "git", "url": "https://github.com/graphql/graphiql", "directory": "packages/codemirror-graphql" }, "bugs": { "url": "https://github.com/graphql/graphiql/issues?q=issue+label:codemirror-graphql" }, "license": "MIT", "main": "index.js", "module": "esm/index.js", "files": [ "src", "cm6-legacy", "esm", "utils", "variables", "results", "/*.js", "/*.js.flow", "/*.js.map", "/*.d.ts", "/*.d.ts.map", "!babel.config.js", "!jest.config.js" ], "scripts": { "types:check": "tsc --noEmit", "build": "node ../../scripts/renameFileExtensions.js './esm/{**,!**/__tests__/}/*.js' . .esm.js", "test": "vitest" }, "peerDependencies": { "@codemirror/language": "6.0.0", "codemirror": "^5.65.3", "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0" }, "// TEMPORARILY PINNED until we fix graphql 15 support": "", "dependencies": { "@types/codemirror": "^0.0.90", "graphql-language-service": "5.5.0" }, "devDependencies": { "@codemirror/language": "^6.0.0", "codemirror": "^5.65.3", "cross-env": "^7.0.2", "graphql": "^16.9.0", "rimraf": "^3.0.2", "sane": "2.0.0" } } ================================================ FILE: packages/codemirror-graphql/resources/checkgit.sh ================================================ # # This script determines if current git state is the up to date main. If so # it exits normally. If not it prompts for an explicit continue. This script # intends to protect from versioning for NPM without first pushing changes # and including any changes on main. # # First fetch to ensure git is up to date. Fail-fast if this fails. git fetch; if [[ $? -ne 0 ]]; then exit 1; fi; # Extract useful information. GITBRANCH=$(git branch -v 2> /dev/null | sed '/^[^*]/d'); GITBRANCHNAME=$(echo "$GITBRANCH" | sed 's/* \([A-Za-z0-9_\-]*\).*/\1/'); GITBRANCHSYNC=$(echo "$GITBRANCH" | sed 's/* [^[]*.\([^]]*\).*/\1/'); # Check if main is checked out if [ "$GITBRANCHNAME" != "main" ]; then read -p "Git not on main but $GITBRANCHNAME. Continue? (y|N) " yn; if [ "$yn" != "y" ]; then exit 1; fi; fi; # Check if branch is synced with remote if [ "$GITBRANCHSYNC" != "" ]; then read -p "Git not up to date but $GITBRANCHSYNC. Continue? (y|N) " yn; if [ "$yn" != "y" ]; then exit 1; fi; fi; ================================================ FILE: packages/codemirror-graphql/setup-files.ts ================================================ // @ts-expect-error document.createRange = function () { return { setEnd() {}, setStart() {}, getClientRects() { return { top: 0, bottom: 0, left: 0, right: 0 }; }, getBoundingClientRect() { return { right: 0 }; }, }; }; ================================================ FILE: packages/codemirror-graphql/src/__tests__/hint.test.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import 'codemirror/addon/hint/show-hint'; import { GraphQLBoolean, GraphQLFloat, GraphQLID, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLString, __Schema, __Type, } from 'graphql'; import '../hint'; import type { GraphQLHintOptions, IHint, IHints } from '../hint'; import '../mode'; import { TestEnum, TestInputObject, TestSchema, TestType, TestUnion, UnionFirst, UnionSecond, } from './testSchema'; import { GraphQLDocumentMode } from 'graphql-language-service'; function createEditorWithHint() { return CodeMirror(document.createElement('div'), { mode: 'graphql', hintOptions: { schema: TestSchema, closeOnUnfocus: false, completeSingle: false, externalFragments: 'fragment Example on Test { id }', }, }); } function getHintSuggestions( queryString: string, cursor: CodeMirror.Position, opts?: GraphQLHintOptions, ) { const editor = createEditorWithHint(); return new Promise(resolve => { const graphqlHint = CodeMirror.hint.graphql; CodeMirror.hint.graphql = ( cm: CodeMirror.Editor, options: GraphQLHintOptions, ) => { const result = graphqlHint(cm, { ...opts, ...options }); resolve(result); CodeMirror.hint.graphql = graphqlHint; return result; }; editor.doc.setValue(queryString); editor.doc.setCursor(cursor); editor.execCommand('autocomplete'); }); } function getExpectedSuggestions(list: IHint[]) { return list.map(item => ({ text: item.text, type: item.type, description: item.description, isDeprecated: item.isDeprecated, deprecationReason: item.deprecationReason, })); } describe('graphql-hint', () => { it('attaches a GraphQL hint function with correct mode/hint options', () => { const editor = createEditorWithHint(); expect(editor.getHelpers(editor.getCursor(), 'hint')).not.toHaveLength(0); }); it('provides correct initial keywords for executable definitions', async () => { const suggestions = await getHintSuggestions( '', { line: 0, ch: 0 }, { autocompleteOptions: { mode: GraphQLDocumentMode.EXECUTABLE } }, ); const list = [ { text: 'query' }, { text: 'mutation' }, { text: 'subscription' }, { text: 'fragment' }, { text: '{' }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct initial keywords for unknown definitions', async () => { const suggestions = await getHintSuggestions('', { line: 0, ch: 0 }); const list = [ { text: 'extend' }, { text: 'query' }, { text: 'mutation' }, { text: 'subscription' }, { text: 'fragment' }, { text: '{' }, { text: 'type' }, { text: 'interface' }, { text: 'union' }, { text: 'input' }, { text: 'scalar' }, { text: 'schema' }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct initial keywords after filtered', async () => { const suggestions = await getHintSuggestions('q', { line: 0, ch: 1 }); const list = [{ text: '{' }, { text: 'query' }]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct field name suggestions', async () => { const suggestions = await getHintSuggestions('{ ', { line: 0, ch: 2 }); const list = [ { text: 'test', type: TestType, isDeprecated: false, }, { text: 'union', type: TestUnion, isDeprecated: false, }, { text: 'first', type: UnionFirst, isDeprecated: false, }, { text: 'id', type: GraphQLInt, isDeprecated: false, }, { text: 'isTest', type: GraphQLBoolean, isDeprecated: false, }, { text: 'hasArgs', type: GraphQLString, isDeprecated: false, }, { text: '__typename', type: new GraphQLNonNull(GraphQLString), description: 'The name of the current Object type at runtime.', isDeprecated: false, }, { text: '__schema', type: new GraphQLNonNull(__Schema), description: 'Access the current type schema of this server.', isDeprecated: false, }, { text: '__type', type: __Type, description: 'Request the type information of a single type.', isDeprecated: false, }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct field name suggestions after filtered', async () => { const suggestions = await getHintSuggestions('{ i', { line: 0, ch: 3 }); const list = [ { text: 'id', type: GraphQLInt, isDeprecated: false, }, { text: 'isTest', type: GraphQLBoolean, isDeprecated: false, }, { text: 'union', type: TestUnion, isDeprecated: false, }, { text: 'first', type: UnionFirst, isDeprecated: false, }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct field name suggestions when using aliases', async () => { const suggestions = await getHintSuggestions('{ aliasTest: first { ', { line: 0, ch: 21, }); const list = [ { text: 'scalar', type: GraphQLString, isDeprecated: false, }, { text: 'first', type: TestType, isDeprecated: false, }, { text: 'example', type: GraphQLString, isDeprecated: false, }, { text: '__typename', type: new GraphQLNonNull(GraphQLString), description: 'The name of the current Object type at runtime.', isDeprecated: false, }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct field name suggestion indentation', async () => { const suggestions = await getHintSuggestions('{\n ', { line: 1, ch: 2 }); expect(suggestions?.from).toEqual({ line: 1, ch: 2, sticky: null }); expect(suggestions?.to).toEqual({ line: 1, ch: 2, sticky: null }); }); it('provides correct argument suggestions', async () => { const suggestions = await getHintSuggestions('{ hasArgs ( ', { line: 0, ch: 12, }); const list = [ { text: 'string', type: GraphQLString, }, { text: 'int', type: GraphQLInt, }, { text: 'float', type: GraphQLFloat, }, { text: 'boolean', type: GraphQLBoolean, }, { text: 'id', type: GraphQLID, }, { text: 'enum', type: TestEnum, }, { text: 'object', type: TestInputObject, }, { text: 'listString', type: new GraphQLList(GraphQLString), }, { text: 'listInt', type: new GraphQLList(GraphQLInt), }, { text: 'listFloat', type: new GraphQLList(GraphQLFloat), }, { text: 'listBoolean', type: new GraphQLList(GraphQLBoolean), }, { text: 'listID', type: new GraphQLList(GraphQLID), }, { text: 'listEnum', type: new GraphQLList(TestEnum), }, { text: 'listObject', type: new GraphQLList(TestInputObject), }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct argument suggestions after filtered', async () => { const suggestions = await getHintSuggestions('{ hasArgs ( f', { line: 0, ch: 13, }); const list = [ { text: 'float', type: GraphQLFloat, }, { text: 'listFloat', type: new GraphQLList(GraphQLFloat), }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct argument suggestions when using aliases', async () => { const suggestions = await getHintSuggestions('{ aliasTest: hasArgs ( ', { line: 0, ch: 23, }); const list = [ { text: 'string', type: GraphQLString, }, { text: 'int', type: GraphQLInt, }, { text: 'float', type: GraphQLFloat, }, { text: 'boolean', type: GraphQLBoolean, }, { text: 'id', type: GraphQLID, }, { text: 'enum', type: TestEnum, }, { text: 'object', type: TestInputObject, }, { text: 'listString', type: new GraphQLList(GraphQLString), }, { text: 'listInt', type: new GraphQLList(GraphQLInt), }, { text: 'listFloat', type: new GraphQLList(GraphQLFloat), }, { text: 'listBoolean', type: new GraphQLList(GraphQLBoolean), }, { text: 'listID', type: new GraphQLList(GraphQLID), }, { text: 'listEnum', type: new GraphQLList(TestEnum), }, { text: 'listObject', type: new GraphQLList(TestInputObject), }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct directive suggestions', async () => { const suggestions = await getHintSuggestions('{ test (@', { line: 0, ch: 9, }); const list = [ { text: 'include', description: 'Directs the executor to include this field or fragment only when the `if` argument is true.', }, { text: 'skip', description: 'Directs the executor to skip this field or fragment when the `if` argument is true.', }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct directive suggestion after filtered', async () => { const suggestions = await getHintSuggestions('{ test (@s', { line: 0, ch: 10, }); const list = [ { text: 'skip', description: 'Directs the executor to skip this field or fragment when the `if` argument is true.', }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct directive suggestions when using aliases', async () => { const suggestions = await getHintSuggestions('{ aliasTest: test (@', { line: 0, ch: 20, }); const list = [ { text: 'include', description: 'Directs the executor to include this field or fragment only when the `if` argument is true.', }, { text: 'skip', description: 'Directs the executor to skip this field or fragment when the `if` argument is true.', }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct directive suggestions on definitions', async () => { const suggestions = await getHintSuggestions('type Type @', { line: 0, ch: 11, }); const list = [ { text: 'onAllDefs', description: '', }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct directive suggestions on args definitions', async () => { const suggestions = await getHintSuggestions( 'type Type { field(arg: String @', { line: 0, ch: 31 }, ); const list = [ { text: 'deprecated', description: 'Marks an element of a GraphQL schema as no longer supported.', }, { text: 'onArg', description: '', }, { text: 'onAllDefs', description: '', }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides interface suggestions for type when using implements keyword', async () => { const suggestions = await getHintSuggestions('type Type implements ', { line: 0, ch: 21, }); const list = [ { text: 'TestInterface', type: TestSchema.getType('TestInterface'), }, { text: 'AnotherTestInterface', type: TestSchema.getType('AnotherTestInterface'), }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides interface suggestions for interface when using implements keyword', async () => { const suggestions = await getHintSuggestions( 'interface MyInt implements An', { line: 0, ch: 29 }, ); const list = [ { text: 'AnotherTestInterface', type: TestSchema.getType('AnotherTestInterface'), }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides interface suggestions for interface when using implements keyword and multiple interfaces', async () => { const suggestions = await getHintSuggestions( 'interface MyInt implements AnotherTestInterface & T', { line: 0, ch: 51 }, ); const list = [ { text: 'TestInterface', type: TestSchema.getType('TestInterface'), }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct typeCondition suggestions', async () => { const suggestions = await getHintSuggestions('{ union { ... on ', { line: 0, ch: 17, }); const list = [ { text: 'First', description: '', }, { text: 'Second', description: '', }, { text: 'TestInterface', description: '', }, { text: 'AnotherTestInterface', description: '', }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct typeCondition suggestions after filtered', async () => { const suggestions = await getHintSuggestions('{ union { ... on F', { line: 0, ch: 18, }); const list = [ { text: 'First', description: '', }, { text: 'TestInterface', description: '', }, { text: 'AnotherTestInterface', description: '', }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct typeCondition suggestions on fragment', async () => { const suggestions = await getHintSuggestions('fragment Foo on ', { line: 0, ch: 16, }); const list = [ { text: 'Test', description: '', }, { text: 'TestUnion', description: '', }, { text: 'First', description: '', }, { text: 'TestInterface', description: '', }, { text: 'AnotherTestInterface', description: '', }, { text: 'Second', description: '', }, { text: 'MutationType', description: 'This is a simple mutation type', }, { text: 'SubscriptionType', description: 'This is a simple subscription type', }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct ENUM suggestions', async () => { const suggestions = await getHintSuggestions('{ hasArgs (enum: ', { line: 0, ch: 17, }); const list = [ { text: 'RED', type: TestEnum, isDeprecated: false, }, { text: 'GREEN', type: TestEnum, isDeprecated: false, }, { text: 'BLUE', type: TestEnum, isDeprecated: false, }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct testInput suggestions', async () => { const suggestions = await getHintSuggestions('{ hasArgs (object: { ', { line: 0, ch: 21, }); const list = [ { text: 'string', type: GraphQLString, }, { text: 'int', type: GraphQLInt, }, { text: 'float', type: GraphQLFloat, }, { text: 'boolean', type: GraphQLBoolean, }, { text: 'id', type: GraphQLID, }, { text: 'enum', type: TestEnum, }, { text: 'object', type: TestInputObject, }, { text: 'listString', type: new GraphQLList(GraphQLString), }, { text: 'listInt', type: new GraphQLList(GraphQLInt), }, { text: 'listFloat', type: new GraphQLList(GraphQLFloat), }, { text: 'listBoolean', type: new GraphQLList(GraphQLBoolean), }, { text: 'listID', type: new GraphQLList(GraphQLID), }, { text: 'listEnum', type: new GraphQLList(TestEnum), }, { text: 'listObject', type: new GraphQLList(TestInputObject), }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct object field suggestions after filtered', async () => { const suggestions = await getHintSuggestions('{ hasArgs (object: { f', { line: 0, ch: 22, }); const list = [ { text: 'float', type: GraphQLFloat, }, { text: 'listFloat', type: new GraphQLList(GraphQLFloat), }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides fragment name suggestion', async () => { const suggestions = await getHintSuggestions( 'fragment Foo on Test { id } query { ...', { line: 0, ch: 40 }, ); const list = [ { text: 'Foo', type: TestType, description: 'fragment Foo on Test', }, { text: 'Example', type: TestType, description: 'fragment Example on Test', }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides fragment names for fragments defined lower', async () => { const suggestions = await getHintSuggestions( 'query { ... }\nfragment Foo on Test { id }', { line: 0, ch: 11 }, ); const list = [ { text: 'Foo', type: TestType, description: 'fragment Foo on Test', }, { text: 'Example', type: TestType, description: 'fragment Example on Test', }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides only appropriate fragment names', async () => { const suggestions = await getHintSuggestions( 'fragment Foo on TestUnion { ... } ' + 'fragment Bar on First { name } ' + 'fragment Baz on Second { name } ' + 'fragment Qux on TestUnion { name } ' + 'fragment Nrf on Test { id } ' + 'fragment Quux on TestInputObject { string } ' + 'fragment Abc on Xyz { abcdef }', { line: 0, ch: 31 }, ); const list = [ { text: 'Bar', type: UnionFirst, description: 'fragment Bar on First', }, { text: 'Baz', type: UnionSecond, description: 'fragment Baz on Second', }, { text: 'Qux', type: TestUnion, description: 'fragment Qux on TestUnion', }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct field name suggestion inside inline fragment', async () => { const suggestions = await getHintSuggestions( 'fragment Foo on TestUnion { ... on First { ', { line: 0, ch: 43 }, ); const list = [ { text: 'scalar', type: GraphQLString, isDeprecated: false, }, { text: 'first', type: TestType, isDeprecated: false, }, { text: 'example', type: GraphQLString, isDeprecated: false, }, { text: '__typename', type: new GraphQLNonNull(GraphQLString), description: 'The name of the current Object type at runtime.', isDeprecated: false, }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct field name suggestion inside type-less inline fragment', async () => { const suggestions = await getHintSuggestions( 'fragment Foo on First { ... { ', { line: 0, ch: 30 }, ); const list = [ { text: 'scalar', type: GraphQLString, isDeprecated: false, }, { text: 'first', type: TestType, isDeprecated: false, }, { text: 'example', type: GraphQLString, isDeprecated: false, }, { text: '__typename', type: new GraphQLNonNull(GraphQLString), description: 'The name of the current Object type at runtime.', isDeprecated: false, }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct boolean suggestions', async () => { const suggestions1 = await getHintSuggestions('{ hasArgs(listBoolean: [ ', { line: 0, ch: 27, }); const list1 = [ { text: 'true', type: GraphQLBoolean, description: 'Not false.', }, { text: 'false', type: GraphQLBoolean, description: 'Not true.', }, ]; const expectedSuggestions1 = getExpectedSuggestions(list1); expect(suggestions1?.list).toEqual(expectedSuggestions1); const suggestions2 = await getHintSuggestions( '{ hasArgs(object: { boolean: t', { line: 0, ch: 30 }, ); const list2 = [ { text: 'true', type: GraphQLBoolean, description: 'Not false.', }, ]; const expectedSuggestions2 = getExpectedSuggestions(list2); expect(suggestions2?.list).toEqual(expectedSuggestions2); const suggestions3 = await getHintSuggestions('{ hasArgs(boolean: f', { line: 0, ch: 20, }); const list3 = [ { text: 'false', type: GraphQLBoolean, description: 'Not true.', }, ]; const expectedSuggestions3 = getExpectedSuggestions(list3); expect(suggestions3?.list).toEqual(expectedSuggestions3); }); it('provides correct variable type suggestions', async () => { const suggestions = await getHintSuggestions('query($foo: ', { line: 0, ch: 12, }); const list = [ { text: 'String', description: 'The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.', }, { text: 'Int', description: 'The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.', }, { text: 'Boolean', description: 'The `Boolean` scalar type represents `true` or `false`.', }, { text: 'Float', description: 'The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).', }, { text: 'ID', description: 'The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.', }, { text: 'TestEnum', description: '' }, { text: 'TestInput', description: '' }, { text: '__TypeKind', description: 'An enum describing what kind of type a given `__Type` is.', }, { text: '__DirectiveLocation', description: 'A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.', }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides correct variable type suggestions inside list type', async () => { const suggestions = await getHintSuggestions('query($foo: [ ', { line: 0, ch: 14, }); const list = [ { text: 'String', description: 'The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.', }, { text: 'Int', description: 'The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.', }, { text: 'Boolean', description: 'The `Boolean` scalar type represents `true` or `false`.', }, { text: 'Float', description: 'The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).', }, { text: 'ID', description: 'The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.', }, { text: 'TestEnum', description: '' }, { text: 'TestInput', description: '' }, { text: '__TypeKind', description: 'An enum describing what kind of type a given `__Type` is.', }, { text: '__DirectiveLocation', description: 'A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.', }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); it('provides no suggestions', async () => { const list: IHint[] = []; const expectedSuggestions = getExpectedSuggestions(list); // kind is FragmentSpread, step is 2 const suggestions1 = await getHintSuggestions( 'fragment Foo on Test { id } query { ...Foo ', { line: 0, ch: 45 }, ); expect(suggestions1?.list).toEqual(expectedSuggestions); // kind is ListType, step is 3 const suggestions2 = await getHintSuggestions('query($foo: [string] ', { line: 0, ch: 21, }); expect(suggestions2?.list).toEqual(expectedSuggestions); // kind is ListValue, step is 1 const suggestions3 = await getHintSuggestions( '{ hasArgs(listString: ["foo" ', { line: 0, ch: 29, }, ); expect(suggestions3?.list).toEqual(expectedSuggestions); // kind is VariableDefinition, step is 1 const suggestions4 = await getHintSuggestions('query($foo ', { line: 0, ch: 11, }); expect(suggestions4?.list).toEqual(expectedSuggestions); // kind is Argument, step is 1 const suggestions5 = await getHintSuggestions('{ hasArgs(string ', { line: 0, ch: 17, }); expect(suggestions5?.list).toEqual(expectedSuggestions); // kind is Argument, step is 2, and input type isn't GraphQLEnumType or GraphQLBoolean const suggestions6 = await getHintSuggestions('{ hasArgs(string: ', { line: 0, ch: 18, }); expect(suggestions6?.list).toEqual(expectedSuggestions); const suggestions7 = await getHintSuggestions( '{ hasArgs(object: { string ', { line: 0, ch: 27 }, ); expect(suggestions7?.list).toEqual(expectedSuggestions); }); it('provides variable completion for arguments', async () => { const expectedSuggestions = getExpectedSuggestions([ { text: 'string', type: GraphQLString }, { text: 'listString', type: new GraphQLList(GraphQLString) }, ]); // kind is Argument, step is 2, and input type isn't GraphQLEnumType or GraphQLBoolean const suggestions9 = await getHintSuggestions( 'query myQuery($arg: String){ hasArgs(string: ', { line: 0, ch: 42, }, ); expect(suggestions9?.list).toEqual(expectedSuggestions); }); it('provides variable completion for arguments with $', async () => { const expectedSuggestions = getExpectedSuggestions([ { text: 'string', type: GraphQLString }, { text: 'listString', type: new GraphQLList(GraphQLString) }, ]); // kind is Argument, step is 2, and input type isn't GraphQLEnumType or GraphQLBoolean const suggestions9 = await getHintSuggestions( 'query myQuery($arg: String){ hasArgs(string: $', { line: 0, ch: 42, }, ); expect(suggestions9?.list).toEqual(expectedSuggestions); }); it('provides correct field name suggestions for an interface type', async () => { const suggestions = await getHintSuggestions( '{ first { ... on TestInterface { ', { line: 0, ch: 33, }, ); const list = [ { text: 'scalar', type: GraphQLString, isDeprecated: false, }, { description: 'The name of the current Object type at runtime.', isDeprecated: false, text: '__typename', type: new GraphQLNonNull(GraphQLString), deprecationReason: undefined, }, ]; const expectedSuggestions = getExpectedSuggestions(list); expect(suggestions?.list).toEqual(expectedSuggestions); }); }); ================================================ FILE: packages/codemirror-graphql/src/__tests__/kitchen-sink.graphql ================================================ # Copyright (c) 2021 GraphQL Contributors # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. An additional grant # of patent rights can be found in the PATENTS file in the same directory. query queryName($foo: TestInput, $site: TestEnum = RED) { testAlias: hasArgs(string: "testString") ... on Test { hasArgs( listEnum: [RED, GREEN, BLUE] int: 1 listFloat: [1.23, 1.3e-1, -1.35384e+3] boolean: true id: 123 object: $foo enum: $site ) } test @include(if: true) { union { __typename } } ...frag ... @skip(if: false) { id } ... { id } } mutation mutationName { setString(value: "newString") } subscription subscriptionName { subscribeToTest(id: "anId") { ... on Test { id } } } fragment frag on Test { test @include(if: true) { union { __typename } } } ================================================ FILE: packages/codemirror-graphql/src/__tests__/lint.test.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import 'codemirror/addon/lint/lint'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import { GraphQLError, OperationDefinitionNode, version } from 'graphql'; import '../lint'; import '../mode'; import { TestSchema } from './testSchema'; function createEditorWithLint(lintConfig?: any) { return CodeMirror(document.createElement('div'), { mode: 'graphql', lint: lintConfig || true, }); } function printLintErrors(queryString: string, configOverrides = {}) { const editor = createEditorWithLint({ schema: TestSchema, ...configOverrides, }); return new Promise(resolve => { editor.state.lint.options.onUpdateLinting = (errors: any[]) => { if (errors?.[0] && !errors[0].message.match('Unexpected EOF')) { resolve(errors); return; } resolve([]); }; editor.doc.setValue(queryString); }); } describe('graphql-lint', () => { it('attaches a GraphQL lint function with correct mode/lint options', () => { const editor = createEditorWithLint(); expect(editor.getHelpers(editor.getCursor(), 'lint')).not.toHaveLength(0); }); const kitchenSink = readFileSync( join(__dirname, '/kitchen-sink.graphql'), 'utf8', ); it('returns no syntactic/validation errors after parsing kitchen-sink query', async () => { const errors = await printLintErrors(kitchenSink); expect(errors).toHaveLength(0); }); it('returns a validation error for a invalid query', async () => { const noMutationOperationRule = (context: any) => ({ OperationDefinition(node: OperationDefinitionNode) { if (node.operation === 'mutation') { context.reportError( new GraphQLError( 'I like turtles.', // @ts-expect-error parseInt(version, 10) > 16 ? { nodes: node } : node, ), ); } return false; }, }); const errors = await printLintErrors(kitchenSink, { validationRules: [noMutationOperationRule], }); expect(errors.length).toBe(1); expect(errors[0].message).toBe('I like turtles.'); }); }); ================================================ FILE: packages/codemirror-graphql/src/__tests__/mode.test.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import 'codemirror/addon/runmode/runmode'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import '../mode'; describe('graphql-mode', () => { it('provides correct tokens and styles after parsing', () => { const queryStr = 'query name { }'; const tokens: string[] = []; const styles: string[] = []; CodeMirror.runMode(queryStr, 'graphql', (token, style) => { if (style && style !== 'ws') { tokens.push(token); styles.push(style); } }); expect(tokens).toEqual(['query', 'name', '{', '}']); expect(styles).toEqual(['keyword', 'def', 'punctuation', 'punctuation']); }); it('parses Relay-style anonymous FragmentDefinitions', () => { CodeMirror.runMode('fragment on Test { id }', 'graphql', (_token, style) => expect(style).not.toBe('invalidchar'), ); }); it('parses inline fragments with optional syntax correctly', () => { CodeMirror.runMode( '{ ... on OptionalType { name } }', 'graphql', (_token, style) => expect(style).not.toBe('invalidchar'), ); CodeMirror.runMode('{ ... { name } }', 'graphql', (_token, style) => expect(style).not.toBe('invalidchar'), ); CodeMirror.runMode( '{ ... @optionalDirective { name } }', 'graphql', (_token, style) => expect(style).not.toBe('invalidchar'), ); }); it('returns "invalidchar" message when there is no matching token', () => { CodeMirror.runMode('invalidKeyword name', 'graphql', (token, style) => { if (token.trim()) { expect(style).toBe('invalidchar'); } }); CodeMirror.runMode('query %', 'graphql', (token, style) => { if (token === '%') { expect(style).toBe('invalidchar'); } }); }); it('parses kitchen-sink query without invalidchar', () => { const kitchenSink = readFileSync( join(__dirname, '/kitchen-sink.graphql'), 'utf8', ); CodeMirror.runMode(kitchenSink, 'graphql', (_token, style) => { expect(style).not.toBe('invalidchar'); }); }); it('parses schema-kitchen-sink query without invalidchar', () => { const schemaKitchenSink = readFileSync( join(__dirname, '/schema-kitchen-sink.graphql'), 'utf8', ); CodeMirror.runMode(schemaKitchenSink, 'graphql', (_token, style) => { expect(style).not.toBe('invalidchar'); }); }); it('parses anonymous operations without invalidchar', () => { CodeMirror.runMode('{ id }', 'graphql', (_token, style) => { expect(style).not.toBe('invalidchar'); }); CodeMirror.runMode( ` mutation { setString(value: "newString") } `, 'graphql', (_token, style) => { expect(style).not.toBe('invalidchar'); }, ); CodeMirror.runMode( ` subscription { subscribeToTest(id: "anId") { id } } `, 'graphql', (_token, style) => { expect(style).not.toBe('invalidchar'); }, ); }); }); ================================================ FILE: packages/codemirror-graphql/src/__tests__/schema-kitchen-sink.graphql ================================================ # Copyright (c) 2021 GraphQL Contributors # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. An additional grant # of patent rights can be found in the PATENTS file in the same directory. schema { query: QueryType mutation: MutationType } type Foo implements Bar { one: Type two(argument: InputType!): Type three(argument: InputType, other: String): Int four(argument: String = "string"): String five(argument: [String] = ["string", "string"]): String six(argument: InputType = {key: "value"}): Type } type AnnotatedObject @onObject(arg: "value") { annotatedField(arg: Type = "default" @onArg): Type @onField } interface Bar { one: Type four(argument: String = "string"): String } interface AnnotatedInterface @onInterface { annotatedField(arg: Type @onArg): Type @onField } union Feed = Story | Article | Advert union AnnotatedUnion @onUnion = A | B scalar CustomScalar scalar AnnotatedScalar @onScalar enum Site { DESKTOP MOBILE } enum AnnotatedEnum @onEnum { ANNOTATED_VALUE @onEnumValue OTHER_VALUE } input InputType { key: String! answer: Int = 42 } input AnnotatedInput @onInputObjectType { annotatedField: Type @onField } extend type Foo { seven(argument: [[String!]!]!): Type } extend type Foo @onType {} type NoFields {} directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT ================================================ FILE: packages/codemirror-graphql/src/__tests__/testSchema.ts ================================================ /* istanbul ignore file */ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import { DirectiveLocation, GraphQLBoolean, GraphQLDeprecatedDirective, GraphQLDirective, GraphQLEnumType, GraphQLFloat, GraphQLID, GraphQLIncludeDirective, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLSkipDirective, GraphQLString, GraphQLUnionType, } from 'graphql'; // Test Schema export const TestEnum = new GraphQLEnumType({ name: 'TestEnum', values: { RED: {}, GREEN: {}, BLUE: {}, }, }); export const TestInputObject: GraphQLInputObjectType = new GraphQLInputObjectType({ name: 'TestInput', fields: () => ({ string: { type: GraphQLString }, int: { type: GraphQLInt }, float: { type: GraphQLFloat }, boolean: { type: GraphQLBoolean }, id: { type: GraphQLID }, enum: { type: TestEnum }, object: { type: TestInputObject }, // List listString: { type: new GraphQLList(GraphQLString) }, listInt: { type: new GraphQLList(GraphQLInt) }, listFloat: { type: new GraphQLList(GraphQLFloat) }, listBoolean: { type: new GraphQLList(GraphQLBoolean) }, listID: { type: new GraphQLList(GraphQLID) }, listEnum: { type: new GraphQLList(TestEnum) }, listObject: { type: new GraphQLList(TestInputObject) }, }), }); const TestInterface: GraphQLInterfaceType = new GraphQLInterfaceType({ name: 'TestInterface', resolveType: () => UnionFirst, fields: { scalar: { type: GraphQLString, resolve: () => ({}), }, }, }); const AnotherTestInterface: GraphQLInterfaceType = new GraphQLInterfaceType({ name: 'AnotherTestInterface', resolveType: () => UnionFirst, fields: { example: { type: GraphQLString, resolve: () => ({}), }, }, }); export const UnionFirst = new GraphQLObjectType({ name: 'First', interfaces: [TestInterface, AnotherTestInterface], fields: () => ({ scalar: { type: GraphQLString, resolve: () => ({}), }, first: { type: TestType, resolve: () => ({}), }, example: { type: GraphQLString, resolve: () => ({}), }, }), }); export const UnionSecond = new GraphQLObjectType({ name: 'Second', fields: () => ({ second: { type: TestType, resolve: () => ({}), }, }), }); export const TestUnion = new GraphQLUnionType({ name: 'TestUnion', types: [UnionFirst, UnionSecond], resolveType() { return UnionFirst; }, }); export const TestType: GraphQLObjectType = new GraphQLObjectType({ name: 'Test', fields: () => ({ test: { type: TestType, resolve: () => ({}), }, deprecatedTest: { type: TestType, deprecationReason: 'Use test instead.', resolve: () => ({}), }, union: { type: TestUnion, resolve: () => ({}), }, first: { type: UnionFirst, resolve: () => ({}), }, id: { type: GraphQLInt, resolve: () => ({}), }, isTest: { type: GraphQLBoolean, resolve() { return true; }, }, hasArgs: { type: GraphQLString, resolve(_value, args) { return JSON.stringify(args); }, args: { string: { type: GraphQLString }, int: { type: GraphQLInt }, float: { type: GraphQLFloat }, boolean: { type: GraphQLBoolean }, id: { type: GraphQLID }, enum: { type: TestEnum }, object: { type: TestInputObject }, // List listString: { type: new GraphQLList(GraphQLString) }, listInt: { type: new GraphQLList(GraphQLInt) }, listFloat: { type: new GraphQLList(GraphQLFloat) }, listBoolean: { type: new GraphQLList(GraphQLBoolean) }, listID: { type: new GraphQLList(GraphQLID) }, listEnum: { type: new GraphQLList(TestEnum) }, listObject: { type: new GraphQLList(TestInputObject) }, }, }, }), }); const TestMutationType = new GraphQLObjectType({ name: 'MutationType', description: 'This is a simple mutation type', fields: { setString: { type: GraphQLString, description: 'Set the string field', args: { value: { type: GraphQLString }, }, }, }, }); const TestSubscriptionType = new GraphQLObjectType({ name: 'SubscriptionType', description: 'This is a simple subscription type', fields: { subscribeToTest: { type: TestType, description: 'Subscribe to the test type', args: { id: { type: GraphQLString }, }, }, }, }); const OnArgDirective = new GraphQLDirective({ name: 'onArg', locations: [DirectiveLocation.ARGUMENT_DEFINITION], }); const OnAllDefsDirective = new GraphQLDirective({ name: 'onAllDefs', locations: [ DirectiveLocation.SCHEMA, DirectiveLocation.SCALAR, DirectiveLocation.OBJECT, DirectiveLocation.FIELD_DEFINITION, DirectiveLocation.INTERFACE, DirectiveLocation.UNION, DirectiveLocation.ENUM, DirectiveLocation.ENUM_VALUE, DirectiveLocation.INPUT_OBJECT, DirectiveLocation.ARGUMENT_DEFINITION, DirectiveLocation.INPUT_FIELD_DEFINITION, ], }); export const TestSchema = new GraphQLSchema({ query: TestType, mutation: TestMutationType, subscription: TestSubscriptionType, directives: [ GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, OnArgDirective, OnAllDefsDirective, ], }); ================================================ FILE: packages/codemirror-graphql/src/cm6-legacy/mode.ts ================================================ import type { StreamParser } from '@codemirror/language'; import graphqlModeFactory from '../utils/mode-factory'; // Types of property 'token' are incompatible. // Type '((stream: StringStream, state: any) => string | null) | undefined' is not comparable to type '(stream: StringStream, state: any) => string | null'. export const graphql = graphqlModeFactory({}) as unknown as StreamParser; ================================================ FILE: packages/codemirror-graphql/src/hint.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * */ import CodeMirror, { Hints, Hint } from 'codemirror'; import 'codemirror/addon/hint/show-hint.js'; import { FragmentDefinitionNode, GraphQLSchema, GraphQLType } from 'graphql'; import type { AutocompleteSuggestionOptions, Maybe, } from 'graphql-language-service'; import { getAutocompleteSuggestions, Position } from 'graphql-language-service'; export interface GraphQLHintOptions { schema?: GraphQLSchema; externalFragments?: string | FragmentDefinitionNode[]; autocompleteOptions?: AutocompleteSuggestionOptions; } interface IHint extends Hint { isDeprecated?: boolean; type?: Maybe; description?: Maybe; deprecationReason?: Maybe; } interface IHints extends Hints { list: IHint[]; } declare module 'codemirror' { interface ShowHintOptions { schema?: GraphQLSchema; externalFragments?: string | FragmentDefinitionNode[]; } interface CodeMirrorHintMap { graphql: ( editor: CodeMirror.Editor, options: GraphQLHintOptions, ) => IHints | undefined; } } /** * Registers a "hint" helper for CodeMirror. * * Using CodeMirror's "hint" addon: https://codemirror.net/demo/complete.html * Given an editor, this helper will take the token at the cursor and return a * list of suggested tokens. * * Options: * * - schema: GraphQLSchema provides the hinter with positionally relevant info * * Additional Events: * * - hasCompletion (codemirror, data, token) - signaled when the hinter has a * new list of completion suggestions. * */ CodeMirror.registerHelper( 'hint', 'graphql', ( editor: CodeMirror.Editor, options: GraphQLHintOptions, ): IHints | undefined => { const { schema, externalFragments, autocompleteOptions } = options; if (!schema) { return; } const cur = editor.getCursor(); const token = editor.getTokenAt(cur); const tokenStart = token.type !== null && /"|\w/.test(token.string[0]) ? token.start : token.end; const position = new Position(cur.line, tokenStart); const rawResults = getAutocompleteSuggestions( schema, editor.getValue(), position, token, externalFragments, autocompleteOptions, ); const results = { list: rawResults.map(item => ({ // important! for when the label is different from the insert text text: item?.rawInsert ?? item.label, type: item.type, description: item.documentation, isDeprecated: item.isDeprecated, deprecationReason: item.deprecationReason, })), from: { line: cur.line, ch: tokenStart }, to: { line: cur.line, ch: token.end }, }; if (results?.list && results.list.length > 0) { results.from = CodeMirror.Pos(results.from.line, results.from.ch); results.to = CodeMirror.Pos(results.to.line, results.to.ch); CodeMirror.signal(editor, 'hasCompletion', editor, results, token); } return results; }, ); // exporting here so we don't need to import the codemirror show-hint addon module (and its implementation) export type { IHint, IHints }; ================================================ FILE: packages/codemirror-graphql/src/index.d.ts ================================================ import 'codemirror/addon/hint/show-hint'; declare module 'codemirror' { let Init: any; interface Editor { doc: CodeMirror.Doc; getHelper(pos: { line: number; ch: number }, type: string): any; getHelpers(pos: { line: number; ch: number }, type: string): any[]; } interface ShowHintOptions { hint?: ShowHintOptions['hint']; } const hint: object; } ================================================ FILE: packages/codemirror-graphql/src/info.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import { GraphQLDirective, GraphQLEnumType, GraphQLEnumValue, GraphQLInputField, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLType, } from 'graphql'; import CodeMirror from 'codemirror'; import getTypeInfo, { TypeInfo } from './utils/getTypeInfo'; import { getArgumentReference, getDirectiveReference, getEnumValueReference, getFieldReference, getTypeReference, SchemaReference, } from './utils/SchemaReference'; import './utils/info-addon'; import type { Maybe } from 'graphql-language-service'; export interface GraphQLInfoOptions { schema?: GraphQLSchema; onClick?: Maybe<(ref: Maybe, e: MouseEvent) => void>; renderDescription?: (str: string) => string; render?: () => string; } /** * Registers GraphQL "info" tooltips for CodeMirror. * * When hovering over a token, this presents a tooltip explaining it. * * Options: * * - schema: GraphQLSchema provides positionally relevant info. * - hoverTime: The number of ms to wait before showing info. (Default 500) * - renderDescription: Convert a description to some HTML, Useful since * descriptions are often Markdown formatted. * - onClick: A function called when a named thing is clicked. * */ CodeMirror.registerHelper( 'info', 'graphql', (token: CodeMirror.Token, options: GraphQLInfoOptions) => { if (!options.schema || !token.state) { return; } const { kind, step } = token.state; const typeInfo = getTypeInfo(options.schema, token.state); // Given a Schema and a Token, produce the contents of an info tooltip. // To do this, create a div element that we will render "into" and then pass // it to various rendering functions. if ( (kind === 'Field' && step === 0 && typeInfo.fieldDef) || (kind === 'AliasedField' && step === 2 && typeInfo.fieldDef) || (kind === 'ObjectField' && step === 0 && typeInfo.fieldDef) ) { const header = document.createElement('div'); header.className = 'CodeMirror-info-header'; renderField(header, typeInfo, options); const into = document.createElement('div'); into.append(header); renderDescription(into, options, typeInfo.fieldDef as any); return into; } if (kind === 'Directive' && step === 1 && typeInfo.directiveDef) { const header = document.createElement('div'); header.className = 'CodeMirror-info-header'; renderDirective(header, typeInfo, options); const into = document.createElement('div'); into.append(header); renderDescription(into, options, typeInfo.directiveDef); return into; } if (kind === 'Argument' && step === 0 && typeInfo.argDef) { const header = document.createElement('div'); header.className = 'CodeMirror-info-header'; renderArg(header, typeInfo, options); const into = document.createElement('div'); into.append(header); renderDescription(into, options, typeInfo.argDef); return into; } if (kind === 'EnumValue' && typeInfo.enumValue?.description) { const header = document.createElement('div'); header.className = 'CodeMirror-info-header'; renderEnumValue(header, typeInfo, options); const into = document.createElement('div'); into.append(header); renderDescription(into, options, typeInfo.enumValue); return into; } if ( kind === 'NamedType' && typeInfo.type && (typeInfo.type as GraphQLObjectType).description ) { const header = document.createElement('div'); header.className = 'CodeMirror-info-header'; renderType(header, typeInfo, options, typeInfo.type); const into = document.createElement('div'); into.append(header); renderDescription(into, options, typeInfo.type); return into; } }, ); function renderField( into: HTMLElement, typeInfo: TypeInfo, options: GraphQLInfoOptions, ) { renderQualifiedField(into, typeInfo, options); renderTypeAnnotation(into, typeInfo, options, typeInfo.type); } function renderQualifiedField( into: HTMLElement, typeInfo: TypeInfo, options: GraphQLInfoOptions, ) { const fieldName = typeInfo.fieldDef?.name || ''; text(into, fieldName, 'field-name', options, getFieldReference(typeInfo)); } function renderDirective( into: HTMLElement, typeInfo: TypeInfo, options: GraphQLInfoOptions, ) { const name = '@' + (typeInfo.directiveDef?.name || ''); text(into, name, 'directive-name', options, getDirectiveReference(typeInfo)); } function renderArg( into: HTMLElement, typeInfo: TypeInfo, options: GraphQLInfoOptions, ) { const name = typeInfo.argDef?.name || ''; text(into, name, 'arg-name', options, getArgumentReference(typeInfo)); renderTypeAnnotation(into, typeInfo, options, typeInfo.inputType); } function renderEnumValue( into: HTMLElement, typeInfo: TypeInfo, options: GraphQLInfoOptions, ) { const name = typeInfo.enumValue?.name || ''; renderType(into, typeInfo, options, typeInfo.inputType); text(into, '.'); text(into, name, 'enum-value', options, getEnumValueReference(typeInfo)); } function renderTypeAnnotation( into: HTMLElement, typeInfo: TypeInfo, options: GraphQLInfoOptions, t: Maybe, ) { const typeSpan = document.createElement('span'); typeSpan.className = 'type-name-pill'; if (t instanceof GraphQLNonNull) { renderType(typeSpan, typeInfo, options, t.ofType); text(typeSpan, '!'); } else if (t instanceof GraphQLList) { text(typeSpan, '['); renderType(typeSpan, typeInfo, options, t.ofType); text(typeSpan, ']'); } else { text( typeSpan, t?.name || '', 'type-name', options, getTypeReference(typeInfo, t), ); } into.append(typeSpan); } function renderType( into: HTMLElement, typeInfo: TypeInfo, options: GraphQLInfoOptions, t: Maybe, ) { if (t instanceof GraphQLNonNull) { renderType(into, typeInfo, options, t.ofType); text(into, '!'); } else if (t instanceof GraphQLList) { text(into, '['); renderType(into, typeInfo, options, t.ofType); text(into, ']'); } else { text( into, t?.name || '', 'type-name', options, getTypeReference(typeInfo, t), ); } } function renderDescription( into: HTMLElement, options: GraphQLInfoOptions, def: | GraphQLInputField | GraphQLEnumType | GraphQLDirective | GraphQLEnumValue | GraphQLType, ) { const { description } = def as GraphQLInputField; if (description) { const descriptionDiv = document.createElement('div'); descriptionDiv.className = 'info-description'; if (options.renderDescription) { descriptionDiv.innerHTML = options.renderDescription(description); } else { descriptionDiv.append(document.createTextNode(description)); } into.append(descriptionDiv); } renderDeprecation(into, options, def); } function renderDeprecation( into: HTMLElement, options: GraphQLInfoOptions, def: | GraphQLInputField | GraphQLEnumType | GraphQLDirective | GraphQLEnumValue | GraphQLType, ) { const reason = (def as GraphQLInputField).deprecationReason; if (reason) { const deprecationDiv = document.createElement('div'); deprecationDiv.className = 'info-deprecation'; into.append(deprecationDiv); const label = document.createElement('span'); label.className = 'info-deprecation-label'; label.append(document.createTextNode('Deprecated')); deprecationDiv.append(label); const reasonDiv = document.createElement('div'); reasonDiv.className = 'info-deprecation-reason'; if (options.renderDescription) { reasonDiv.innerHTML = options.renderDescription(reason); } else { reasonDiv.append(document.createTextNode(reason)); } deprecationDiv.append(reasonDiv); } } function text( into: HTMLElement, content: string, className = '', options: GraphQLInfoOptions = { onClick: null }, ref: Maybe = null, ) { if (className) { const { onClick } = options; let node; if (onClick) { node = document.createElement('a'); // Providing a href forces proper a tag behavior, though we don't actually // want clicking the node to navigate anywhere. node.href = 'javascript:void 0'; // eslint-disable-line no-script-url node.addEventListener('click', (e: MouseEvent) => { // Although an href of 'javascript:void 0' should never navigate away from the page, // that is not always the case: https://github.com/graphql/graphiql/issues/3565 e.preventDefault(); onClick(ref, e); }); } else { node = document.createElement('span'); } node.className = className; node.append(document.createTextNode(content)); into.append(node); } else { into.append(document.createTextNode(content)); } } ================================================ FILE: packages/codemirror-graphql/src/jump.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import getTypeInfo from './utils/getTypeInfo'; import { getArgumentReference, getDirectiveReference, getEnumValueReference, getFieldReference, getTypeReference, } from './utils/SchemaReference'; import './utils/jump-addon'; import { GraphQLSchema } from 'graphql'; import type { State } from 'graphql-language-service'; export interface GraphQLJumpOptions { schema?: GraphQLSchema; onClick?: () => void; state?: State; } /** * Registers GraphQL "jump" links for CodeMirror. * * When command-hovering over a token, this converts it to a link, which when * pressed will call the provided onClick handler. * * Options: * * - schema: GraphQLSchema provides positionally relevant info. * - onClick: A function called when a named thing is clicked. * */ CodeMirror.registerHelper( 'jump', 'graphql', (token: CodeMirror.Token, options: GraphQLJumpOptions) => { if (!options.schema || !options.onClick || !token.state) { return; } // Given a Schema and a Token, produce a "SchemaReference" which refers to // the particular artifact from the schema (such as a type, field, argument, // or directive) that token references. const { state } = token; const { kind, step } = state; const typeInfo = getTypeInfo(options.schema, state); if ( (kind === 'Field' && step === 0 && typeInfo.fieldDef) || (kind === 'AliasedField' && step === 2 && typeInfo.fieldDef) ) { return getFieldReference(typeInfo); } if (kind === 'Directive' && step === 1 && typeInfo.directiveDef) { return getDirectiveReference(typeInfo); } if (kind === 'Argument' && step === 0 && typeInfo.argDef) { return getArgumentReference(typeInfo); } if (kind === 'EnumValue' && typeInfo.enumValue) { return getEnumValueReference(typeInfo); } if (kind === 'NamedType' && typeInfo.type) { return getTypeReference(typeInfo); } }, ); ================================================ FILE: packages/codemirror-graphql/src/lint.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import { FragmentDefinitionNode, GraphQLSchema, ValidationRule } from 'graphql'; import { getDiagnostics } from 'graphql-language-service'; const SEVERITY = ['error', 'warning', 'information', 'hint']; const TYPE: Record = { 'GraphQL: Validation': 'validation', 'GraphQL: Deprecation': 'deprecation', 'GraphQL: Syntax': 'syntax', }; interface GraphQLLintOptions { schema?: GraphQLSchema; validationRules: ValidationRule[]; externalFragments?: string | FragmentDefinitionNode[]; } /** * Registers a "lint" helper for CodeMirror. * * Using CodeMirror's "lint" addon: https://codemirror.net/demo/lint.html * Given the text within an editor, this helper will take that text and return * a list of linter issues, derived from GraphQL's parse and validate steps. * Also, this uses `graphql-language-service-parser` to power the diagnostics * service. * * Options: * * - schema: GraphQLSchema provides the linter with positionally relevant info * */ CodeMirror.registerHelper( 'lint', 'graphql', (text: string, options: GraphQLLintOptions): CodeMirror.Annotation[] => { const { schema, validationRules, externalFragments } = options; const rawResults = getDiagnostics( text, schema, validationRules, undefined, externalFragments, ); const results = rawResults.map(error => ({ message: error.message, severity: error.severity ? SEVERITY[error.severity - 1] : SEVERITY[0], type: error.source ? TYPE[error.source] : undefined, from: CodeMirror.Pos(error.range.start.line, error.range.start.character), to: CodeMirror.Pos(error.range.end.line, error.range.end.character), })); return results; }, ); ================================================ FILE: packages/codemirror-graphql/src/mode.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import modeFactory from './utils/mode-factory'; CodeMirror.defineMode('graphql', modeFactory); ================================================ FILE: packages/codemirror-graphql/src/results/__tests__/mode.test.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import 'codemirror/addon/runmode/runmode'; import '../mode'; describe('graphql-results-mode', () => { it('provides correct tokens and styles after parsing', () => { const queryStr = '{ "data": { "field": "value" }, "errors": [ { "message": "bork" } ] }'; const tokens: [string, string][] = []; CodeMirror.runMode(queryStr, 'graphql-results', (token, style) => { if (style && style !== 'ws') { tokens.push([token, style]); } }); expect(tokens).toEqual([ ['{', 'punctuation'], ['"data"', 'def'], [':', 'punctuation'], ['{', 'punctuation'], ['"field"', 'property'], [':', 'punctuation'], ['"value"', 'string'], ['}', 'punctuation'], [',', 'punctuation'], ['"errors"', 'def'], [':', 'punctuation'], ['[', 'punctuation'], ['{', 'punctuation'], ['"message"', 'property'], [':', 'punctuation'], ['"bork"', 'string'], ['}', 'punctuation'], [']', 'punctuation'], ['}', 'punctuation'], ]); }); }); ================================================ FILE: packages/codemirror-graphql/src/results/mode.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import { list, t, onlineParser, p, Token } from 'graphql-language-service'; import indent from '../utils/mode-indent'; /** * This mode defines JSON, but provides a data-laden parser state to enable * better code intelligence. */ CodeMirror.defineMode('graphql-results', config => { const parser = onlineParser({ eatWhitespace: stream => stream.eatSpace(), lexRules: LexRules, parseRules: ParseRules, editorConfig: { tabSize: config.tabSize }, }); return { config, startState: parser.startState, token: parser.token as unknown as CodeMirror.Mode['token'], // TODO: Check if the types are indeed compatible indent, electricInput: /^\s*[}\]]/, fold: 'brace', closeBrackets: { pairs: '[]{}""', explode: '[]{}', }, }; }); /** * The lexer rules. These are exactly as described by the spec. */ const LexRules = { // All Punctuation used in JSON. Punctuation: /^\[|]|\{|\}|:|,/, // JSON Number. Number: /^-?(?:0|(?:[1-9][0-9]*))(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?/, // JSON String. String: /^"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?/, // JSON literal keywords. Keyword: /^true|false|null/, }; /** * The parser rules for JSON. */ const ParseRules = { Document: [p('{'), list('Entry', p(',')), p('}')], Entry: [t('String', 'def'), p(':'), 'Value'], Value(token: Token) { switch (token.kind) { case 'Number': return 'NumberValue'; case 'String': return 'StringValue'; case 'Punctuation': switch (token.value) { case '[': return 'ListValue'; case '{': return 'ObjectValue'; } return null; case 'Keyword': switch (token.value) { case 'true': case 'false': return 'BooleanValue'; case 'null': return 'NullValue'; } return null; } }, NumberValue: [t('Number', 'number')], StringValue: [t('String', 'string')], BooleanValue: [t('Keyword', 'builtin')], NullValue: [t('Keyword', 'keyword')], ListValue: [p('['), list('Value', p(',')), p(']')], ObjectValue: [p('{'), list('ObjectField', p(',')), p('}')], ObjectField: [t('String', 'property'), p(':'), 'Value'], }; ================================================ FILE: packages/codemirror-graphql/src/utils/SchemaReference.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import { getNamedType, GraphQLSchema } from 'graphql'; import type { GraphQLArgument, GraphQLDirective, GraphQLEnumValue, GraphQLEnumType, GraphQLField, GraphQLNamedType, } from 'graphql'; import { Maybe } from 'graphql/jsutils/Maybe'; import { TypeInfo } from './getTypeInfo'; export type SchemaReference = | FieldReference | DirectiveReference | ArgumentReference | EnumValueReference | TypeReference; export type FieldReference = { kind: 'Field'; field: GraphQLField; type: Maybe; schema?: GraphQLSchema; }; export type DirectiveReference = { kind: 'Directive'; directive: GraphQLDirective; schema?: GraphQLSchema; }; export type ArgumentReference = { kind: 'Argument'; argument: GraphQLArgument; field?: GraphQLField; type?: GraphQLNamedType; directive?: GraphQLDirective; schema?: GraphQLSchema; }; export type EnumValueReference = { kind: 'EnumValue'; value?: GraphQLEnumValue; type?: GraphQLEnumType; schema?: GraphQLSchema; }; export type TypeReference = { kind: 'Type'; type: GraphQLNamedType; schema?: GraphQLSchema; }; export function getFieldReference(typeInfo: any): FieldReference { return { kind: 'Field', schema: typeInfo.schema, field: typeInfo.fieldDef, type: isMetaField(typeInfo.fieldDef) ? null : typeInfo.parentType, }; } export function getDirectiveReference(typeInfo: any): DirectiveReference { return { kind: 'Directive', schema: typeInfo.schema, directive: typeInfo.directiveDef, }; } export function getArgumentReference(typeInfo: any): ArgumentReference { return typeInfo.directiveDef ? { kind: 'Argument', schema: typeInfo.schema, argument: typeInfo.argDef, directive: typeInfo.directiveDef, } : { kind: 'Argument', schema: typeInfo.schema, argument: typeInfo.argDef, field: typeInfo.fieldDef, type: isMetaField(typeInfo.fieldDef) ? null : typeInfo.parentType, }; } export function getEnumValueReference(typeInfo: TypeInfo): EnumValueReference { return { kind: 'EnumValue', value: typeInfo.enumValue || undefined, type: typeInfo.inputType ? (getNamedType(typeInfo.inputType) as GraphQLEnumType) : undefined, }; } // Note: for reusability, getTypeReference can produce a reference to any type, // though it defaults to the current type. export function getTypeReference( typeInfo: any, type?: Maybe, ): TypeReference { return { kind: 'Type', schema: typeInfo.schema, type: type || typeInfo.type, }; } function isMetaField(fieldDef: GraphQLField) { return fieldDef.name.slice(0, 2) === '__'; } ================================================ FILE: packages/codemirror-graphql/src/utils/__tests__/jsonParse.test.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import jsonParse, { ParseTokenOutput } from '../jsonParse'; describe('jsonParse', () => { function expectEscapedString( str: string, key: ParseTokenOutput, value: ParseTokenOutput, ) { const ast = jsonParse(str); expect(ast.kind).toBe('Object'); expect(ast.members[0].key).toStrictEqual(key); expect(ast.members[0].value).toStrictEqual(value); } it('correctly parses escaped strings', () => { expectEscapedString( '{ "test": "\\"" }', { kind: 'String', start: 2, end: 8, value: 'test' }, { kind: 'String', start: 10, end: 14, value: '"' }, ); expectEscapedString( '{ "test": "\\\\" }', { kind: 'String', start: 2, end: 8, value: 'test' }, { kind: 'String', start: 10, end: 14, value: '\\' }, ); expectEscapedString( '{ "slash": "\\/" }', { kind: 'String', start: 2, end: 9, value: 'slash' }, { kind: 'String', start: 11, end: 15, value: '/' }, ); }); }); ================================================ FILE: packages/codemirror-graphql/src/utils/collectVariables.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import { DocumentNode, GraphQLSchema, NamedTypeNode, typeFromAST, } from 'graphql'; /** * Provided a schema and a document, produces a `variableToType` Object. */ export default function collectVariables( schema: GraphQLSchema, documentAST: DocumentNode, ) { const variableToType = Object.create(null); for (const definition of documentAST.definitions) { if (definition.kind === 'OperationDefinition') { const { variableDefinitions } = definition; if (variableDefinitions) { for (const { variable, type } of variableDefinitions) { const inputType = typeFromAST(schema, type as NamedTypeNode); if (inputType) { variableToType[variable.name.value] = inputType; } } } } } return variableToType; } ================================================ FILE: packages/codemirror-graphql/src/utils/forEachState.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import type { State, Maybe } from 'graphql-language-service'; // Utility for iterating through a CodeMirror parse state stack bottom-up. export default function forEachState(stack: State, fn: (state: State) => void) { const reverseStateStack = []; let state: Maybe = stack; while (state?.kind) { reverseStateStack.push(state); state = state.prevState; } for (let i = reverseStateStack.length - 1; i >= 0; i--) { fn(reverseStateStack[i]); } } ================================================ FILE: packages/codemirror-graphql/src/utils/getTypeInfo.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import { isCompositeType, getNullableType, getNamedType, GraphQLEnumType, GraphQLInputObjectType, GraphQLList, GraphQLSchema, GraphQLType, GraphQLObjectType, GraphQLField, GraphQLDirective, GraphQLArgument, GraphQLInputType, GraphQLEnumValue, GraphQLInputFieldMap, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, } from 'graphql'; import type { State, Maybe } from 'graphql-language-service'; import forEachState from './forEachState'; export interface TypeInfo { schema: GraphQLSchema; type?: Maybe; parentType?: Maybe; inputType?: Maybe; directiveDef?: Maybe; fieldDef?: Maybe>; argDef?: Maybe; argDefs?: Maybe; enumValue?: Maybe; objectFieldDefs?: Maybe; } /** * Utility for collecting rich type information given any token's state * from the graphql-mode parser. */ export default function getTypeInfo(schema: GraphQLSchema, tokenState: State) { const info: TypeInfo = { schema, type: null, parentType: null, inputType: null, directiveDef: null, fieldDef: null, argDef: null, argDefs: null, objectFieldDefs: null, }; forEachState(tokenState, (state: State) => { switch (state.kind) { case 'Query': case 'ShortQuery': info.type = schema.getQueryType(); break; case 'Mutation': info.type = schema.getMutationType(); break; case 'Subscription': info.type = schema.getSubscriptionType(); break; case 'InlineFragment': case 'FragmentDefinition': if (state.type) { info.type = schema.getType(state.type); } break; case 'Field': case 'AliasedField': info.fieldDef = info.type && state.name ? getFieldDef(schema, info.parentType, state.name) : null; info.type = info.fieldDef?.type; break; case 'SelectionSet': info.parentType = info.type ? getNamedType(info.type) : null; break; case 'Directive': info.directiveDef = state.name ? schema.getDirective(state.name) : null; break; case 'Arguments': const parentDef = state.prevState ? state.prevState.kind === 'Field' ? info.fieldDef : state.prevState.kind === 'Directive' ? info.directiveDef : state.prevState.kind === 'AliasedField' ? state.prevState.name && getFieldDef(schema, info.parentType, state.prevState.name) : null : null; info.argDefs = parentDef ? (parentDef.args as GraphQLArgument[]) : null; break; case 'Argument': info.argDef = null; if (info.argDefs) { for (let i = 0; i < info.argDefs.length; i++) { if (info.argDefs[i].name === state.name) { info.argDef = info.argDefs[i]; break; } } } info.inputType = info.argDef?.type; break; case 'EnumValue': const enumType = info.inputType ? getNamedType(info.inputType) : null; info.enumValue = enumType instanceof GraphQLEnumType ? find( enumType.getValues() as GraphQLEnumValue[], val => val.value === state.name, ) : null; break; case 'ListValue': const nullableType = info.inputType ? getNullableType(info.inputType) : null; info.inputType = nullableType instanceof GraphQLList ? nullableType.ofType : null; break; case 'ObjectValue': const objectType = info.inputType ? getNamedType(info.inputType) : null; info.objectFieldDefs = objectType instanceof GraphQLInputObjectType ? objectType.getFields() : null; break; case 'ObjectField': const objectField = state.name && info.objectFieldDefs ? info.objectFieldDefs[state.name] : null; info.inputType = objectField?.type; // @ts-expect-error info.fieldDef = objectField; break; case 'NamedType': info.type = state.name ? schema.getType(state.name) : null; break; } }); return info; } // Gets the field definition given a type and field name function getFieldDef( schema: GraphQLSchema, type: Maybe, fieldName: string, ) { if (fieldName === SchemaMetaFieldDef.name && schema.getQueryType() === type) { return SchemaMetaFieldDef; } if (fieldName === TypeMetaFieldDef.name && schema.getQueryType() === type) { return TypeMetaFieldDef; } if (fieldName === TypeNameMetaFieldDef.name && isCompositeType(type)) { return TypeNameMetaFieldDef; } if (type && (type as GraphQLObjectType).getFields) { return (type as GraphQLObjectType).getFields()[fieldName]; } } // Returns the first item in the array which causes predicate to return truthy. function find(array: T[], predicate: (item: T) => boolean) { for (let i = 0; i < array.length; i++) { if (predicate(array[i])) { return array[i]; } } } ================================================ FILE: packages/codemirror-graphql/src/utils/hintList.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import type CodeMirror from 'codemirror'; import { IHint, IHints } from '../hint'; // Create the expected hint response given a possible list and a token export default function hintList( cursor: CodeMirror.Position, token: CodeMirror.Token, list: IHint[], ): IHints | undefined { const hints = filterAndSortList(list, normalizeText(token.string)); if (!hints) { return; } const tokenStart = token.type !== null && /"|\w/.test(token.string[0]) ? token.start : token.end; return { list: hints, from: { line: cursor.line, ch: tokenStart }, // TODO: Confirm. Was changed column to ch to: { line: cursor.line, ch: token.end }, }; } // Given a list of hint entries and currently typed text, sort and filter to // provide a concise list. function filterAndSortList(list: IHint[], text: string) { if (!text) { return filterNonEmpty(list, entry => !entry.isDeprecated); } const byProximity = list.map(entry => ({ proximity: getProximity(normalizeText(entry.text), text), entry, })); const conciseMatches = filterNonEmpty( filterNonEmpty(byProximity, pair => pair.proximity <= 2), pair => !pair.entry.isDeprecated, ); const sortedMatches = conciseMatches.sort( (a, b) => (a.entry.isDeprecated ? 1 : 0) - (b.entry.isDeprecated ? 1 : 0) || a.proximity - b.proximity || a.entry.text.length - b.entry.text.length, ); return sortedMatches.map(pair => pair.entry); } // Filters the array by the predicate, unless it results in an empty array, // in which case return the original array. function filterNonEmpty(array: T[], predicate: (item: T) => boolean) { const filtered = array.filter(predicate); return filtered.length === 0 ? array : filtered; } function normalizeText(text: string) { return text.toLowerCase().replaceAll(/\W/g, ''); } // Determine a numeric proximity for a suggestion based on current text. function getProximity(suggestion: string, text: string) { // start with lexical distance let proximity = lexicalDistance(text, suggestion); if (suggestion.length > text.length) { // do not penalize long suggestions. proximity -= suggestion.length - text.length - 1; // penalize suggestions not starting with this phrase proximity += suggestion.indexOf(text) === 0 ? 0 : 0.5; } return proximity; } /** * Computes the lexical distance between strings A and B. * * The "distance" between two strings is given by counting the minimum number * of edits needed to transform string A into string B. An edit can be an * insertion, deletion, or substitution of a single character, or a swap of two * adjacent characters. * * This distance can be useful for detecting typos in input or sorting * * @param {string} a * @param {string} b * @return {int} distance in number of edits */ function lexicalDistance(a: string, b: string) { let i; let j; const d = []; const aLength = a.length; const bLength = b.length; for (i = 0; i <= aLength; i++) { d[i] = [i]; } for (j = 1; j <= bLength; j++) { d[0][j] = j; } for (i = 1; i <= aLength; i++) { for (j = 1; j <= bLength; j++) { const cost = a[i - 1] === b[j - 1] ? 0 : 1; d[i][j] = Math.min( d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost, ); if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) { d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost); } } } return d[aLength][bLength]; } ================================================ FILE: packages/codemirror-graphql/src/utils/info-addon.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import { GraphQLInfoOptions } from '../info'; CodeMirror.defineOption( 'info', false, ( cm: CodeMirror.Editor, options: GraphQLInfoOptions, old?: GraphQLInfoOptions, ) => { if (old && old !== CodeMirror.Init) { const oldOnMouseOver = cm.state.info.onMouseOver; CodeMirror.off(cm.getWrapperElement(), 'mouseover', oldOnMouseOver); clearTimeout(cm.state.info.hoverTimeout); delete cm.state.info; } if (options) { const state: Record = (cm.state.info = createState(options)); state.onMouseOver = onMouseOver.bind(null, cm); CodeMirror.on(cm.getWrapperElement(), 'mouseover', state.onMouseOver); } }, ); function createState(options: GraphQLInfoOptions) { return { options: options instanceof Function ? { render: options } : options === true ? {} : options, }; } function getHoverTime(cm: CodeMirror.Editor) { const { options } = cm.state.info; return options?.hoverTime || 500; } function onMouseOver(cm: CodeMirror.Editor, e: MouseEvent) { const state = cm.state.info; const target = e.target || e.srcElement; if (!(target instanceof HTMLElement)) { return; } if (target.nodeName !== 'SPAN' || state.hoverTimeout !== undefined) { return; } const box = target.getBoundingClientRect(); const onMouseMove = function () { clearTimeout(state.hoverTimeout); state.hoverTimeout = setTimeout(onHover, hoverTime); }; const onMouseOut = function () { CodeMirror.off(document, 'mousemove', onMouseMove); CodeMirror.off(cm.getWrapperElement(), 'mouseout', onMouseOut); clearTimeout(state.hoverTimeout); state.hoverTimeout = undefined; }; const onHover = function () { CodeMirror.off(document, 'mousemove', onMouseMove); CodeMirror.off(cm.getWrapperElement(), 'mouseout', onMouseOut); state.hoverTimeout = undefined; onMouseHover(cm, box); }; const hoverTime = getHoverTime(cm); state.hoverTimeout = setTimeout(onHover, hoverTime); CodeMirror.on(document, 'mousemove', onMouseMove); CodeMirror.on(cm.getWrapperElement(), 'mouseout', onMouseOut); } function onMouseHover(cm: CodeMirror.Editor, box: DOMRect) { const pos = cm.coordsChar( { left: (box.left + box.right) / 2, top: (box.top + box.bottom) / 2, }, 'window', ); // 'window' allows to work when editor is not full page and window has scrolled const state = cm.state.info; const { options } = state; const render = options.render || cm.getHelper(pos, 'info'); if (render) { const token = cm.getTokenAt(pos, true); if (token) { const info: HTMLDivElement = render(token, options, cm, pos); if (info) { showPopup(cm, box, info); } } } } function showPopup(cm: CodeMirror.Editor, box: DOMRect, info: HTMLDivElement) { const popup = document.createElement('div'); popup.className = 'CodeMirror-info'; popup.append(info); document.body.append(popup); const popupBox = popup.getBoundingClientRect(); const { marginLeft, marginRight, marginBottom, marginTop } = getComputedStyle(popup); const popupWidth = popupBox.right - popupBox.left + parseFloat(marginLeft) + parseFloat(marginRight); const popupHeight = popupBox.bottom - popupBox.top + parseFloat(marginTop) + parseFloat(marginBottom); let topPos = box.bottom; if ( popupHeight > window.innerHeight - box.bottom - 15 && box.top > window.innerHeight - box.bottom ) { topPos = box.top - popupHeight; } if (topPos < 0) { topPos = box.bottom; } let leftPos = Math.max(0, window.innerWidth - popupWidth - 15); if (leftPos > box.left) { leftPos = box.left; } popup.style.opacity = '1'; popup.style.top = topPos + 'px'; popup.style.left = leftPos + 'px'; let popupTimeout: NodeJS.Timeout; const onMouseOverPopup = function () { clearTimeout(popupTimeout); }; const onMouseOut = function () { clearTimeout(popupTimeout); popupTimeout = setTimeout(hidePopup, 200); }; const hidePopup = function () { CodeMirror.off(popup, 'mouseover', onMouseOverPopup); CodeMirror.off(popup, 'mouseout', onMouseOut); CodeMirror.off(cm.getWrapperElement(), 'mouseout', onMouseOut); if (popup.style.opacity) { popup.style.opacity = '0'; setTimeout(() => { if (popup.parentNode) { popup.remove(); } }, 600); } else if (popup.parentNode) { popup.remove(); } }; CodeMirror.on(popup, 'mouseover', onMouseOverPopup); CodeMirror.on(popup, 'mouseout', onMouseOut); CodeMirror.on(cm.getWrapperElement(), 'mouseout', onMouseOut); } ================================================ FILE: packages/codemirror-graphql/src/utils/jsonParse.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ /** * This JSON parser simply walks the input, generating an AST. Use this in lieu * of JSON.parse if you need character offset parse errors and an AST parse tree * with location information. * * If an error is encountered, a SyntaxError will be thrown, with properties: * * - message: string * - start: int - the start inclusive offset of the syntax error * - end: int - the end exclusive offset of the syntax error * */ export default function jsonParse(str: string) { string = str; strLen = str.length; start = end = lastEnd = -1; ch(); lex(); const ast = parseObj(); expect('EOF'); return ast; } let string: string; let strLen: number; let start: number; let end: number; let lastEnd: number; let code: number; let kind: string; interface BaseParseOutput { kind: string; start: number; end: number; } export interface ParseTokenOutput extends BaseParseOutput { value: any; } export interface ParseObjectOutput extends BaseParseOutput { kind: 'Object'; members: ParseMemberOutput[]; } export interface ParseArrayOutput extends BaseParseOutput { kind: 'Array'; values?: ParseValueOutput[]; } export interface ParseMemberOutput extends BaseParseOutput { key: ParseTokenOutput | null; value?: ParseValueOutput; } export type ParseValueOutput = | ParseTokenOutput | ParseObjectOutput | ParseArrayOutput | undefined; function parseObj(): ParseObjectOutput { const nodeStart = start; const members = []; expect('{'); if (!skip('}')) { do { members.push(parseMember()); } while (skip(',')); expect('}'); } return { kind: 'Object', start: nodeStart, end: lastEnd, members, }; } function parseMember(): ParseMemberOutput { const nodeStart = start; const key = kind === 'String' ? curToken() : null; expect('String'); expect(':'); const value = parseVal(); return { kind: 'Member', start: nodeStart, end: lastEnd, key, value, }; } function parseArr(): ParseArrayOutput { const nodeStart = start; const values = []; expect('['); if (!skip(']')) { do { values.push(parseVal()); } while (skip(',')); expect(']'); } return { kind: 'Array', start: nodeStart, end: lastEnd, values, }; } function parseVal(): ParseValueOutput | undefined { switch (kind) { case '[': return parseArr(); case '{': return parseObj(); case 'String': case 'Number': case 'Boolean': case 'Null': const token = curToken(); lex(); return token; } expect('Value'); } function curToken(): ParseTokenOutput { return { kind, start, end, value: JSON.parse(string.slice(start, end)) }; } function expect(str: string) { if (kind === str) { lex(); return; } let found; if (kind === 'EOF') { found = '[end of file]'; } else if (end - start > 1) { found = '`' + string.slice(start, end) + '`'; } else { const match = string.slice(start).match(/^.+?\b/); found = '`' + (match ? match[0] : string[start]) + '`'; } throw syntaxError(`Expected ${str} but found ${found}.`); } type SyntaxErrorPosition = { start: number; end: number }; export class JSONSyntaxError extends Error { readonly position: SyntaxErrorPosition; constructor(message: string, position: SyntaxErrorPosition) { super(message); this.position = position; } } function syntaxError(message: string) { return new JSONSyntaxError(message, { start, end }); } function skip(k: string) { if (kind === k) { lex(); return true; } } function ch() { if (end < strLen) { end++; code = end === strLen ? 0 : string.charCodeAt(end); } return code; } function lex() { lastEnd = end; while (code === 9 || code === 10 || code === 13 || code === 32) { ch(); } if (code === 0) { kind = 'EOF'; return; } start = end; switch (code) { // " case 34: kind = 'String'; return readString(); // -, 0-9 case 45: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: kind = 'Number'; return readNumber(); // f case 102: if (string.slice(start, start + 5) !== 'false') { break; } end += 4; ch(); kind = 'Boolean'; return; // n case 110: if (string.slice(start, start + 4) !== 'null') { break; } end += 3; ch(); kind = 'Null'; return; // t case 116: if (string.slice(start, start + 4) !== 'true') { break; } end += 3; ch(); kind = 'Boolean'; return; } kind = string[start]; ch(); } function readString() { ch(); while (code !== 34 && code > 31) { if (code === 92) { // \ code = ch(); switch (code) { case 34: // " case 47: // / case 92: // \ case 98: // b case 102: // f case 110: // n case 114: // r case 116: // t ch(); break; case 117: // u ch(); readHex(); readHex(); readHex(); readHex(); break; default: throw syntaxError('Bad character escape sequence.'); } } else if (end === strLen) { throw syntaxError('Unterminated string.'); } else { ch(); } } if (code === 34) { ch(); return; } throw syntaxError('Unterminated string.'); } function readHex() { if ( (code >= 48 && code <= 57) || // 0-9 (code >= 65 && code <= 70) || // A-F (code >= 97 && code <= 102) // a-f ) { return ch(); } throw syntaxError('Expected hexadecimal digit.'); } function readNumber() { if (code === 45) { // - ch(); } if (code === 48) { // 0 ch(); } else { readDigits(); } if (code === 46) { // . ch(); readDigits(); } if (code === 69 || code === 101) { // E e code = ch(); if (code === 43 || code === 45) { // + - ch(); } readDigits(); } } function readDigits() { if (code < 48 || code > 57) { // 0 - 9 throw syntaxError('Expected decimal digit.'); } do { ch(); } while (code >= 48 && code <= 57); // 0 - 9 } ================================================ FILE: packages/codemirror-graphql/src/utils/jump-addon.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import { GraphQLJumpOptions } from '../jump'; CodeMirror.defineOption( 'jump', false, ( cm: CodeMirror.Editor, options: GraphQLJumpOptions, old?: GraphQLJumpOptions, ) => { if (old && old !== CodeMirror.Init) { const oldOnMouseOver = cm.state.jump.onMouseOver; CodeMirror.off(cm.getWrapperElement(), 'mouseover', oldOnMouseOver); const oldOnMouseOut = cm.state.jump.onMouseOut; CodeMirror.off(cm.getWrapperElement(), 'mouseout', oldOnMouseOut); CodeMirror.off(document, 'keydown', cm.state.jump.onKeyDown); delete cm.state.jump; } if (options) { const state = (cm.state.jump = { options, onMouseOver: onMouseOver.bind(null, cm), onMouseOut: onMouseOut.bind(null, cm), onKeyDown: onKeyDown.bind(null, cm), }); CodeMirror.on(cm.getWrapperElement(), 'mouseover', state.onMouseOver); CodeMirror.on(cm.getWrapperElement(), 'mouseout', state.onMouseOut); CodeMirror.on(document, 'keydown', state.onKeyDown); } }, ); function onMouseOver(cm: CodeMirror.Editor, event: MouseEvent) { const target = event.target || event.srcElement; if (!(target instanceof HTMLElement)) { return; } if (target?.nodeName !== 'SPAN') { return; } const box = target.getBoundingClientRect(); const cursor = { left: (box.left + box.right) / 2, top: (box.top + box.bottom) / 2, }; cm.state.jump.cursor = cursor; if (cm.state.jump.isHoldingModifier) { enableJumpMode(cm); } } function onMouseOut(cm: CodeMirror.Editor) { if (!cm.state.jump.isHoldingModifier && cm.state.jump.cursor) { cm.state.jump.cursor = null; return; } if (cm.state.jump.isHoldingModifier && cm.state.jump.marker) { disableJumpMode(cm); } } function onKeyDown(cm: CodeMirror.Editor, event: KeyboardEvent) { if (cm.state.jump.isHoldingModifier || !isJumpModifier(event.key)) { return; } cm.state.jump.isHoldingModifier = true; if (cm.state.jump.cursor) { enableJumpMode(cm); } const onKeyUp = (upEvent: KeyboardEvent) => { if (upEvent.code !== event.code) { return; } cm.state.jump.isHoldingModifier = false; if (cm.state.jump.marker) { disableJumpMode(cm); } CodeMirror.off(document, 'keyup', onKeyUp); CodeMirror.off(document, 'click', onClick); cm.off('mousedown', onMouseDown); }; const onClick = (clickEvent: MouseEvent) => { const { destination, options } = cm.state.jump; if (destination) { options.onClick(destination, clickEvent); } }; const onMouseDown = (_: any, downEvent: MouseEvent) => { if (cm.state.jump.destination) { (downEvent as any).codemirrorIgnore = true; } }; CodeMirror.on(document, 'keyup', onKeyUp); CodeMirror.on(document, 'click', onClick); cm.on('mousedown', onMouseDown); } const isMac = typeof navigator !== 'undefined' && navigator.userAgent.includes('Mac'); function isJumpModifier(key: string) { return key === (isMac ? 'Meta' : 'Control'); } function enableJumpMode(cm: CodeMirror.Editor) { if (cm.state.jump.marker) { return; } const { cursor, options } = cm.state.jump; const pos = cm.coordsChar(cursor); const token = cm.getTokenAt(pos, true); const getDestination = options.getDestination || cm.getHelper(pos, 'jump'); if (getDestination) { const destination = getDestination(token, options, cm); if (destination) { const marker = cm.markText( { line: pos.line, ch: token.start }, { line: pos.line, ch: token.end }, { className: 'CodeMirror-jump-token' }, ); cm.state.jump.marker = marker; cm.state.jump.destination = destination; } } } function disableJumpMode(cm: CodeMirror.Editor) { const { marker } = cm.state.jump; cm.state.jump.marker = null; cm.state.jump.destination = null; marker.clear(); } ================================================ FILE: packages/codemirror-graphql/src/utils/mode-factory.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import { LexRules, ParseRules, isIgnored, onlineParser, } from 'graphql-language-service'; import indent from './mode-indent'; /** * The GraphQL mode is defined as a tokenizer along with a list of rules, each * of which is either a function or an array. * * * Function: Provided a token and the stream, returns an expected next step. * * Array: A list of steps to take in order. * * A step is either another rule, or a terminal description of a token. If it * is a rule, that rule is pushed onto the stack and the parsing continues from * that point. * * If it is a terminal description, the token is checked against it using a * `match` function. If the match is successful, the token is colored and the * rule is stepped forward. If the match is unsuccessful, the remainder of the * rule is skipped and the previous rule is advanced. * * This parsing algorithm allows for incremental online parsing within various * levels of the syntax tree and results in a structured `state` linked-list * which contains the relevant information to produce valuable typeahead. */ const graphqlModeFactory: CodeMirror.ModeFactory = config => { const parser = onlineParser({ eatWhitespace: stream => stream.eatWhile(isIgnored), lexRules: LexRules, parseRules: ParseRules, editorConfig: { tabSize: config.tabSize }, }); return { config, startState: parser.startState, token: parser.token as unknown as NonNullable< CodeMirror.Mode['token'] >, // TODO: Check if the types are indeed compatible indent, electricInput: /^\s*[})\]]/, fold: 'brace', lineComment: '#', closeBrackets: { pairs: '()[]{}""', explode: '()[]{}', }, }; }; export default graphqlModeFactory; ================================================ FILE: packages/codemirror-graphql/src/utils/mode-indent.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import { State } from 'graphql-language-service'; // Seems the electricInput type in @types/codemirror is wrong (i.e it is written all lowercase) export default function indent( this: CodeMirror.Mode & { electricInput?: RegExp; config?: CodeMirror.EditorConfiguration; }, state: State, textAfter: string, ) { const { levels, indentLevel } = state; // If there is no stack of levels, use the current level. // Otherwise, use the top level, preemptively dedenting for close braces. const level = !levels || levels.length === 0 ? indentLevel : levels.at(-1)! - (this.electricInput?.test(textAfter) ? 1 : 0); return (level || 0) * (this.config?.indentUnit || 0); } ================================================ FILE: packages/codemirror-graphql/src/utils/runParser.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import { CharacterStream, onlineParser, ParserOptions, State, } from 'graphql-language-service'; export default function runParser( sourceText: string, parserOptions: ParserOptions, callbackFn: (stream: CharacterStream, state: State, style: string) => void, ) { const parser = onlineParser(parserOptions); const state = parser.startState(); const lines = sourceText.split('\n'); for (const line of lines) { const stream = new CharacterStream(line); while (!stream.eol()) { const style = parser.token(stream, state); callbackFn(stream, state, style); } } } ================================================ FILE: packages/codemirror-graphql/src/variables/__tests__/hint.test.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import 'codemirror/addon/hint/show-hint'; import { GraphQLEnumType, GraphQLInputObjectType, parse } from 'graphql'; import { IHint, IHints } from '../../hint'; import collectVariables from '../../utils/collectVariables'; import { TestSchema } from '../../__tests__/testSchema'; import '../hint'; import '../mode'; function createEditorWithHint(query: string) { return CodeMirror(document.createElement('div'), { mode: 'graphql-variables', hintOptions: { variableToType: query && collectVariables(TestSchema, parse(query)), closeOnUnfocus: false, completeSingle: false, }, }); } function getHintSuggestions( query: string, variables: string, cursor: CodeMirror.Position, ) { const editor = createEditorWithHint(query); return new Promise(resolve => { const graphqlVariablesHint = CodeMirror.hint['graphql-variables']; CodeMirror.hint['graphql-variables'] = (cm, options) => { const result = graphqlVariablesHint(cm, options); resolve(result); CodeMirror.hint['graphql-variables'] = graphqlVariablesHint; return result; }; editor.doc.setValue(variables); editor.doc.setCursor(cursor); editor.execCommand('autocomplete'); }); } function expectSuggestions(source: string[], suggestions?: IHint[]) { const titles = suggestions?.map(suggestion => suggestion.text); expect(titles).toEqual(source); } describe('graphql-variables-hint', () => { it('attaches a GraphQL hint function with correct mode/hint options', () => { const editor = createEditorWithHint('{ f }'); expect(editor.getHelpers(editor.getCursor(), 'hint')).not.toHaveLength(0); }); it('provides correct initial token', async () => { const suggestions = await getHintSuggestions('', '', { line: 0, ch: 0 }); const initialKeywords = ['{']; expectSuggestions(initialKeywords, suggestions?.list); }); it('provides correct field name suggestions', async () => { const suggestions = await getHintSuggestions( 'query ($foo: String!, $bar: Int) { f }', '{ ', { line: 0, ch: 2 }, ); expectSuggestions(['"foo": ', '"bar": '], suggestions?.list); }); it('provides correct variable suggestion indentation', async () => { const suggestions = await getHintSuggestions( 'query ($foo: String!, $bar: Int) { f }', '{\n ', { line: 1, ch: 2 }, ); expect(suggestions?.from).toEqual({ line: 1, ch: 2, sticky: null }); expect(suggestions?.to).toEqual({ line: 1, ch: 2, sticky: null }); }); it('provides correct variable completion', async () => { const suggestions = await getHintSuggestions( 'query ($foo: String!, $bar: Int) { f }', '{\n ba', { line: 1, ch: 4 }, ); expectSuggestions(['"bar": '], suggestions?.list); expect(suggestions?.from).toEqual({ line: 1, ch: 2, sticky: null }); expect(suggestions?.to).toEqual({ line: 1, ch: 4, sticky: null }); }); it('provides correct variable completion with open quote', async () => { const suggestions = await getHintSuggestions( 'query ($foo: String!, $bar: Int) { f }', '{\n "', { line: 1, ch: 4 }, ); expectSuggestions(['"foo": ', '"bar": '], suggestions?.list); expect(suggestions?.from).toEqual({ line: 1, ch: 2, sticky: null }); expect(suggestions?.to).toEqual({ line: 1, ch: 3, sticky: null }); }); it('provides correct Enum suggestions', async () => { const suggestions = await getHintSuggestions( 'query ($myEnum: TestEnum) { f }', '{\n "myEnum": ', { line: 1, ch: 12 }, ); const TestEnum = TestSchema.getType('TestEnum'); expectSuggestions( (TestEnum as GraphQLEnumType) ?.getValues() .map(value => `"${value.name}"`), suggestions?.list, ); }); it('suggests to open an Input Object', async () => { const suggestions = await getHintSuggestions( 'query ($myInput: TestInput) { f }', '{\n "myInput": ', { line: 1, ch: 13 }, ); expectSuggestions(['{'], suggestions?.list); }); it('provides Input Object fields', async () => { const suggestions = await getHintSuggestions( 'query ($myInput: TestInput) { f }', '{\n "myInput": {\n ', { line: 2, ch: 4 }, ); const TestInput = TestSchema.getType('TestInput'); expectSuggestions( Object.keys((TestInput as GraphQLInputObjectType).getFields()).map( name => `"${name}": `, ), suggestions?.list, ); expect(suggestions?.from).toEqual({ line: 2, ch: 4, sticky: null }); expect(suggestions?.to).toEqual({ line: 2, ch: 4, sticky: null }); }); it('provides correct Input Object field completion', async () => { const suggestions = await getHintSuggestions( 'query ($myInput: TestInput) { f }', '{\n "myInput": {\n bool', { line: 2, ch: 8 }, ); expectSuggestions(['"boolean": ', '"listBoolean": '], suggestions?.list); expect(suggestions?.from).toEqual({ line: 2, ch: 4, sticky: null }); expect(suggestions?.to).toEqual({ line: 2, ch: 8, sticky: null }); }); it('provides correct Input Object field value completion', async () => { const suggestions = await getHintSuggestions( 'query ($myInput: TestInput) { f }', '{\n "myInput": {\n "boolean": ', { line: 2, ch: 15 }, ); expectSuggestions(['true', 'false'], suggestions?.list); }); }); ================================================ FILE: packages/codemirror-graphql/src/variables/__tests__/lint.test.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import 'codemirror/addon/lint/lint'; import { parse } from 'graphql'; import { Maybe } from 'graphql-language-service'; import collectVariables from '../../utils/collectVariables'; import { TestSchema } from '../../__tests__/testSchema'; import '../lint'; import '../mode'; function createEditorWithLint(lintConfig?: any) { return CodeMirror(document.createElement('div'), { mode: 'graphql-variables', lint: lintConfig || true, }); } function printLintErrors(query: Maybe, variables: string) { const editor = createEditorWithLint({ variableToType: query && collectVariables(TestSchema, parse(query)), }); return new Promise(resolve => { editor.state.lint.options.onUpdateLinting = ( errors: CodeMirror.Annotation[], ) => { if (errors?.[0] && !errors[0].message?.match('Unexpected EOF')) { resolve(errors); return; } resolve([]); }; editor.doc.setValue(variables); }); } describe('graphql-variables-lint', () => { it('attaches a GraphQL lint function with correct mode/lint options', () => { const editor = createEditorWithLint(); expect(editor.getHelpers(editor.getCursor(), 'lint')).not.toHaveLength(0); }); it('catches syntax errors', async () => { expect((await printLintErrors(null, '{ foo: "bar" }'))[0].message).toBe( 'Expected String but found `foo`.', ); }); it('catches type validation errors', async () => { const errors = await printLintErrors( 'query ($foo: Int) { f }', ' { "foo": "NaN" }', ); expect(errors[0]).toEqual({ message: 'Expected value of type "Int".', severity: 'error', type: 'validation', from: { line: 0, ch: 10, sticky: null }, to: { line: 0, ch: 15, sticky: null }, }); }); it('reports unknown variable names', async () => { const errors = await printLintErrors( 'query ($foo: Int) { f }', ' { "food": "NaN" }', ); expect(errors[0]).toEqual({ message: 'Variable "$food" does not appear in any GraphQL query.', severity: 'error', type: 'validation', from: { line: 0, ch: 3, sticky: null }, to: { line: 0, ch: 9, sticky: null }, }); }); it('reports nothing when not configured', async () => { const errors = await printLintErrors(null, ' { "foo": "NaN" }'); expect(errors.length).toBe(0); }); }); ================================================ FILE: packages/codemirror-graphql/src/variables/__tests__/mode.test.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import 'codemirror/addon/runmode/runmode'; import '../mode'; describe('graphql-variables-mode', () => { it('provides correct tokens and styles after parsing', () => { const queryStr = '{ "variable": { "field": "value" }, "list": [ 1, true, null ] }'; const tokens: [string, string][] = []; CodeMirror.runMode(queryStr, 'graphql-variables', (token, style) => { if (style && style !== 'ws') { tokens.push([token, style]); } }); expect(tokens).toEqual([ ['{', 'punctuation'], ['"variable"', 'variable'], [':', 'punctuation'], ['{', 'punctuation'], ['"field"', 'attribute'], [':', 'punctuation'], ['"value"', 'string'], ['}', 'punctuation'], [',', 'punctuation'], ['"list"', 'variable'], [':', 'punctuation'], ['[', 'punctuation'], ['1', 'number'], [',', 'punctuation'], ['true', 'builtin'], [',', 'punctuation'], ['null', 'keyword'], [']', 'punctuation'], ['}', 'punctuation'], ]); }); it('is resilient to missing commas', () => { const queryStr = '{ "variable": { "field": "value" } "list": [ 1 true null ] }'; const tokens: [string, string][] = []; CodeMirror.runMode(queryStr, 'graphql-variables', (token, style) => { if (style && style !== 'ws') { tokens.push([token, style]); } }); expect(tokens).toEqual([ ['{', 'punctuation'], ['"variable"', 'variable'], [':', 'punctuation'], ['{', 'punctuation'], ['"field"', 'attribute'], [':', 'punctuation'], ['"value"', 'string'], ['}', 'punctuation'], ['"list"', 'variable'], [':', 'punctuation'], ['[', 'punctuation'], ['1', 'number'], ['true', 'builtin'], ['null', 'keyword'], [']', 'punctuation'], ['}', 'punctuation'], ]); }); it('returns "invalidchar" message when there is no matching token', () => { CodeMirror.runMode('nope', 'graphql-variables', (token, style) => { if (token.trim()) { expect(style).toBe('invalidchar'); } }); CodeMirror.runMode('{ foo', 'graphql-variables', (token, style) => { if (token === 'foo') { expect(style).toBe('invalidchar'); } }); }); }); ================================================ FILE: packages/codemirror-graphql/src/variables/hint.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror, { Hints } from 'codemirror'; import { getNullableType, getNamedType, GraphQLEnumType, GraphQLInputObjectType, GraphQLList, GraphQLBoolean, GraphQLInputType, GraphQLInputFieldMap, } from 'graphql'; import type { State, Maybe } from 'graphql-language-service'; import { IHints } from '../hint'; import forEachState from '../utils/forEachState'; import hintList from '../utils/hintList'; export type VariableToType = Record; interface GraphQLVariableHintOptions { variableToType: VariableToType; } declare module 'codemirror' { interface ShowHintOptions { variableToType?: VariableToType; } interface CodeMirrorHintMap { 'graphql-variables': ( editor: CodeMirror.Editor, options: GraphQLVariableHintOptions, ) => IHints | undefined; } } /** * Registers a "hint" helper for CodeMirror. * * Using CodeMirror's "hint" addon: https://codemirror.net/demo/complete.html * Given an editor, this helper will take the token at the cursor and return a * list of suggested tokens. * * Options: * * - variableToType: { [variable: string]: GraphQLInputType } * * Additional Events: * * - hasCompletion (codemirror, data, token) - signaled when the hinter has a * new list of completion suggestions. * */ CodeMirror.registerHelper( 'hint', 'graphql-variables', ( editor: CodeMirror.Editor, options: GraphQLVariableHintOptions, ): Hints | undefined => { const cur = editor.getCursor(); const token = editor.getTokenAt(cur); const results = getVariablesHint(cur, token, options); if (results?.list && results.list.length > 0) { results.from = CodeMirror.Pos(results.from.line, results.from.ch); results.to = CodeMirror.Pos(results.to.line, results.to.ch); CodeMirror.signal(editor, 'hasCompletion', editor, results, token); } return results; }, ); function getVariablesHint( cur: CodeMirror.Position, token: CodeMirror.Token, options: GraphQLVariableHintOptions, ) { // If currently parsing an invalid state, attempt to hint to the prior state. const state = token.state.kind === 'Invalid' ? token.state.prevState : token.state; const { kind, step } = state; // Variables can only be an object literal. if (kind === 'Document' && step === 0) { return hintList(cur, token, [{ text: '{' }]); } const { variableToType } = options; if (!variableToType) { return; } const typeInfo = getTypeInfo(variableToType, token.state); // Top level should typeahead possible variables. if (kind === 'Document' || (kind === 'Variable' && step === 0)) { const variableNames = Object.keys(variableToType); return hintList( cur, token, variableNames.map(name => ({ text: `"${name}": `, type: variableToType[name], })), ); } // Input Object fields if ( (kind === 'ObjectValue' || (kind === 'ObjectField' && step === 0)) && typeInfo.fields ) { const inputFields = Object.keys(typeInfo.fields).map( fieldName => typeInfo.fields![fieldName], ); return hintList( cur, token, inputFields.map(field => ({ text: `"${field.name}": `, type: field.type, description: field.description, })), ); } // Input values. if ( kind === 'StringValue' || kind === 'NumberValue' || kind === 'BooleanValue' || kind === 'NullValue' || (kind === 'ListValue' && step === 1) || (kind === 'ObjectField' && step === 2) || (kind === 'Variable' && step === 2) ) { const namedInputType = typeInfo.type ? getNamedType(typeInfo.type) : undefined; if (namedInputType instanceof GraphQLInputObjectType) { return hintList(cur, token, [{ text: '{' }]); } if (namedInputType instanceof GraphQLEnumType) { const values = namedInputType.getValues(); // const values = Object.keys(valueMap).map(name => valueMap[name]); // TODO: Previously added return hintList( cur, token, values.map(value => ({ text: `"${value.name}"`, type: namedInputType, description: value.description, })), ); } if (namedInputType === GraphQLBoolean) { return hintList(cur, token, [ { text: 'true', type: GraphQLBoolean, description: 'Not false.' }, // TODO: type and description don't seem to be used. Added them as optional anyway. { text: 'false', type: GraphQLBoolean, description: 'Not true.' }, ]); } } } interface VariableTypeInfo { type?: Maybe; fields?: Maybe; } // Utility for collecting rich type information given any token's state // from the graphql-variables-mode parser. function getTypeInfo( variableToType: Record, tokenState: State, ) { const info: VariableTypeInfo = { type: null, fields: null, }; forEachState(tokenState, state => { switch (state.kind) { case 'Variable': { info.type = variableToType[state.name!]; break; } case 'ListValue': { const nullableType = info.type ? getNullableType(info.type) : undefined; info.type = nullableType instanceof GraphQLList ? nullableType.ofType : null; break; } case 'ObjectValue': { const objectType = info.type ? getNamedType(info.type) : undefined; info.fields = objectType instanceof GraphQLInputObjectType ? objectType.getFields() : null; break; } case 'ObjectField': { const objectField = state.name && info.fields ? info.fields[state.name] : null; info.type = objectField?.type; break; } } }); return info; } ================================================ FILE: packages/codemirror-graphql/src/variables/lint.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import { GraphQLEnumType, GraphQLInputObjectType, GraphQLList, GraphQLNonNull, GraphQLScalarType, GraphQLType, } from 'graphql'; import jsonParse, { JSONSyntaxError, ParseArrayOutput, ParseObjectOutput, ParseValueOutput, } from '../utils/jsonParse'; import { VariableToType } from './hint'; interface GraphQLVariableLintOptions { variableToType: VariableToType; } /** * Registers a "lint" helper for CodeMirror. * * Using CodeMirror's "lint" addon: https://codemirror.net/demo/lint.html * Given the text within an editor, this helper will take that text and return * a list of linter issues ensuring that correct variables were provided. * * Options: * * - variableToType: { [variable: string]: GraphQLInputType } * */ CodeMirror.registerHelper( 'lint', 'graphql-variables', ( text: string, options: GraphQLVariableLintOptions, editor: CodeMirror.Editor, ) => { // If there's no text, do nothing. if (!text) { return []; } // First, linter needs to determine if there are any parsing errors. let ast; try { ast = jsonParse(text); } catch (error) { if (error instanceof JSONSyntaxError) { return [lintError(editor, error.position, error.message)]; } throw error; } // If there are not yet known variables, do nothing. const { variableToType } = options; if (!variableToType) { return []; } // Then highlight any issues with the provided variables. return validateVariables(editor, variableToType, ast); }, ); // Given a variableToType object, a source text, and a JSON AST, produces a // list of CodeMirror annotations for any variable validation errors. function validateVariables( editor: CodeMirror.Editor, variableToType: VariableToType, variablesAST: ParseObjectOutput, ) { const errors: CodeMirror.Annotation[] = []; for (const member of variablesAST.members) { if (member) { const variableName = member.key?.value; const type = variableToType[variableName]; if (type) { for (const [node, message] of validateValue(type, member.value)) { errors.push(lintError(editor, node, message)); } } else { errors.push( lintError( editor, member.key!, `Variable "$${variableName}" does not appear in any GraphQL query.`, ), ); } } } return errors; } // Returns a list of validation errors in the form Array<[Node, String]>. function validateValue( type?: GraphQLType, valueAST?: ParseValueOutput, ): any[][] { // TODO: Can't figure out the right type. if (!type || !valueAST) { return []; } // Validate non-nullable values. if (type instanceof GraphQLNonNull) { if (valueAST.kind === 'Null') { return [[valueAST, `Type "${type}" is non-nullable and cannot be null.`]]; } return validateValue(type.ofType, valueAST); } if (valueAST.kind === 'Null') { return []; } // Validate lists of values, accepting a non-list as a list of one. if (type instanceof GraphQLList) { const itemType = type.ofType; if (valueAST.kind === 'Array') { const values = (valueAST as ParseArrayOutput).values || []; return mapCat(values, item => validateValue(itemType, item)); } return validateValue(itemType, valueAST); } // Validate input objects. if (type instanceof GraphQLInputObjectType) { if (valueAST.kind !== 'Object') { return [[valueAST, `Type "${type}" must be an Object.`]]; } // Validate each field in the input object. const providedFields = Object.create(null); const fieldErrors: any[][] = mapCat( (valueAST as ParseObjectOutput).members, member => { // TODO: Can't figure out the right type here const fieldName = member?.key?.value; providedFields[fieldName] = true; const inputField = type.getFields()[fieldName]; if (!inputField) { return [ [ member.key, `Type "${type}" does not have a field "${fieldName}".`, ], ]; } const fieldType = inputField ? inputField.type : undefined; return validateValue(fieldType, member.value); }, ); // Look for missing non-nullable fields. for (const fieldName of Object.keys(type.getFields())) { const field = type.getFields()[fieldName]; if ( !providedFields[fieldName] && field.type instanceof GraphQLNonNull && !field.defaultValue ) { fieldErrors.push([ valueAST, `Object of type "${type}" is missing required field "${fieldName}".`, ]); } } return fieldErrors; } // Validate common scalars. if ( (type.name === 'Boolean' && valueAST.kind !== 'Boolean') || (type.name === 'String' && valueAST.kind !== 'String') || (type.name === 'ID' && valueAST.kind !== 'Number' && valueAST.kind !== 'String') || (type.name === 'Float' && valueAST.kind !== 'Number') || (type.name === 'Int' && // eslint-disable-next-line no-bitwise (valueAST.kind !== 'Number' || (valueAST.value | 0) !== valueAST.value)) ) { return [[valueAST, `Expected value of type "${type}".`]]; } // Validate enums and custom scalars. if ( (type instanceof GraphQLEnumType || type instanceof GraphQLScalarType) && ((valueAST.kind !== 'String' && valueAST.kind !== 'Number' && valueAST.kind !== 'Boolean' && valueAST.kind !== 'Null') || isNullish(type.parseValue(valueAST.value))) ) { return [[valueAST, `Expected value of type "${type}".`]]; } return []; } // Give a parent text, an AST node with location, and a message, produces a // CodeMirror annotation object. function lintError( editor: CodeMirror.Editor, node: { start: number; end: number }, message: string, ): CodeMirror.Annotation & { type: string } { return { message, severity: 'error', type: 'validation', from: editor.posFromIndex(node.start), to: editor.posFromIndex(node.end), }; } function isNullish(value: any): boolean { // eslint-disable-next-line no-self-compare return value === null || value === undefined || value !== value; } function mapCat(array: T[], mapper: (item: T) => R[]): R[] { return Array.prototype.concat.apply([], array.map(mapper)); } ================================================ FILE: packages/codemirror-graphql/src/variables/mode.ts ================================================ /** * Copyright (c) 2021 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ import CodeMirror from 'codemirror'; import { list, t, onlineParser, opt, p, State, Token, } from 'graphql-language-service'; import indent from '../utils/mode-indent'; /** * This mode defines JSON, but provides a data-laden parser state to enable * better code intelligence. */ CodeMirror.defineMode('graphql-variables', config => { const parser = onlineParser({ eatWhitespace: stream => stream.eatSpace(), lexRules: LexRules, parseRules: ParseRules, editorConfig: { tabSize: config.tabSize }, }); return { config, startState: parser.startState, token: parser.token as unknown as CodeMirror.Mode['token'], // TODO: Check if the types are indeed compatible indent, electricInput: /^\s*[}\]]/, fold: 'brace', closeBrackets: { pairs: '[]{}""', explode: '[]{}', }, }; }); /** * The lexer rules. These are exactly as described by the spec. */ const LexRules = { // All Punctuation used in JSON. Punctuation: /^\[|]|\{|\}|:|,/, // JSON Number. Number: /^-?(?:0|(?:[1-9][0-9]*))(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?/, // JSON String. String: /^"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?/, // JSON literal keywords. Keyword: /^true|false|null/, }; /** * The parser rules for JSON. */ const ParseRules = { Document: [p('{'), list('Variable', opt(p(','))), p('}')], Variable: [namedKey('variable'), p(':'), 'Value'], Value(token: Token) { switch (token.kind) { case 'Number': return 'NumberValue'; case 'String': return 'StringValue'; case 'Punctuation': switch (token.value) { case '[': return 'ListValue'; case '{': return 'ObjectValue'; } return null; case 'Keyword': switch (token.value) { case 'true': case 'false': return 'BooleanValue'; case 'null': return 'NullValue'; } return null; } }, NumberValue: [t('Number', 'number')], StringValue: [t('String', 'string')], BooleanValue: [t('Keyword', 'builtin')], NullValue: [t('Keyword', 'keyword')], ListValue: [p('['), list('Value', opt(p(','))), p(']')], ObjectValue: [p('{'), list('ObjectField', opt(p(','))), p('}')], ObjectField: [namedKey('attribute'), p(':'), 'Value'], }; // A namedKey Token which will decorate the state with a `name` function namedKey(style: string) { return { style, match: (token: Token) => token.kind === 'String', update(state: State, token: Token) { state.name = token.value.slice(1, -1); // Remove quotes. }, }; } ================================================ FILE: packages/codemirror-graphql/tsconfig.esm.json ================================================ { "extends": "../../resources/tsconfig.base.esm.json", "compilerOptions": { "rootDir": "./src", "outDir": "./esm", "composite": true, "jsx": "react", "strictPropertyInitialization": false, "baseUrl": "." }, "include": ["src"], "exclude": [ "**/__tests__/**", "**/dist/**.*", "**/*.spec.ts", "**/*.spec.js", "**/*-test.ts", "**/*-test.js" ], "references": [ { "path": "../graphql-language-service" } ] } ================================================ FILE: packages/codemirror-graphql/tsconfig.json ================================================ { "extends": "../../resources/tsconfig.base.cjs.json", "compilerOptions": { "rootDir": "./src", "outDir": "./", "composite": true, "jsx": "react", "target": "es5", "baseUrl": ".", "strictPropertyInitialization": false }, "include": ["src"], "exclude": [ "**/__tests__/**", "**/dist/**.*", "**/esm/**.*", "**/*.spec.ts", "**/*.spec.js", "**/*-test.ts", "**/*-test.js" ], "references": [ { "path": "../graphql-language-service" } ] } ================================================ FILE: packages/codemirror-graphql/vitest.config.mts ================================================ import { defineConfig } from 'vitest/config'; import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); export default defineConfig({ test: { globals: true, environment: 'jsdom', setupFiles: ['./setup-files.ts'], alias: { // fixes Duplicate "graphql" modules cannot be used at the same time since different graphql: require.resolve('graphql'), }, }, }); ================================================ FILE: packages/graphiql/CHANGELOG.md ================================================ # Change Log ## 5.2.2 ### Patch Changes - [#4133](https://github.com/graphql/graphiql/pull/4133) [`1bc6568`](https://github.com/graphql/graphiql/commit/1bc6568da947394c216342ae75fb509fdbf03390) Thanks [@dimaMachina](https://github.com/dimaMachina)! - to fix esm.sh example we should pin `monaco-editor` peer dependency to versions `≥ 0.20.0 and < 0.53`, since `monaco-editor@^0.53.0` isn't supported yet with `monaco-graphql` - Updated dependencies [[`1bc6568`](https://github.com/graphql/graphiql/commit/1bc6568da947394c216342ae75fb509fdbf03390)]: - @graphiql/react@0.37.3 ## 5.2.1 ### Patch Changes - [#4124](https://github.com/graphql/graphiql/pull/4124) [`d77abe6`](https://github.com/graphql/graphiql/commit/d77abe647e700ef8949a16c3bccda648d5c6adae) Thanks [@dimaMachina](https://github.com/dimaMachina)! - pin `monaco-editor` to `0.52.2` - Updated dependencies [[`d77abe6`](https://github.com/graphql/graphiql/commit/d77abe647e700ef8949a16c3bccda648d5c6adae)]: - @graphiql/react@0.37.2 ## 5.2.0 ### Minor Changes - [#4081](https://github.com/graphql/graphiql/pull/4081) [`4950dec`](https://github.com/graphql/graphiql/commit/4950decaddb816ef3e3d22d814d976d94405029e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat: add loader for initial loading of operation editor fix: adjust command palette `width`, `border` and remove `box-shadow` feat: add short cut `Cmd/Ctrl + ,` for opening GraphiQL settings dialog ### Patch Changes - Updated dependencies [[`4950dec`](https://github.com/graphql/graphiql/commit/4950decaddb816ef3e3d22d814d976d94405029e)]: - @graphiql/react@0.37.1 ## 5.1.1 ### Patch Changes - [#4078](https://github.com/graphql/graphiql/pull/4078) [`6e5d5fc`](https://github.com/graphql/graphiql/commit/6e5d5fce9a7eb5770f40300fc153e0b9b10edfbf) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix color in the F1 popup should be graphiql primary color and add deprecated exports for `useEditorStore`, `useExecutionStore`, `usePluginStore` and `useSchemaStore` - Updated dependencies [[`6e5d5fc`](https://github.com/graphql/graphiql/commit/6e5d5fce9a7eb5770f40300fc153e0b9b10edfbf), [`293beed`](https://github.com/graphql/graphiql/commit/293beed772baa2be834cad5f19e1aee0628e15cc)]: - @graphiql/react@0.37.0 - @graphiql/plugin-doc-explorer@0.4.1 - @graphiql/plugin-history@0.4.1 ## 5.1.0 ### Minor Changes - [#4071](https://github.com/graphql/graphiql/pull/4071) [`3a0a755`](https://github.com/graphql/graphiql/commit/3a0a75569c6b318f5dc27d62000bcc9b0536c6fd) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(graphql-language-service): export `getContextAtPosition` feat(graphiql): dynamically import `monaco-editor` and `monaco-graphql` When using GraphiQL in Next.js app, you no longer need to use `next/dynamic`: ```diff -import dynamic from 'next/dynamic' -const GraphiQL = dynamic(() => import('graphiql').then(mod => mod.GraphiQL), { - ssr: false -}) +import { GraphiQL } from 'graphiql' ``` - [#4074](https://github.com/graphql/graphiql/pull/4074) [`fd3f9e6`](https://github.com/graphql/graphiql/commit/fd3f9e6a91be728a69a136ad8680f6e3c7241198) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Ensure `storage` and `theme` store values aren't shared between GraphiQL instances. Deprecate `useTheme` and `useStorage` hooks in favour of values from `useGraphiQL` and `useGraphiQLActions` hooks feat(`@graphiql/plugin-history`/`@graphiql/plugin-doc-explorer`): move `@graphiql/react` to `peerDependencies` - [#4077](https://github.com/graphql/graphiql/pull/4077) [`3d41e11`](https://github.com/graphql/graphiql/commit/3d41e113fbf53930fd1b519b6d1330d0f4b23b7b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - add new example [Usage GraphiQL 5 with Vite, React Router and `ssr: true`](https://github.com/graphql/graphiql/tree/main/examples/example-graphiql-vite-react-router) ### Patch Changes - [#4076](https://github.com/graphql/graphiql/pull/4076) [`416e3a0`](https://github.com/graphql/graphiql/commit/416e3a05e9473eb2abd444da61ecfb8614020d14) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix broken `useOperationsEditorState` and `useEditorState` hook and add unit tests - Updated dependencies [[`3a0a755`](https://github.com/graphql/graphiql/commit/3a0a75569c6b318f5dc27d62000bcc9b0536c6fd), [`fd3f9e6`](https://github.com/graphql/graphiql/commit/fd3f9e6a91be728a69a136ad8680f6e3c7241198), [`416e3a0`](https://github.com/graphql/graphiql/commit/416e3a05e9473eb2abd444da61ecfb8614020d14), [`3d41e11`](https://github.com/graphql/graphiql/commit/3d41e113fbf53930fd1b519b6d1330d0f4b23b7b)]: - @graphiql/react@0.36.0 - @graphiql/plugin-history@0.4.0 - @graphiql/plugin-doc-explorer@0.4.0 ## 5.0.6 ### Patch Changes - [#4069](https://github.com/graphql/graphiql/pull/4069) [`142f3f2`](https://github.com/graphql/graphiql/commit/142f3f2529c668aa1a6ba2f7269cf4b7e2fd3e61) Thanks [@dimaMachina](https://github.com/dimaMachina)! - reduce bundle size, import `prettier` dynamically to avoid bundling Prettier diff from vite example ```diff -dist/assets/index-BMgFrxsd.js 4,911.53 kB │ gzip: 1,339.77 kB +dist/assets/index-BlpzusGL.js 4,221.28 kB │ gzip: 1,145.58 kB ``` - Updated dependencies [[`142f3f2`](https://github.com/graphql/graphiql/commit/142f3f2529c668aa1a6ba2f7269cf4b7e2fd3e61)]: - @graphiql/react@0.35.6 ## 5.0.5 ### Patch Changes - [#4065](https://github.com/graphql/graphiql/pull/4065) [`962225a`](https://github.com/graphql/graphiql/commit/962225ad74c8b69101f900c63243612560ddd501) Thanks [@benjie](https://github.com/benjie)! - Expose the `GraphiQLInterfaceProps` type. ## 5.0.4 ### Patch Changes - [#4061](https://github.com/graphql/graphiql/pull/4061) [`8f14fff`](https://github.com/graphql/graphiql/commit/8f14fff26e0d804b5f4ecf307b7b29bb78664973) Thanks [@dimaMachina](https://github.com/dimaMachina)! - add `graphiql.css`, CSS file without importing fonts and monaco-editor styles - [#4059](https://github.com/graphql/graphiql/pull/4059) [`a4382bf`](https://github.com/graphql/graphiql/commit/a4382bfae28efd6e03153cf8aa81f55db43de6ed) Thanks [@dimaMachina](https://github.com/dimaMachina)! - export `GraphiQLInterface` - [#4063](https://github.com/graphql/graphiql/pull/4063) [`44b18e4`](https://github.com/graphql/graphiql/commit/44b18e4ed054d757568b5cfedc43614fd7ea3fc9) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix `useOperationsEditorState` wasn't returned updated return value - Updated dependencies [[`44b18e4`](https://github.com/graphql/graphiql/commit/44b18e4ed054d757568b5cfedc43614fd7ea3fc9)]: - @graphiql/react@0.35.5 ## 5.0.3 ### Patch Changes - [#4052](https://github.com/graphql/graphiql/pull/4052) [`9b54581`](https://github.com/graphql/graphiql/commit/9b54581e74a7e6c6354a810c2288869fb85f24eb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix multiple GraphiQL instances, suffix a unique id for operation, request headers, variables and response URI. E.g., the first GraphiQL instance will have: - `1-operation.graphql` - `1-request-headers.json` - `1-variables.json` - `1-response.json` The 2nd instance will have: - `2-operation.graphql` - `2-request-headers.json` - `2-variables.json` - `2-response.json` etc. - [#4049](https://github.com/graphql/graphiql/pull/4049) [`2c0586d`](https://github.com/graphql/graphiql/commit/2c0586d1f3db8fe8dc604032010cc9840d10b72d) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - use `allowTrailingComma` option in jsonc parser to make `tryParseJsonObject` sync - parse introspection headers with jsonc parser - use prettier format for operation editor since we already use prettier for jsonc editors - [#4050](https://github.com/graphql/graphiql/pull/4050) [`002f133`](https://github.com/graphql/graphiql/commit/002f1336db4bdafa01cff1964a1b56ba858699eb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix can't access property "jsonDefaults" - Updated dependencies [[`9b54581`](https://github.com/graphql/graphiql/commit/9b54581e74a7e6c6354a810c2288869fb85f24eb), [`2c0586d`](https://github.com/graphql/graphiql/commit/2c0586d1f3db8fe8dc604032010cc9840d10b72d), [`002f133`](https://github.com/graphql/graphiql/commit/002f1336db4bdafa01cff1964a1b56ba858699eb)]: - @graphiql/react@0.35.4 ## 5.0.2 ### Patch Changes - [#4046](https://github.com/graphql/graphiql/pull/4046) [`8b56462`](https://github.com/graphql/graphiql/commit/8b564625b2470652db3c27dc70b0f85d5bbc3a0f) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Enable font ligatures in monaco-editors fix incorrect caret position on Windows - Updated dependencies [[`8b56462`](https://github.com/graphql/graphiql/commit/8b564625b2470652db3c27dc70b0f85d5bbc3a0f)]: - @graphiql/react@0.35.3 ## 5.0.1 ### Patch Changes - [#4044](https://github.com/graphql/graphiql/pull/4044) [`68b347c`](https://github.com/graphql/graphiql/commit/68b347c78faa80cc00397fc1705dbf114c1f374b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix `Fixes Uncaught Error: can't access property "offsetNode", hitResult is null` on Mozilla - Updated dependencies [[`68b347c`](https://github.com/graphql/graphiql/commit/68b347c78faa80cc00397fc1705dbf114c1f374b)]: - @graphiql/react@0.35.2 ## 5.0.0 ### Major Changes - [#3990](https://github.com/graphql/graphiql/pull/3990) [`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - allow multiple independent instances of GraphiQL on the same page - store `onClickReference` in query editor in React `ref` - remove `onClickReference` from variable editor - fix shortcut text per OS for run query in execute query button's tooltip and in default query - allow override all default GraphiQL plugins - adjust operation argument color to be purple from GraphiQL v2 on dark/light theme - [#3999](https://github.com/graphql/graphiql/pull/3999) [`866a8f3`](https://github.com/graphql/graphiql/commit/866a8f39a27d213315ccc55ec06353bb3280b270) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update graphiql-cdn example to show how to load workers with esm.sh - [#4009](https://github.com/graphql/graphiql/pull/4009) [`4936492`](https://github.com/graphql/graphiql/commit/49364924d0da05a86f7c6c3139d44aed0e474531) Thanks [@dimaMachina](https://github.com/dimaMachina)! - separate store actions from state, add `useGraphiQLActions` state - [#4002](https://github.com/graphql/graphiql/pull/4002) [`2d9faec`](https://github.com/graphql/graphiql/commit/2d9faec57830b38aa175929c47a55c959c327535) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove UMD builds - [#4005](https://github.com/graphql/graphiql/pull/4005) [`1e3ec84`](https://github.com/graphql/graphiql/commit/1e3ec8455706e62e6cae306df58d3343ec6b612d) Thanks [@dimaMachina](https://github.com/dimaMachina)! - support `externalFragments` prop and remove `validationRules` prop - [#4003](https://github.com/graphql/graphiql/pull/4003) [`0c8e390`](https://github.com/graphql/graphiql/commit/0c8e3906cf58055f898cb173b2e912a494ae8439) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove `readOnly` prop document `keyMap` prop was removed in migration guide - [#3735](https://github.com/graphql/graphiql/pull/3735) [`0a08642`](https://github.com/graphql/graphiql/commit/0a0864268da4f340e30a1e9b8191d34e33ffbfa7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - Remove `query`, `variables`, `headers`, and `response` props from `` and `` - Add `initialQuery`, `initialVariables` and `initialHeaders` props - Fix `defaultQuery`, when is set will only be used for the first tab. When opening more tabs, the query editor will start out empty - remove `useSynchronizeValue` hook - [#3966](https://github.com/graphql/graphiql/pull/3966) [`17bee1c`](https://github.com/graphql/graphiql/commit/17bee1ced4637cfa5e0e6cddc7716d89cfa49687) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Remove examples: `GraphiQL x Parcel` and `GraphiQL x Create React App` Add new examples: `GraphiQL x Vite` and `GraphiQL x Next.js` - [#3234](https://github.com/graphql/graphiql/pull/3234) [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Migration from Codemirror to [Monaco Editor](https://github.com/microsoft/monaco-editor) Replacing `codemirror-graphql` with [`monaco-graphql`](https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql) Support for comments in **Variables** and **Headers** editors ### Minor Changes - [#4017](https://github.com/graphql/graphiql/pull/4017) [`cff3da5`](https://github.com/graphql/graphiql/commit/cff3da541184d36d1c2e5c919dd4231e9905ccbb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - extract graphiql sidebar to react component - [#4025](https://github.com/graphql/graphiql/pull/4025) [`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - set "importsNotUsedAsValues": "error" in tsconfig - [#4026](https://github.com/graphql/graphiql/pull/4026) [`7fb5ac3`](https://github.com/graphql/graphiql/commit/7fb5ac38b8ec27f0234adc06aacf42e71f6a259b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - deprecate `useExplorerContext`, `useHistoryContext`, `usePrettifyEditors`, `useCopyQuery`, `useMergeQuery`, `useExecutionContext`, `usePluginContext`, `useSchemaContext`, `useStorageContext` hooks - fix response editor overflow on `` - export `GraphiQLProps` type - allow `children: ReactNode` for `` - change `ToolbarMenu` component: - The `label` and `className` props were removed - The `button` prop should now be a button element - document `useGraphiQL` and `useGraphiQLActions` hooks in `@graphiql/react` README.md - rename `useThemeStore` to `useTheme` ### Patch Changes - [#3949](https://github.com/graphql/graphiql/pull/3949) [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - replace `onCopyQuery` hook with `copyQuery` function - replace `onMergeQuery` hook with `mergeQuery` function - replace `onPrettifyEditors` hook with `prettifyEditors` function - remove `fetcher` prop from `SchemaContextProvider` and `schemaStore` and add `fetcher` to `executionStore` - add `onCopyQuery` and `onPrettifyQuery` props to `EditorContextProvider` - remove exports (use `GraphiQLProvider`) - `EditorContextProvider` - `ExecutionContextProvider` - `PluginContextProvider` - `SchemaContextProvider` - `StorageContextProvider` - `ExecutionContextType` - `PluginContextType` - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - prefer `getComputedStyle` over `window.getComputedStyle` - [#4008](https://github.com/graphql/graphiql/pull/4008) [`e0dafa4`](https://github.com/graphql/graphiql/commit/e0dafa4cf86edffc8344c11f2c0a5280d873585a) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - add f1 command as first item in shortcut table - set color of `quickInputList.focusForeground` in command palette to be primary color - [#3950](https://github.com/graphql/graphiql/pull/3950) [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - remove `useQueryEditor`, `useVariableEditor`, `useHeaderEditor`, `useResponseEditor` hooks - remove `UseHeaderEditorArgs`, `UseQueryEditorArgs`, `UseResponseEditorArgs`, `UseVariableEditorArgs` exports - rename components - `StorageContextProvider` => `StorageStore` - `EditorContextProvider` => `EditorStore` - `SchemaContextProvider` => `SchemaStore` - `ExecutionContextProvider` => `ExecutionStore` - `HistoryContextProvider` => `HistoryStore` - `ExplorerContextProvider` => `ExplorerStore` - Updated dependencies [[`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92), [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e), [`866a8f3`](https://github.com/graphql/graphiql/commit/866a8f39a27d213315ccc55ec06353bb3280b270), [`4936492`](https://github.com/graphql/graphiql/commit/49364924d0da05a86f7c6c3139d44aed0e474531), [`7792dc9`](https://github.com/graphql/graphiql/commit/7792dc98814abcd6dc5f5cd94ae84c308a260dcf), [`f9780bd`](https://github.com/graphql/graphiql/commit/f9780bd44f67acad0a9bb10f57eb6059db60e1ec), [`3c0ad34`](https://github.com/graphql/graphiql/commit/3c0ad34a8f2f9d0f912db9597f608d7405c2bd83), [`1e3ec84`](https://github.com/graphql/graphiql/commit/1e3ec8455706e62e6cae306df58d3343ec6b612d), [`0c8e390`](https://github.com/graphql/graphiql/commit/0c8e3906cf58055f898cb173b2e912a494ae8439), [`0a08642`](https://github.com/graphql/graphiql/commit/0a0864268da4f340e30a1e9b8191d34e33ffbfa7), [`cff3da5`](https://github.com/graphql/graphiql/commit/cff3da541184d36d1c2e5c919dd4231e9905ccbb), [`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b), [`16fdd6a`](https://github.com/graphql/graphiql/commit/16fdd6a16684c9f250ee53ea2dfbb24435cee6a9), [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91), [`30bc3f9`](https://github.com/graphql/graphiql/commit/30bc3f9cae4dbb11649a0952dad092e192ad653c), [`4b39f11`](https://github.com/graphql/graphiql/commit/4b39f1118d008c2fac6e2df9c94a3f3271c4eeb9), [`7fb5ac3`](https://github.com/graphql/graphiql/commit/7fb5ac38b8ec27f0234adc06aacf42e71f6a259b), [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb)]: - @graphiql/plugin-doc-explorer@0.3.0 - @graphiql/plugin-history@0.3.0 - @graphiql/react@0.35.0 ## 5.0.0-rc.6 ### Major Changes - [#3735](https://github.com/graphql/graphiql/pull/3735) [`0a08642`](https://github.com/graphql/graphiql/commit/0a0864268da4f340e30a1e9b8191d34e33ffbfa7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - Remove `query`, `variables`, `headers`, and `response` props from `` and `` - Add `initialQuery`, `initialVariables` and `initialHeaders` props - Fix `defaultQuery`, when is set will only be used for the first tab. When opening more tabs, the query editor will start out empty - remove `useSynchronizeValue` hook ### Patch Changes - Updated dependencies [[`0a08642`](https://github.com/graphql/graphiql/commit/0a0864268da4f340e30a1e9b8191d34e33ffbfa7)]: - @graphiql/react@0.35.0-rc.9 ## 5.0.0-rc.5 ### Minor Changes - [#4025](https://github.com/graphql/graphiql/pull/4025) [`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - set "importsNotUsedAsValues": "error" in tsconfig - [#4026](https://github.com/graphql/graphiql/pull/4026) [`7fb5ac3`](https://github.com/graphql/graphiql/commit/7fb5ac38b8ec27f0234adc06aacf42e71f6a259b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - deprecate `useExplorerContext`, `useHistoryContext`, `usePrettifyEditors`, `useCopyQuery`, `useMergeQuery`, `useExecutionContext`, `usePluginContext`, `useSchemaContext`, `useStorageContext` hooks - fix response editor overflow on `` - export `GraphiQLProps` type - allow `children: ReactNode` for `` - change `ToolbarMenu` component: - The `label` and `className` props were removed - The `button` prop should now be a button element - document `useGraphiQL` and `useGraphiQLActions` hooks in `@graphiql/react` README.md - rename `useThemeStore` to `useTheme` ### Patch Changes - Updated dependencies [[`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b), [`7fb5ac3`](https://github.com/graphql/graphiql/commit/7fb5ac38b8ec27f0234adc06aacf42e71f6a259b)]: - @graphiql/plugin-doc-explorer@0.3.0-rc.4 - @graphiql/plugin-history@0.3.0-rc.3 - @graphiql/react@0.35.0-rc.8 ## 5.0.0-rc.4 ### Minor Changes - [#4017](https://github.com/graphql/graphiql/pull/4017) [`cff3da5`](https://github.com/graphql/graphiql/commit/cff3da541184d36d1c2e5c919dd4231e9905ccbb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - extract graphiql sidebar to react component ### Patch Changes - Updated dependencies [[`cff3da5`](https://github.com/graphql/graphiql/commit/cff3da541184d36d1c2e5c919dd4231e9905ccbb)]: - @graphiql/react@0.35.0-rc.6 ## 5.0.0-rc.3 ### Major Changes - [#4009](https://github.com/graphql/graphiql/pull/4009) [`4936492`](https://github.com/graphql/graphiql/commit/49364924d0da05a86f7c6c3139d44aed0e474531) Thanks [@dimaMachina](https://github.com/dimaMachina)! - separate store actions from state, add `useGraphiQLActions` state ### Patch Changes - Updated dependencies [[`4936492`](https://github.com/graphql/graphiql/commit/49364924d0da05a86f7c6c3139d44aed0e474531)]: - @graphiql/plugin-doc-explorer@0.3.0-rc.3 - @graphiql/react@0.35.0-rc.3 ## 5.0.0-rc.2 ### Major Changes - [#3999](https://github.com/graphql/graphiql/pull/3999) [`866a8f3`](https://github.com/graphql/graphiql/commit/866a8f39a27d213315ccc55ec06353bb3280b270) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update graphiql-cdn example to show how to load workers with esm.sh - [#4002](https://github.com/graphql/graphiql/pull/4002) [`2d9faec`](https://github.com/graphql/graphiql/commit/2d9faec57830b38aa175929c47a55c959c327535) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove UMD builds - [#4005](https://github.com/graphql/graphiql/pull/4005) [`1e3ec84`](https://github.com/graphql/graphiql/commit/1e3ec8455706e62e6cae306df58d3343ec6b612d) Thanks [@dimaMachina](https://github.com/dimaMachina)! - support `externalFragments` prop and remove `validationRules` prop - [#4003](https://github.com/graphql/graphiql/pull/4003) [`0c8e390`](https://github.com/graphql/graphiql/commit/0c8e3906cf58055f898cb173b2e912a494ae8439) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove `readOnly` prop document `keyMap` prop was removed in migration guide ### Patch Changes - [#4008](https://github.com/graphql/graphiql/pull/4008) [`e0dafa4`](https://github.com/graphql/graphiql/commit/e0dafa4cf86edffc8344c11f2c0a5280d873585a) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - add f1 command as first item in shortcut table - set color of `quickInputList.focusForeground` in command palette to be primary color - Updated dependencies [[`866a8f3`](https://github.com/graphql/graphiql/commit/866a8f39a27d213315ccc55ec06353bb3280b270), [`7792dc9`](https://github.com/graphql/graphiql/commit/7792dc98814abcd6dc5f5cd94ae84c308a260dcf), [`f9780bd`](https://github.com/graphql/graphiql/commit/f9780bd44f67acad0a9bb10f57eb6059db60e1ec), [`1e3ec84`](https://github.com/graphql/graphiql/commit/1e3ec8455706e62e6cae306df58d3343ec6b612d), [`0c8e390`](https://github.com/graphql/graphiql/commit/0c8e3906cf58055f898cb173b2e912a494ae8439), [`16fdd6a`](https://github.com/graphql/graphiql/commit/16fdd6a16684c9f250ee53ea2dfbb24435cee6a9)]: - @graphiql/react@0.35.0-rc.2 - @graphiql/plugin-doc-explorer@0.3.0-rc.2 ## 5.0.0-rc.1 ### Major Changes - [#3990](https://github.com/graphql/graphiql/pull/3990) [`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - allow multiple independent instances of GraphiQL on the same page - store `onClickReference` in query editor in React `ref` - remove `onClickReference` from variable editor - fix shortcut text per OS for run query in execute query button's tooltip and in default query - allow override all default GraphiQL plugins - adjust operation argument color to be purple from GraphiQL v2 on dark/light theme ### Patch Changes - Updated dependencies [[`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92)]: - @graphiql/plugin-doc-explorer@0.3.0-rc.1 - @graphiql/plugin-history@0.3.0-rc.1 - @graphiql/react@0.35.0-rc.1 ## 5.0.0-rc.0 ### Major Changes - [#3966](https://github.com/graphql/graphiql/pull/3966) [`17bee1c`](https://github.com/graphql/graphiql/commit/17bee1ced4637cfa5e0e6cddc7716d89cfa49687) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Remove examples: `GraphiQL x Parcel` and `GraphiQL x Create React App` Add new examples: `GraphiQL x Vite` and `GraphiQL x Next.js` - [#3234](https://github.com/graphql/graphiql/pull/3234) [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Migration from Codemirror to [Monaco Editor](https://github.com/microsoft/monaco-editor) Replacing `codemirror-graphql` with [`monaco-graphql`](https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql) Support for comments in **Variables** and **Headers** editors ### Patch Changes - [#3949](https://github.com/graphql/graphiql/pull/3949) [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - replace `onCopyQuery` hook with `copyQuery` function - replace `onMergeQuery` hook with `mergeQuery` function - replace `onPrettifyEditors` hook with `prettifyEditors` function - remove `fetcher` prop from `SchemaContextProvider` and `schemaStore` and add `fetcher` to `executionStore` - add `onCopyQuery` and `onPrettifyQuery` props to `EditorContextProvider` - remove exports (use `GraphiQLProvider`) - `EditorContextProvider` - `ExecutionContextProvider` - `PluginContextProvider` - `SchemaContextProvider` - `StorageContextProvider` - `ExecutionContextType` - `PluginContextType` - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - prefer `getComputedStyle` over `window.getComputedStyle` - [#3950](https://github.com/graphql/graphiql/pull/3950) [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - remove `useQueryEditor`, `useVariableEditor`, `useHeaderEditor`, `useResponseEditor` hooks - remove `UseHeaderEditorArgs`, `UseQueryEditorArgs`, `UseResponseEditorArgs`, `UseVariableEditorArgs` exports - rename components - `StorageContextProvider` => `StorageStore` - `EditorContextProvider` => `EditorStore` - `SchemaContextProvider` => `SchemaStore` - `ExecutionContextProvider` => `ExecutionStore` - `HistoryContextProvider` => `HistoryStore` - `ExplorerContextProvider` => `ExplorerStore` - Updated dependencies [[`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e), [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91), [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb)]: - @graphiql/plugin-doc-explorer@0.3.0-rc.0 - @graphiql/plugin-history@0.3.0-rc.0 - @graphiql/react@0.35.0-rc.0 ## 4.1.2 ### Patch Changes - [#3993](https://github.com/graphql/graphiql/pull/3993) [`70d2216`](https://github.com/graphql/graphiql/commit/70d22164d67b925f3342800161a2b568997bd689) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix `TypeError: Cannot read properties of null (reading 'get')` and update graphiql webpack example to show how to use `useStorage` hook with `GraphiQL` component ## 4.1.1 ### Patch Changes - [#3970](https://github.com/graphql/graphiql/pull/3970) [`7054591`](https://github.com/graphql/graphiql/commit/70545912d1b3bb9e0c45e766a5c89896a9c4dfb7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - revert https://github.com/graphql/graphiql/pull/3946 to have support multiple embedded graphiql instances on the same page - Updated dependencies [[`7054591`](https://github.com/graphql/graphiql/commit/70545912d1b3bb9e0c45e766a5c89896a9c4dfb7)]: - @graphiql/plugin-doc-explorer@0.2.2 - @graphiql/plugin-history@0.2.2 - @graphiql/react@0.34.1 ## 4.1.0 ### Minor Changes - [#3946](https://github.com/graphql/graphiql/pull/3946) [`71755b7`](https://github.com/graphql/graphiql/commit/71755b7f412f8f3dd9f5194d3f1e0168b9ad07af) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - replace `useAutoCompleteLeafs` hook with `getAutoCompleteLeafs` function ### Patch Changes - [#3963](https://github.com/graphql/graphiql/pull/3963) [`6d631e2`](https://github.com/graphql/graphiql/commit/6d631e2e558d038476fe235b1506bc52ecf68781) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix headers are not set in the refetch of introspection query - Updated dependencies [[`71755b7`](https://github.com/graphql/graphiql/commit/71755b7f412f8f3dd9f5194d3f1e0168b9ad07af), [`6d631e2`](https://github.com/graphql/graphiql/commit/6d631e2e558d038476fe235b1506bc52ecf68781)]: - @graphiql/plugin-doc-explorer@0.2.1 - @graphiql/plugin-history@0.2.1 - @graphiql/react@0.34.0 ## 4.0.5 ### Patch Changes - [#3945](https://github.com/graphql/graphiql/pull/3945) [`117627b`](https://github.com/graphql/graphiql/commit/117627b451607198dd7b9dc19e76da8a71d14b71) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand, replace `usePluginContext` with `usePluginStore` hook - [#3947](https://github.com/graphql/graphiql/pull/3947) [`fa78481`](https://github.com/graphql/graphiql/commit/fa784819ce020346052901019079fb5b44af6ef0) Thanks [@dimaMachina](https://github.com/dimaMachina)! - refactor `useStorage`, `useDocExplorer` and `useHistory` hooks - [#3943](https://github.com/graphql/graphiql/pull/3943) [`7275472`](https://github.com/graphql/graphiql/commit/727547236bbd4fc721069ceae63eb8a6acffa57e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand, replace `useSchemaContext` with `useSchemaStore` hook - [#3942](https://github.com/graphql/graphiql/pull/3942) [`00c8605`](https://github.com/graphql/graphiql/commit/00c8605e1f3068e6547a5a9e969571a86a57f921) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand, replace `useStorageContext` with `useStorage` hook - Updated dependencies [[`117627b`](https://github.com/graphql/graphiql/commit/117627b451607198dd7b9dc19e76da8a71d14b71), [`fa78481`](https://github.com/graphql/graphiql/commit/fa784819ce020346052901019079fb5b44af6ef0), [`7275472`](https://github.com/graphql/graphiql/commit/727547236bbd4fc721069ceae63eb8a6acffa57e), [`00c8605`](https://github.com/graphql/graphiql/commit/00c8605e1f3068e6547a5a9e969571a86a57f921)]: - @graphiql/plugin-doc-explorer@0.2.0 - @graphiql/plugin-history@0.2.0 - @graphiql/react@0.33.0 ## 4.0.4 ### Patch Changes - [#3940](https://github.com/graphql/graphiql/pull/3940) [`5a66864`](https://github.com/graphql/graphiql/commit/5a668647e1cbca9e846bfa617f97fbae21c821bd) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/plugin-doc-explorer): migrate React context to zustand, replace `useExplorerContext` with `useDocExplorer` and `useDocExplorerActions` hooks - Updated dependencies [[`5a66864`](https://github.com/graphql/graphiql/commit/5a668647e1cbca9e846bfa617f97fbae21c821bd)]: - @graphiql/plugin-doc-explorer@0.1.0 ## 4.0.3 ### Patch Changes - [#3938](https://github.com/graphql/graphiql/pull/3938) [`9f55d93`](https://github.com/graphql/graphiql/commit/9f55d930c8a63b1683740cc7e51531fe09059b72) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix unable override `referencePlugin` prop - [#3936](https://github.com/graphql/graphiql/pull/3936) [`2bfbb06`](https://github.com/graphql/graphiql/commit/2bfbb06e416cabc46951a137b61a12a571f0c937) Thanks [@dimaMachina](https://github.com/dimaMachina)! - add scroll-x to graphiql tabs area - [#3939](https://github.com/graphql/graphiql/pull/3939) [`69ad489`](https://github.com/graphql/graphiql/commit/69ad489678d0096432d5c4b1749d87343f4ed1f7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - prefer `React.FC` type when declaring React components - [#3937](https://github.com/graphql/graphiql/pull/3937) [`2500288`](https://github.com/graphql/graphiql/commit/250028863f6eefe4167ff9f9c23168ccf0a85b7b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove `Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format` warnings on SSR - [#3935](https://github.com/graphql/graphiql/pull/3935) [`5985e13`](https://github.com/graphql/graphiql/commit/5985e135fcc38a0ce90bf5a5d2cc344ec6b36aab) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/plugin-history): migrate React context to zustand, replace `useHistoryContext` with `useHistory`, `useHistoryActions` hooks - Updated dependencies [[`2bfbb06`](https://github.com/graphql/graphiql/commit/2bfbb06e416cabc46951a137b61a12a571f0c937), [`69ad489`](https://github.com/graphql/graphiql/commit/69ad489678d0096432d5c4b1749d87343f4ed1f7), [`2500288`](https://github.com/graphql/graphiql/commit/250028863f6eefe4167ff9f9c23168ccf0a85b7b), [`5985e13`](https://github.com/graphql/graphiql/commit/5985e135fcc38a0ce90bf5a5d2cc344ec6b36aab)]: - @graphiql/react@0.32.2 - @graphiql/plugin-doc-explorer@0.0.2 - @graphiql/plugin-history@0.1.0 ## 4.0.2 ### Patch Changes - [#3916](https://github.com/graphql/graphiql/pull/3916) [`98d13a3`](https://github.com/graphql/graphiql/commit/98d13a3e515eb70aaf5a5ba669c680d5959fef67) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - remove the following exports from `@graphiql/react` and move them in `@graphiql/plugin-doc-explorer` package: - Argument - DefaultValue - DeprecationReason - Directive - DocExplorer - ExplorerContext - ExplorerContextProvider - ExplorerSection - FieldDocumentation - FieldLink - SchemaDocumentation - Search - TypeDocumentation - TypeLink - useExplorerContext - DOC_EXPLORER_PLUGIN - ExplorerContextType - ExplorerFieldDef - ExplorerNavStack - ExplorerNavStackItem - add new `referencePlugin` prop on `PluginContextProviderProps` component for plugin which is used to display the reference documentation when selecting a type. - Updated dependencies [[`98d13a3`](https://github.com/graphql/graphiql/commit/98d13a3e515eb70aaf5a5ba669c680d5959fef67)]: - @graphiql/plugin-doc-explorer@0.0.1 - @graphiql/react@0.32.0 - @graphiql/plugin-history@0.0.2 ## 4.0.1 ### Patch Changes - [#3911](https://github.com/graphql/graphiql/pull/3911) [`e7c436b`](https://github.com/graphql/graphiql/commit/e7c436b329a68981bdbd2b662be94875a546a1d6) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - export `cn` from `@graphiql/react` - remove following exports from `@graphiql/react` and move them in `@graphiql/plugin-history` package: - `History` - `HistoryContext` - `HistoryContextType` - `HistoryContextProvider` - `useHistoryContext` - `HISTORY_PLUGIN` - remove types from `@graphiql/react` (use `ComponentProps` instead): - `HistoryContextProviderProps` - `ExecutionContextProviderProps` - `EditorContextProviderProps` - `ExplorerContextProviderProps` - `PluginContextProviderProps` - `SchemaContextProviderProps` - `StorageContextProviderProps` - `GraphiQLProviderProps` - [#3915](https://github.com/graphql/graphiql/pull/3915) [`bc31cd9`](https://github.com/graphql/graphiql/commit/bc31cd99a92693238e7359456e3cc22ed0387df0) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix unpkg.com results to `Not found` when `main` field isn't specified in `package.json` - Updated dependencies [[`e7c436b`](https://github.com/graphql/graphiql/commit/e7c436b329a68981bdbd2b662be94875a546a1d6)]: - @graphiql/plugin-history@0.0.1 - @graphiql/react@0.31.0 ## 4.0.0 ### Major Changes - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - drop commonjs build files - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - show tabs even there is only 1 tab - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove default export ## Migration ### Before ```jsx import GraphiQL from 'graphiql'; ``` ### After ```jsx import { GraphiQL } from 'graphiql'; ``` - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - 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 - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove `disableTabs` option - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove `data-testid="graphiql-container"` - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - changed exports ```diff -graphiql/graphiql.css +graphiql/style.css ``` changed cdn paths, `dist/index.umd.js` and `dist/style.css` are minified ```diff -https://unpkg.com/graphiql/graphiql.js -https://unpkg.com/graphiql/graphiql.min.js +https://unpkg.com/graphiql/dist/index.umd.js -https://unpkg.com/graphiql/graphiql.css -https://unpkg.com/graphiql/graphiql.min.css +https://unpkg.com/graphiql/dist/style.css ``` - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - new looks of tabs - fix `disableTabs` when `Add tab` button is still shown - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Remove `toolbar.additionalContent` and `toolbar.additionalComponent` props in favor of `GraphiQL.Toolbar` render props. ## Migration from `toolbar.additionalContent` ### Before ```jsx My button }} /> ``` ### After ```jsx {({ merge, prettify, copy }) => ( <> {prettify} {merge} {copy} )} ``` ## Migration from `toolbar.additionalComponent` ### Before ```jsx My button; }, }} /> ``` ### After ```jsx {({ merge, prettify, copy }) => ( <> {prettify} {merge} {copy} )} ``` *** Additionally, you can sort default toolbar buttons in different order or remove unneeded buttons for you: ```jsx {({ prettify, copy }) => ( <> {copy /* Copy button will be first instead of default last */} {/* Merge button is removed from toolbar */} {prettify} )} ``` ### Minor Changes - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Add support for `onPrettifyQuery` callback to enable customised query formatting - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Update GraphiQL CDN example using ESM-based CDN esm.sh - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update `vite` and related dependencies - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove `.graphiql-session` class ### Patch Changes - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update graphql to `16.9.0` and use vite `define` configuration to remove development code from cdn bundle - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Respect Markdown format: ignore single newline - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - use `position: absolute` for `.graphiql-logo` class - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - replace `overflow-y: scroll` with `overflow-y: auto` - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - rollback `position: absolute` style for `.graphiql-logo` because tabs will behind logo - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - prefer `location` over `window.location` - prefer `navigator` over `window.navigator` - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - use `right: var(--px-16)` instead of `right: 0` for `.graphiql-logo` - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - replace `Tooltip`s in tabs with html `title="..."` attribute - Updated dependencies [[`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602)]: - @graphiql/react@0.30.0 ## 4.0.0-alpha.5 ### Minor Changes - [#3733](https://github.com/graphql/graphiql/pull/3733) [`8dbddb5`](https://github.com/graphql/graphiql/commit/8dbddb50273720d76f895af6b783b04204c68e03) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Add support for `onPrettifyQuery` callback to enable customised query formatting ### Patch Changes - Updated dependencies [[`8dbddb5`](https://github.com/graphql/graphiql/commit/8dbddb50273720d76f895af6b783b04204c68e03)]: - @graphiql/react@1.0.0-alpha.4 ## 4.0.0-alpha.4 ### Minor Changes - [#3728](https://github.com/graphql/graphiql/pull/3728) [`a1a5208`](https://github.com/graphql/graphiql/commit/a1a5208aeebe4ff622e83cd355f8b4e9b7fa011c) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove `.graphiql-session` class ### Patch Changes - [#3414](https://github.com/graphql/graphiql/pull/3414) [`f8b719f`](https://github.com/graphql/graphiql/commit/f8b719f215a79038d1b2a54ddfef461fd849a912) Thanks [@leonardehrenfried](https://github.com/leonardehrenfried)! - Respect Markdown format: ignore single newline - [#3730](https://github.com/graphql/graphiql/pull/3730) [`360a038`](https://github.com/graphql/graphiql/commit/360a0385d4ef0105beb8e76044a78f5cd43c9448) Thanks [@dimaMachina](https://github.com/dimaMachina)! - rollback `position: absolute` style for `.graphiql-logo` because tabs will behind logo - [#3726](https://github.com/graphql/graphiql/pull/3726) [`196e9a0`](https://github.com/graphql/graphiql/commit/196e9a081ffc0df16a5537c8ec0fb622fc3ba0b0) Thanks [@dimaMachina](https://github.com/dimaMachina)! - use `right: var(--px-16)` instead of `right: 0` for `.graphiql-logo` - Updated dependencies [[`f8b719f`](https://github.com/graphql/graphiql/commit/f8b719f215a79038d1b2a54ddfef461fd849a912), [`360a038`](https://github.com/graphql/graphiql/commit/360a0385d4ef0105beb8e76044a78f5cd43c9448)]: - @graphiql/react@1.0.0-alpha.3 ## 4.0.0-alpha.3 ### Patch Changes - [#3720](https://github.com/graphql/graphiql/pull/3720) [`79f3abf`](https://github.com/graphql/graphiql/commit/79f3abf9b697c448442e32eb5a21b7ff720bc242) Thanks [@dimaMachina](https://github.com/dimaMachina)! - replace `overflow-y: scroll` with `overflow-y: auto` - [#3720](https://github.com/graphql/graphiql/pull/3720) [`79f3abf`](https://github.com/graphql/graphiql/commit/79f3abf9b697c448442e32eb5a21b7ff720bc242) Thanks [@dimaMachina](https://github.com/dimaMachina)! - replace `Tooltip`s in tabs with html `title="..."` attribute - Updated dependencies [[`79f3abf`](https://github.com/graphql/graphiql/commit/79f3abf9b697c448442e32eb5a21b7ff720bc242)]: - @graphiql/react@1.0.0-alpha.2 ## 4.0.0-alpha.2 ### Patch Changes - [#3716](https://github.com/graphql/graphiql/pull/3716) [`cc2808f`](https://github.com/graphql/graphiql/commit/cc2808f9b0d9ac0f98603299ec67e2a659cbfcd7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - use `position: absolute` for `.graphiql-logo` class - Updated dependencies [[`bf0c4e7`](https://github.com/graphql/graphiql/commit/bf0c4e7236f4a68448063aa0c6a4ed439e869a9f)]: - @graphiql/react@1.0.0-alpha.1 ## 4.0.0-alpha.1 ### Major Changes - [#3713](https://github.com/graphql/graphiql/pull/3713) [`27bbc51`](https://github.com/graphql/graphiql/commit/27bbc51a69504ffa9c6efbb17f112668f38fe52d) Thanks [@dimaMachina](https://github.com/dimaMachina)! - show tabs even there is only 1 tab - [#3707](https://github.com/graphql/graphiql/pull/3707) [`3c901c1`](https://github.com/graphql/graphiql/commit/3c901c104123750f45bcd64ade5b0ab9706d3146) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Remove `toolbar.additionalContent` and `toolbar.additionalComponent` props in favor of `GraphiQL.Toolbar` render props. ## Migration from `toolbar.additionalContent` #### Before ```jsx My button }} /> ``` #### After ```jsx {({ merge, prettify, copy }) => ( <> {prettify} {merge} {copy} )} ``` ### Migration from `toolbar.additionalComponent` #### Before ```jsx My button; }, }} /> ``` #### After ```jsx {({ merge, prettify, copy }) => ( <> {prettify} {merge} {copy} )} ``` *** Additionally, you can sort default toolbar buttons in different order or remove unneeded buttons for you: ```jsx {({ prettify, copy }) => ( <> {copy /* Copy button will be first instead of default last */} {/* Merge button is removed from toolbar */} {prettify} )} ``` ## 4.0.0-alpha.0 ### Major Changes - [#3706](https://github.com/graphql/graphiql/pull/3706) [`343dd59`](https://github.com/graphql/graphiql/commit/343dd599ee10b0670cd7ab4dfaa65344f0d48c84) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove default export ## Migration ### Before ```jsx import GraphiQL from 'graphiql'; ``` ### After ```jsx import { GraphiQL } from 'graphiql'; ``` - [#3687](https://github.com/graphql/graphiql/pull/3687) [`09e7004`](https://github.com/graphql/graphiql/commit/09e700403beb6c7290d165df33a2455ac2196971) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove `disableTabs` option - [#3688](https://github.com/graphql/graphiql/pull/3688) [`0fdd9b9`](https://github.com/graphql/graphiql/commit/0fdd9b9f32513d96281f577a5d9bd2fefb5f05d4) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove `data-testid="graphiql-container"` - [#3679](https://github.com/graphql/graphiql/pull/3679) [`5d90e0e`](https://github.com/graphql/graphiql/commit/5d90e0eed58214c5926e6e0edb196971b15b1121) Thanks [@dimaMachina](https://github.com/dimaMachina)! - migrate from `webpack` to `vite` changed exports ```diff -graphiql/graphiql.css +graphiql/style.css ``` changed cdn paths, `dist/index.umd.js` and `dist/style.css` are minified ```diff -https://unpkg.com/graphiql/graphiql.js -https://unpkg.com/graphiql/graphiql.min.js +https://unpkg.com/graphiql/dist/index.umd.js -https://unpkg.com/graphiql/graphiql.css -https://unpkg.com/graphiql/graphiql.min.css +https://unpkg.com/graphiql/dist/style.css ``` - [#3644](https://github.com/graphql/graphiql/pull/3644) [`3c1a345`](https://github.com/graphql/graphiql/commit/3c1a345acd9bf07b45bc230009cb57c51c425673) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - new looks of tabs - fix `disableTabs` when `Add tab` button is still shown ### Patch Changes - [#3683](https://github.com/graphql/graphiql/pull/3683) [`8efb873`](https://github.com/graphql/graphiql/commit/8efb873458489ce3497d917bcafd4ad8dfcbe6c8) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update graphql to `16.9.0` and use vite `define` configuration to remove development code from cdn bundle - [#3692](https://github.com/graphql/graphiql/pull/3692) [`82bc961`](https://github.com/graphql/graphiql/commit/82bc961a33c4e9da29dffb4a603035a4909f49ad) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - prefer `location` over `window.location` - prefer `navigator` over `window.navigator` - Updated dependencies [[`00415d2`](https://github.com/graphql/graphiql/commit/00415d2940c4d76a4a9e683e9fa0504ba97dd627), [`9baf1f0`](https://github.com/graphql/graphiql/commit/9baf1f0fc9f32404fbb8bf57b3d1c2c2c8778ddb), [`8ff87d7`](https://github.com/graphql/graphiql/commit/8ff87d7b6b3d5d12b539612a39ca3abf7e631106), [`82bc961`](https://github.com/graphql/graphiql/commit/82bc961a33c4e9da29dffb4a603035a4909f49ad), [`3c1a345`](https://github.com/graphql/graphiql/commit/3c1a345acd9bf07b45bc230009cb57c51c425673)]: - @graphiql/react@1.0.0-alpha.0 ## 3.9.0 ### Minor Changes - [#3826](https://github.com/graphql/graphiql/pull/3826) [`cb29e9f`](https://github.com/graphql/graphiql/commit/cb29e9fbe1362778bc327513fc884c4ec419775e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - remove react compiler custom patch - update `react-compiler-runtime` to use `19.1.0-rc.1` version - [#3826](https://github.com/graphql/graphiql/pull/3826) [`cb29e9f`](https://github.com/graphql/graphiql/commit/cb29e9fbe1362778bc327513fc884c4ec419775e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - migrate `graphiql` to `vite` and `react compiler` ### Patch Changes - Updated dependencies [[`cb29e9f`](https://github.com/graphql/graphiql/commit/cb29e9fbe1362778bc327513fc884c4ec419775e), [`1adc40c`](https://github.com/graphql/graphiql/commit/1adc40cc56dbf79296bb857156e6adce1c44dcbe)]: - @graphiql/react@0.29.0 ## 3.8.3 ### Patch Changes - [#3843](https://github.com/graphql/graphiql/pull/3843) [`16b5698`](https://github.com/graphql/graphiql/commit/16b56982ce4de62c850380fe25698c3893551c5a) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix regression in documentation explorer search when clicking on results in dropdown - Updated dependencies [[`16b5698`](https://github.com/graphql/graphiql/commit/16b56982ce4de62c850380fe25698c3893551c5a)]: - @graphiql/react@0.28.2 ## 3.8.2 ### Patch Changes - [#3840](https://github.com/graphql/graphiql/pull/3840) [`b529a6c`](https://github.com/graphql/graphiql/commit/b529a6c59b760f8bc54df0cd691b0704d94c022b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update `@graphiql/react` dependency range to `^0.28.1` ## 3.8.1 ### Patch Changes - Updated dependencies [[`3633d61`](https://github.com/graphql/graphiql/commit/3633d61c3c597adf60c0ec1bbf98cf6a1f49beed)]: - @graphiql/react@0.28.0 ## 3.8.0 ### Minor Changes - [#3825](https://github.com/graphql/graphiql/pull/3825) [`7cdcabf`](https://github.com/graphql/graphiql/commit/7cdcabf9d401683e90c995476b187c6f8ea70f63) Thanks [@dimaMachina](https://github.com/dimaMachina)! - migrate `graphiql` from `jest` to `vitest` ### Patch Changes - Updated dependencies [[`72f06bc`](https://github.com/graphql/graphiql/commit/72f06bc52a9bdc0cb146d65861ba7364717bbdf5)]: - @graphiql/react@0.27.1 ## 3.7.2 ### Patch Changes - Updated dependencies [[`f86e2bc`](https://github.com/graphql/graphiql/commit/f86e2bce40826b3d07755f91b37a72051de00f9c)]: - @graphiql/react@0.27.0 ## 3.7.1 ### Patch Changes - [#3751](https://github.com/graphql/graphiql/pull/3751) [`b8538d8`](https://github.com/graphql/graphiql/commit/b8538d87421edb086b32d4eb2e30a3f7d9d9e893) Thanks [@dimaMachina](https://github.com/dimaMachina)! - replace deprecated `navigator.platform` with `navigator.userAgent` fix placeholder `⌘ K` in doc explorer search input for non mac devices, replace by `Ctrl K` - Updated dependencies [[`b8538d8`](https://github.com/graphql/graphiql/commit/b8538d87421edb086b32d4eb2e30a3f7d9d9e893)]: - @graphiql/react@0.26.2 ## 3.7.0 ### Minor Changes - [#3619](https://github.com/graphql/graphiql/pull/3619) [`9aef83a`](https://github.com/graphql/graphiql/commit/9aef83a32aeb5f193a3ff0f191c95d09eb0d70b6) Thanks [@Yahkob](https://github.com/Yahkob)! - add new prop `defaultTheme` to set the default color preference theme ### Patch Changes - [#3441](https://github.com/graphql/graphiql/pull/3441) [`959ed21`](https://github.com/graphql/graphiql/commit/959ed21815682fc439f64d78e23e603a8f313a6f) Thanks [@cimdalli](https://github.com/cimdalli)! - fix: set query editor to `defaultQuery` while adding a new tab or GraphiQL's default query ```graphql # Welcome to GraphiQL # # GraphiQL is an in-browser tool for writing, validating, and # testing GraphQL queries. ... ``` - Updated dependencies [[`959ed21`](https://github.com/graphql/graphiql/commit/959ed21815682fc439f64d78e23e603a8f313a6f), [`9aef83a`](https://github.com/graphql/graphiql/commit/9aef83a32aeb5f193a3ff0f191c95d09eb0d70b6)]: - @graphiql/react@0.26.0 ## 3.6.0 ### Minor Changes - [#3563](https://github.com/graphql/graphiql/pull/3563) [`4fb231f`](https://github.com/graphql/graphiql/commit/4fb231fb9619544974d81be9a2e7d92e37ab7426) Thanks [@klippx](https://github.com/klippx)! - Add new prop `confirmCloseTab` to allow control of closing tabs - [#3532](https://github.com/graphql/graphiql/pull/3532) [`7404e8e`](https://github.com/graphql/graphiql/commit/7404e8e6c62b06107f452142493297ec70f1649c) Thanks [@Cr4xy](https://github.com/Cr4xy)! - Add webp support to graphiql results image-preview ### Patch Changes - Updated dependencies [[`7404e8e`](https://github.com/graphql/graphiql/commit/7404e8e6c62b06107f452142493297ec70f1649c)]: - @graphiql/react@0.25.0 ## 3.5.0 ### Minor Changes - [#3682](https://github.com/graphql/graphiql/pull/3682) [`6c9f0df`](https://github.com/graphql/graphiql/commit/6c9f0df83ea4afe7fa59f84d83d59fba73dc3931) Thanks [@yaacovCR](https://github.com/yaacovCR)! - Support v17 of `graphql-js` from `17.0.0-alpha.2` forward. Includes support for the latest incremental delivery response format. For further details, see https://github.com/graphql/defer-stream-wg/discussions/69. ### Patch Changes - Updated dependencies [[`6c9f0df`](https://github.com/graphql/graphiql/commit/6c9f0df83ea4afe7fa59f84d83d59fba73dc3931)]: - @graphiql/react@0.24.0 ## 3.4.1 ### Patch Changes - [#3675](https://github.com/graphql/graphiql/pull/3675) [`676f910`](https://github.com/graphql/graphiql/commit/676f910638eed5177146045d028a74e623884b45) Thanks [@dimaMachina](https://github.com/dimaMachina)! - move `@graphiql/toolkit` to `devDependecies` because umd build is bundled with all dependencies in one file - [#3655](https://github.com/graphql/graphiql/pull/3655) [`5450e6b`](https://github.com/graphql/graphiql/commit/5450e6b547add41a9dd89145934e79576b5544e6) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove unused dependencies `graphql-language-service` and `markdown-it` - Updated dependencies [[`6a0a5e5`](https://github.com/graphql/graphiql/commit/6a0a5e590b7b526af8a66c59a27ec3d0144af572)]: - @graphiql/react@0.23.1 ## 3.4.0 ### Minor Changes - [#3643](https://github.com/graphql/graphiql/pull/3643) [`82f1ecc`](https://github.com/graphql/graphiql/commit/82f1eccb52e328241cee93389c58154b9f2e8730) Thanks [@dimaMachina](https://github.com/dimaMachina)! - add `className` prop. Additional class names which will be appended to the GraphiQL container element ### Patch Changes - Updated dependencies [[`5bc7b84`](https://github.com/graphql/graphiql/commit/5bc7b84531b6404553787615d61a5cbcc96c1d6f), [`fdec377`](https://github.com/graphql/graphiql/commit/fdec377f28ac0d918a219b78dfa2d8f0996ff84d), [`56c6f45`](https://github.com/graphql/graphiql/commit/56c6f4571dd0dfda307ed11c5afb8c837ad928b0), [`93c7e9f`](https://github.com/graphql/graphiql/commit/93c7e9fd224cb4f1e9a86b3391efc1e0ef6e1e3f)]: - @graphiql/react@0.23.0 - graphql-language-service@5.2.2 - @graphiql/toolkit@0.9.2 ## 3.3.2 ### Patch Changes - [#3634](https://github.com/graphql/graphiql/pull/3634) [`adf0ba01`](https://github.com/graphql/graphiql/commit/adf0ba019902dcac2e49ccee69b79a6665c4766d) Thanks [@dimaMachina](https://github.com/dimaMachina)! - when alpha is `1`, use `hsl` instead of `hsla` - Updated dependencies [[`adf0ba01`](https://github.com/graphql/graphiql/commit/adf0ba019902dcac2e49ccee69b79a6665c4766d)]: - @graphiql/react@0.22.4 ## 3.3.1 ### Patch Changes - Updated dependencies [[`335d830c`](https://github.com/graphql/graphiql/commit/335d830c2a4e551ef97fbeff8ed7c538ff5cd4af)]: - @graphiql/react@0.22.3 ## 3.3.0 ### Minor Changes - [#3407](https://github.com/graphql/graphiql/pull/3407) [`115c1c02`](https://github.com/graphql/graphiql/commit/115c1c0281b3bcba6d2ae13f0df51e2cb1d0c24c) Thanks [@TuvalSimha](https://github.com/TuvalSimha)! - Add a new prop to GraphiQL component: `forcedTheme` to force the theme and hide the theme switcher. ## 3.2.3 ### Patch Changes - Updated dependencies [[`03ab3a6b`](https://github.com/graphql/graphiql/commit/03ab3a6b76378591ef79a828d80cc69b0b8f2842), [`aa6dbbb4`](https://github.com/graphql/graphiql/commit/aa6dbbb45bf51c1966537640fbe5c4f375735c8d)]: - @graphiql/react@0.22.2 - graphql-language-service@5.2.1 ## 3.2.2 ### Patch Changes - Updated dependencies [[`224b43f5`](https://github.com/graphql/graphiql/commit/224b43f5473456f264a82998d48a34a441537f54)]: - @graphiql/react@0.22.1 ## 3.2.1 ### Patch Changes - Updated dependencies [[`d48f4ef5`](https://github.com/graphql/graphiql/commit/d48f4ef56578dad7ec90f33458353791e463ef7b)]: - @graphiql/react@0.22.0 ## 3.2.0 ### Minor Changes - [#3569](https://github.com/graphql/graphiql/pull/3569) [`5d051054`](https://github.com/graphql/graphiql/commit/5d05105469c3f0cbeb5e294da1cf6ff2355e4eb5) Thanks [@AaronMoat](https://github.com/AaronMoat)! - Update to markdown-it 14.x ### Patch Changes - Updated dependencies [[`5d051054`](https://github.com/graphql/graphiql/commit/5d05105469c3f0cbeb5e294da1cf6ff2355e4eb5)]: - @graphiql/react@0.21.0 ## 3.1.2 ### Patch Changes - Updated dependencies []: - @graphiql/react@0.20.4 ## 3.1.1 ### Patch Changes - Updated dependencies [[`2b6ea316`](https://github.com/graphql/graphiql/commit/2b6ea3166c8d8e152f16d87c878aa8a66f1b3775)]: - @graphiql/react@0.20.3 ## 3.1.0 ### Minor Changes - [#3408](https://github.com/graphql/graphiql/pull/3408) [`a8080197`](https://github.com/graphql/graphiql/commit/a80801970e095e493eb0fda7687766f103bf701e) Thanks [@TuvalSimha](https://github.com/TuvalSimha)! - Allow disabling tabs and added new prop `disableTabs` ## 3.0.10 ### Patch Changes - [#3439](https://github.com/graphql/graphiql/pull/3439) [`d07d5fc0`](https://github.com/graphql/graphiql/commit/d07d5fc0cf764518bc1184ef168361cedf61540b) Thanks [@xonx4l](https://github.com/xonx4l)! - FIX: Unexpected duplicate CSS "display" property ## 3.0.9 ### Patch Changes - Updated dependencies [[`e89c432d`](https://github.com/graphql/graphiql/commit/e89c432d8d2b91f087b683360f23e0686462bc02)]: - @graphiql/react@0.20.2 ## 3.0.8 ### Patch Changes - Updated dependencies [[`39bf31d1`](https://github.com/graphql/graphiql/commit/39bf31d15b1e7fb5f235ec9adc1ce8081536de4a)]: - @graphiql/react@0.20.1 ## 3.0.7 ### Patch Changes - Updated dependencies [[`f6afd22d`](https://github.com/graphql/graphiql/commit/f6afd22d3f5a20089759042f16fd865646a32038)]: - @graphiql/react@0.20.0 ## 3.0.6 ### Patch Changes - Updated dependencies [[`7b00774a`](https://github.com/graphql/graphiql/commit/7b00774affad1f25253ce49f1f48c9e3f372808c), [`7b00774a`](https://github.com/graphql/graphiql/commit/7b00774affad1f25253ce49f1f48c9e3f372808c)]: - graphql-language-service@5.2.0 - @graphiql/react@0.19.4 ## 3.0.5 ### Patch Changes - [#3371](https://github.com/graphql/graphiql/pull/3371) [`2348641c`](https://github.com/graphql/graphiql/commit/2348641c07748691c478ac5f67032b7e9081f9cb) Thanks [@acao](https://github.com/acao)! - Solves #2825, an old bug where new tabs were created on every refresh the bug occurred when: 1. `shouldPersistHeaders` is not set to true 2. `headers` or `defaultHeaders` are provided as props 3. the user refreshes the browser - Updated dependencies [[`2348641c`](https://github.com/graphql/graphiql/commit/2348641c07748691c478ac5f67032b7e9081f9cb)]: - @graphiql/react@0.19.3 ## 3.0.4 ### Patch Changes - [#3364](https://github.com/graphql/graphiql/pull/3364) [`d67c13f6`](https://github.com/graphql/graphiql/commit/d67c13f6e1f478b171801afd0767b98312db04c9) Thanks [@acao](https://github.com/acao)! - Fix search result bug on select, #33307 - Updated dependencies [[`4cbdf183`](https://github.com/graphql/graphiql/commit/4cbdf18385d34ef9bc095c376936f92a62eb9e9b), [`d67c13f6`](https://github.com/graphql/graphiql/commit/d67c13f6e1f478b171801afd0767b98312db04c9)]: - @graphiql/toolkit@0.9.1 - @graphiql/react@0.19.2 ## 3.0.3 ### Patch Changes - [#3359](https://github.com/graphql/graphiql/pull/3359) [`8ebedc9a`](https://github.com/graphql/graphiql/commit/8ebedc9a518581f3dcbaa440bcd829d4546c76db) Thanks [@acao](https://github.com/acao)! - export createLocalStorage in UMD bundle ## 3.0.2 ### Patch Changes - [#3349](https://github.com/graphql/graphiql/pull/3349) [`17069e7a`](https://github.com/graphql/graphiql/commit/17069e7a0224dbce3f5523630a898e093f5c47c9) Thanks [@acao](https://github.com/acao)! - fix display of deprecation reason on field type docs - Updated dependencies [[`17069e7a`](https://github.com/graphql/graphiql/commit/17069e7a0224dbce3f5523630a898e093f5c47c9), [`ffb6486d`](https://github.com/graphql/graphiql/commit/ffb6486d1eab0be2bc8fdec366b5671a5d6504d1), [`e4a36207`](https://github.com/graphql/graphiql/commit/e4a362071edf1db53f87f271c523ab2f3a5c4717)]: - @graphiql/react@0.19.1 - @graphiql/toolkit@0.9.0 ## 3.0.1 ### Patch Changes - Updated dependencies [[`9a38de29`](https://github.com/graphql/graphiql/commit/9a38de29fddf174ba9e793ac5852407537244f87)]: - @graphiql/react@0.19.0 ## 3.0.0 ### Major Changes - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - remove `initialTabs`, use `defaultTabs` instead ### Patch Changes - [#3235](https://github.com/graphql/graphiql/pull/3235) [`5d062809`](https://github.com/graphql/graphiql/commit/5d062809b5240c393854e3f97f2117e58d505991) Thanks [@B2o5T](https://github.com/B2o5T)! - remove unnecessary `
` wrappers - Updated dependencies [[`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`5971d528`](https://github.com/graphql/graphiql/commit/5971d528b0608e76d9d109103f64857a790a99b9), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`d9e5089f`](https://github.com/graphql/graphiql/commit/d9e5089f78f85cd50c3e3e3ba8510f7dda3d06f5), [`bc9d243d`](https://github.com/graphql/graphiql/commit/bc9d243d40b95f95fc9d00d25aa0dd1733952626), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`67bf93a3`](https://github.com/graphql/graphiql/commit/67bf93a33e98c60ae3a686063a1c47037f88ef49)]: - @graphiql/react@0.18.0 - graphql-language-service@5.1.7 ## 3.0.0-alpha.1 ### Patch Changes - Updated dependencies [[`5971d528`](https://github.com/graphql/graphiql/commit/5971d528b0608e76d9d109103f64857a790a99b9), [`d9e5089f`](https://github.com/graphql/graphiql/commit/d9e5089f78f85cd50c3e3e3ba8510f7dda3d06f5), [`bc9d243d`](https://github.com/graphql/graphiql/commit/bc9d243d40b95f95fc9d00d25aa0dd1733952626), [`67bf93a3`](https://github.com/graphql/graphiql/commit/67bf93a33e98c60ae3a686063a1c47037f88ef49)]: - graphql-language-service@5.1.7-alpha.0 - @graphiql/react@0.18.0-alpha.1 ## 3.0.0-alpha.0 ### Major Changes - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - remove `initialTabs`, use `defaultTabs` instead ### Patch Changes - Updated dependencies [[`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696)]: - @graphiql/react@0.18.0-alpha.0 ## 2.4.7 ### Patch Changes - [#3198](https://github.com/graphql/graphiql/pull/3198) [`e6cb6395`](https://github.com/graphql/graphiql/commit/e6cb63956baf338f09806c2fb8d5648fde19869d) Thanks [@B2o5T](https://github.com/B2o5T)! - fix ReferenceError: window is not defined in Next.js ## 2.4.6 ### Patch Changes - [#3124](https://github.com/graphql/graphiql/pull/3124) [`c645932c`](https://github.com/graphql/graphiql/commit/c645932c7973e11ad917e1d1d897fd409f8c042f) Thanks [@B2o5T](https://github.com/B2o5T)! - avoid unnecessary renders by using useMemo or useCallback - Updated dependencies [[`911cf3e0`](https://github.com/graphql/graphiql/commit/911cf3e0b0fa13268245463c8db8299279e5c461), [`c645932c`](https://github.com/graphql/graphiql/commit/c645932c7973e11ad917e1d1d897fd409f8c042f), [`2ca4841b`](https://github.com/graphql/graphiql/commit/2ca4841baf74e87a3f067b3415f8da3347ee3898), [`7bf90929`](https://github.com/graphql/graphiql/commit/7bf90929f62ba812c0946e0424f9f843f7b6b0ff), [`431b7fe1`](https://github.com/graphql/graphiql/commit/431b7fe1efefa4867f0ea617adc436b1117052e8)]: - @graphiql/react@0.17.6 ## 2.4.5 ### Patch Changes - Updated dependencies [[`2b212941`](https://github.com/graphql/graphiql/commit/2b212941628498957d95ee89a7a5a0623f391b7a), [`9b333a04`](https://github.com/graphql/graphiql/commit/9b333a047d6b75db7681f484156d8772e9f91810)]: - @graphiql/react@0.17.5 ## 2.4.4 ### Patch Changes - Updated dependencies [[`707f3cbc`](https://github.com/graphql/graphiql/commit/707f3cbca3ac2ce186058e7d2b145cdf69bf7d9c), [`06007498`](https://github.com/graphql/graphiql/commit/06007498880528ed75dd4d705dcbcd7c9e775939)]: - @graphiql/react@0.17.4 - graphql-language-service@5.1.6 ## 2.4.3 ### Patch Changes - Updated dependencies [[`4d33b221`](https://github.com/graphql/graphiql/commit/4d33b2214e941f171385a1b72a1fa995714bb284)]: - graphql-language-service@5.1.5 - @graphiql/react@0.17.3 ## 2.4.2 ### Patch Changes - [#3113](https://github.com/graphql/graphiql/pull/3113) [`2e477eb2`](https://github.com/graphql/graphiql/commit/2e477eb24672a242ae4a4f2dfaeaf41152ed7ee9) Thanks [@B2o5T](https://github.com/B2o5T)! - replace `.forEach` with `for..of` - Updated dependencies [[`2e477eb2`](https://github.com/graphql/graphiql/commit/2e477eb24672a242ae4a4f2dfaeaf41152ed7ee9), [`4879984e`](https://github.com/graphql/graphiql/commit/4879984ea1803a6e9f97d81c97e8ba27aacddae9), [`51007002`](https://github.com/graphql/graphiql/commit/510070028b7d8e98f2ba25f396519976aea5fa4b), [`15c26eb6`](https://github.com/graphql/graphiql/commit/15c26eb6d621a85df9eecb2b8a5fa009fa2fe040)]: - @graphiql/react@0.17.2 - @graphiql/toolkit@0.8.4 - graphql-language-service@5.1.4 ## 2.4.1 ### Patch Changes - [#3087](https://github.com/graphql/graphiql/pull/3087) [`0e2dfd49`](https://github.com/graphql/graphiql/commit/0e2dfd49b95d670a0955991fd65055000e52a9f8) Thanks [@B2o5T](https://github.com/B2o5T)! - remove nowhere used `entities` dependency - Updated dependencies [[`2d5c60ec`](https://github.com/graphql/graphiql/commit/2d5c60ecf717abafde2bddd32b2772261d3eec8b), [`b9c13328`](https://github.com/graphql/graphiql/commit/b9c13328f3d28c0026ee0f0ecc7213065c9b016d), [`4a2284f5`](https://github.com/graphql/graphiql/commit/4a2284f54809f91d03ba51b9eb4e3ba7b8b7e773), [`881a2024`](https://github.com/graphql/graphiql/commit/881a202497d5a58eb5260a5aa54c0c88930d69a0), [`7cf4908a`](https://github.com/graphql/graphiql/commit/7cf4908a5d4bd58af315047f4dec5236e8c701fc)]: - @graphiql/react@0.17.1 - @graphiql/toolkit@0.8.3 - graphql-language-service@5.1.3 ## 2.4.0 ### Minor Changes - [#3012](https://github.com/graphql/graphiql/pull/3012) [`65f5176a`](https://github.com/graphql/graphiql/commit/65f5176a408cfbbc514ca60e2e4bd2ea133a8b0b) Thanks [@benjie](https://github.com/benjie)! - GraphiQL now maintains the DocExplorer navigation stack as best it can when the schema is updated ### Patch Changes - [#2995](https://github.com/graphql/graphiql/pull/2995) [`5f276c41`](https://github.com/graphql/graphiql/commit/5f276c415ad93350382fec873025ffecc9a29d9d) Thanks [@imolorhe](https://github.com/imolorhe)! - fix(cm6-graphql): Fix query token used as field name - [#2962](https://github.com/graphql/graphiql/pull/2962) [`db2a0982`](https://github.com/graphql/graphiql/commit/db2a0982a17134f0069483ab283594eb64735b7d) Thanks [@B2o5T](https://github.com/B2o5T)! - clean all ESLint warnings, add `--max-warnings=0` and `--cache` flags - [#2940](https://github.com/graphql/graphiql/pull/2940) [`8725d1b6`](https://github.com/graphql/graphiql/commit/8725d1b6b686139286cf05dec6a84d89942128ba) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `unicorn/prefer-node-protocol` rule - Updated dependencies [[`e68cb8bc`](https://github.com/graphql/graphiql/commit/e68cb8bcaf9baddf6fca747abab871ecd1bc7a4c), [`f788e65a`](https://github.com/graphql/graphiql/commit/f788e65aff267ec873237034831d1fd936222a9b), [`bdc966cb`](https://github.com/graphql/graphiql/commit/bdc966cba6134a72ff7fe40f76543c77ba15d4a4), [`65f5176a`](https://github.com/graphql/graphiql/commit/65f5176a408cfbbc514ca60e2e4bd2ea133a8b0b), [`db2a0982`](https://github.com/graphql/graphiql/commit/db2a0982a17134f0069483ab283594eb64735b7d), [`8725d1b6`](https://github.com/graphql/graphiql/commit/8725d1b6b686139286cf05dec6a84d89942128ba)]: - graphql-language-service@5.1.2 - @graphiql/react@0.17.0 - @graphiql/toolkit@0.8.2 ## 2.3.0 ### Minor Changes - [#2895](https://github.com/graphql/graphiql/pull/2895) [`ccba2f33`](https://github.com/graphql/graphiql/commit/ccba2f33b67a03f492222f7afde1354cfd033b42) Thanks [@TheMightyPenguin](https://github.com/TheMightyPenguin)! - Add user facing setting for persisting headers ### Patch Changes - [#2922](https://github.com/graphql/graphiql/pull/2922) [`d1fcad72`](https://github.com/graphql/graphiql/commit/d1fcad72607e2789517dfe4936b5ec604e46762b) Thanks [@B2o5T](https://github.com/B2o5T)! - extends `plugin:import/recommended` and fix warnings - [#2941](https://github.com/graphql/graphiql/pull/2941) [`4a8b2e17`](https://github.com/graphql/graphiql/commit/4a8b2e1766a38eb4828cf9a81bf9d767070041de) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `unicorn/prefer-logical-operator-over-ternary` rule - [#2964](https://github.com/graphql/graphiql/pull/2964) [`cec3fb2a`](https://github.com/graphql/graphiql/commit/cec3fb2a493c4a0c40df7dfad04e1a95ed35e786) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `unicorn/prefer-export-from` rule - [#2939](https://github.com/graphql/graphiql/pull/2939) [`bca318ce`](https://github.com/graphql/graphiql/commit/bca318ceb7821f0c4b3973c5b05131c9a23bf2cf) Thanks [@jonathanawesome](https://github.com/jonathanawesome)! - removes regenerator-runtime from cdn.ts, resolves #2868 - [#2963](https://github.com/graphql/graphiql/pull/2963) [`f263f778`](https://github.com/graphql/graphiql/commit/f263f778cb95b9f413bd09ca56a43f5b9c2f6215) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `prefer-destructuring` rule - [#2938](https://github.com/graphql/graphiql/pull/2938) [`6a9d913f`](https://github.com/graphql/graphiql/commit/6a9d913f0d1b847124286b3fa1f3a2649d315171) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `unicorn/throw-new-error` rule - Updated dependencies [[`f7addb20`](https://github.com/graphql/graphiql/commit/f7addb20c4a558fbfb4112c8ff095bbc8f9d9147), [`d1fcad72`](https://github.com/graphql/graphiql/commit/d1fcad72607e2789517dfe4936b5ec604e46762b), [`4a8b2e17`](https://github.com/graphql/graphiql/commit/4a8b2e1766a38eb4828cf9a81bf9d767070041de), [`cec3fb2a`](https://github.com/graphql/graphiql/commit/cec3fb2a493c4a0c40df7dfad04e1a95ed35e786), [`695100bd`](https://github.com/graphql/graphiql/commit/695100bd317940ff3ffd8f56b54248c1dba1ac04), [`11e6ad11`](https://github.com/graphql/graphiql/commit/11e6ad11e745c671eb320731697887bb8d7177b7), [`c70d9165`](https://github.com/graphql/graphiql/commit/c70d9165cc1ef8eb1cd0d6b506ced98c626597f9), [`c44ea4f1`](https://github.com/graphql/graphiql/commit/c44ea4f1917b97daac815c08299b934c8ca57ed9), [`d502a33b`](https://github.com/graphql/graphiql/commit/d502a33b4332f1025e947c02d7cfdc5799365c8d), [`0669767e`](https://github.com/graphql/graphiql/commit/0669767e1e2196a78cbefe3679a52bcbb341e913), [`18f8e80a`](https://github.com/graphql/graphiql/commit/18f8e80ae12edfd0c36adcb300cf9e06ac27ea49), [`f263f778`](https://github.com/graphql/graphiql/commit/f263f778cb95b9f413bd09ca56a43f5b9c2f6215), [`ccba2f33`](https://github.com/graphql/graphiql/commit/ccba2f33b67a03f492222f7afde1354cfd033b42), [`6a9d913f`](https://github.com/graphql/graphiql/commit/6a9d913f0d1b847124286b3fa1f3a2649d315171), [`4ff2794c`](https://github.com/graphql/graphiql/commit/4ff2794c8b6032168e27252096cb276ce712878e)]: - @graphiql/react@0.16.0 - @graphiql/toolkit@0.8.1 - graphql-language-service@5.1.1 ## 2.2.0 ### Minor Changes - [#2908](https://github.com/graphql/graphiql/pull/2908) [`3340fd74`](https://github.com/graphql/graphiql/commit/3340fd745e181ba8f1f5a6ed002a04d253a78d4a) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Deprecate the `initialTabs` prop and add a `defaultTabs` props that supersedes it ### Patch Changes - [#2911](https://github.com/graphql/graphiql/pull/2911) [`118db402`](https://github.com/graphql/graphiql/commit/118db402eb1f5569e29f8f9bffef86d941dd2634) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix styles of secondary editor buttons - [#2919](https://github.com/graphql/graphiql/pull/2919) [`f6cae4ea`](https://github.com/graphql/graphiql/commit/f6cae4eaa0258ea7fcde97ba6368830955f0abf4) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix overflow when there are lots of tabs that don't fit into the tab bar at once - Updated dependencies [[`16174a05`](https://github.com/graphql/graphiql/commit/16174a053ed89fb9554d096395ab7bf69c8f6911), [`f6cae4ea`](https://github.com/graphql/graphiql/commit/f6cae4eaa0258ea7fcde97ba6368830955f0abf4), [`3340fd74`](https://github.com/graphql/graphiql/commit/3340fd745e181ba8f1f5a6ed002a04d253a78d4a), [`0851d5f9`](https://github.com/graphql/graphiql/commit/0851d5f9ecf709597d0a698609d88f99c4395665), [`83364b28`](https://github.com/graphql/graphiql/commit/83364b28020b5946ed58908d6d977f1de766e75d), [`3a7d0007`](https://github.com/graphql/graphiql/commit/3a7d00071922e2005777c92daf6ad0c1ce3e2816)]: - @graphiql/react@0.15.0 ## 2.1.0 ### Minor Changes - [#2821](https://github.com/graphql/graphiql/pull/2821) [`29630c22`](https://github.com/graphql/graphiql/commit/29630c2219bca8b825ab0897840864364a9de2e8) Thanks [@avaly](https://github.com/avaly)! - Initial tabs support ### Patch Changes - [#2885](https://github.com/graphql/graphiql/pull/2885) [`8f926489`](https://github.com/graphql/graphiql/commit/8f9264896e9971951853463a283a90ba3d1310ef) Thanks [@simhnna](https://github.com/simhnna)! - Fix stop execution button showing a dropdown - [#2886](https://github.com/graphql/graphiql/pull/2886) [`2ba2f620`](https://github.com/graphql/graphiql/commit/2ba2f620b6e7de3ae6b5ea641f33e600f7f44e08) Thanks [@B2o5T](https://github.com/B2o5T)! - feat: add `defaultHeaders` prop - Updated dependencies [[`29630c22`](https://github.com/graphql/graphiql/commit/29630c2219bca8b825ab0897840864364a9de2e8), [`8f926489`](https://github.com/graphql/graphiql/commit/8f9264896e9971951853463a283a90ba3d1310ef), [`2ba2f620`](https://github.com/graphql/graphiql/commit/2ba2f620b6e7de3ae6b5ea641f33e600f7f44e08)]: - @graphiql/react@0.14.0 ## 2.0.13 ### Patch Changes - Updated dependencies []: - @graphiql/react@0.13.7 ## 2.0.12 ### Patch Changes - [#2758](https://github.com/graphql/graphiql/pull/2758) [`d63801fa`](https://github.com/graphql/graphiql/commit/d63801fad08e840eff7ff26f55694c6d18769466) Thanks [@LekoArts](https://github.com/LekoArts)! - Fix the width of the plugin pane - Updated dependencies []: - @graphiql/react@0.13.6 ## 2.0.11 ### Patch Changes - Updated dependencies [[`682ad06e`](https://github.com/graphql/graphiql/commit/682ad06e58ded2f82fa973e8e6613dd654417fe2)]: - @graphiql/react@0.13.5 ## 2.0.10 ### Patch Changes - Updated dependencies [[`4e2f7ff9`](https://github.com/graphql/graphiql/commit/4e2f7ff99c578ceae54a1ae17c02088bd91b89c3)]: - @graphiql/react@0.13.4 ## 2.0.9 ### Patch Changes - [#2778](https://github.com/graphql/graphiql/pull/2778) [`905f2e5e`](https://github.com/graphql/graphiql/commit/905f2e5ea3f0b304d27ea583e250ed4baff5016e) Thanks [@jonathanawesome](https://github.com/jonathanawesome)! - Adds a box-model reset for all children of the `.graphiql-container` class. This change facilitated another change to the `--sidebar-width` variable. - Updated dependencies [[`42700076`](https://github.com/graphql/graphiql/commit/4270007671ce52f6c2250739916083611748b657), [`36839800`](https://github.com/graphql/graphiql/commit/36839800de128b05d11c262036c8240390c72a14), [`905f2e5e`](https://github.com/graphql/graphiql/commit/905f2e5ea3f0b304d27ea583e250ed4baff5016e)]: - @graphiql/react@0.13.3 ## 2.0.8 ### Patch Changes - [#2653](https://github.com/graphql/graphiql/pull/2653) [`39b4668d`](https://github.com/graphql/graphiql/commit/39b4668d43176526d37ecf07d8c86901d53e0d80) Thanks [@dylanowen](https://github.com/dylanowen)! - Fix `fetchError` not being cleared when a new `fetcher` is used - Updated dependencies [[`39b4668d`](https://github.com/graphql/graphiql/commit/39b4668d43176526d37ecf07d8c86901d53e0d80)]: - @graphiql/react@0.13.2 ## 2.0.7 ### Patch Changes - Updated dependencies [[`e244b782`](https://github.com/graphql/graphiql/commit/e244b78291c2e2bb02d5753db82437926ebb4df4)]: - @graphiql/toolkit@0.8.0 - @graphiql/react@0.13.1 ## 2.0.6 ### Patch Changes - [#2735](https://github.com/graphql/graphiql/pull/2735) [`ca067d88`](https://github.com/graphql/graphiql/commit/ca067d88148c5d221d196790a997ad599038fad1) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Use the new CSS variables for color alpha values defined in `@graphiql/react` in style definitions - Updated dependencies [[`ca067d88`](https://github.com/graphql/graphiql/commit/ca067d88148c5d221d196790a997ad599038fad1), [`674bf3f8`](https://github.com/graphql/graphiql/commit/674bf3f8ff321dfb8471b0f6e5419bb77ddc94af), [`32a70065`](https://github.com/graphql/graphiql/commit/32a70065434eaa7733e28cda0ea0e7d51952e62a)]: - @graphiql/react@0.13.0 - @graphiql/toolkit@0.7.3 ## 2.0.5 ### Patch Changes - Updated dependencies [[`bfa90f24`](https://github.com/graphql/graphiql/commit/bfa90f249be4f68049c1bb81abfb524ae623313f), [`8ab5fcd0`](https://github.com/graphql/graphiql/commit/8ab5fcd0a8399a0f8eb1b569751dd0e8390b9679)]: - @graphiql/toolkit@0.7.2 - @graphiql/react@0.12.1 ## 2.0.4 ### Patch Changes - [#2745](https://github.com/graphql/graphiql/pull/2745) [`92a17490`](https://github.com/graphql/graphiql/commit/92a17490c3842b4f83ed1065b73a803f73d02a17) Thanks [@acao](https://github.com/acao)! - Specify MIT license for `@graphiql/plugin-explorer` `package.json` * [#2741](https://github.com/graphql/graphiql/pull/2741) [`0219eef3`](https://github.com/graphql/graphiql/commit/0219eef39146495749aca2487112db52fa3bb8fd) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Improved sizing of button for adding tabs - [#2746](https://github.com/graphql/graphiql/pull/2746) [`6f0fa98e`](https://github.com/graphql/graphiql/commit/6f0fa98eadf897c7eaf8eb89e49c46880d381033) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix CodeMirror editors overlapping other parts of the UI on certain browser-OS-combinations (e.g. Chrome on Windows) - Updated dependencies [[`98e14155`](https://github.com/graphql/graphiql/commit/98e14155c650ee7c5ac639e594eb47f0052b7fa9), [`48872a87`](https://github.com/graphql/graphiql/commit/48872a87e6edec0c301102baaf669ffcce043a13), [`7dfea94a`](https://github.com/graphql/graphiql/commit/7dfea94afc0cfe79b5080f10d840bfdce53f02d7), [`3aa1f39f`](https://github.com/graphql/graphiql/commit/3aa1f39f6df559b54f703937ed510c8ba1f21058), [`0219eef3`](https://github.com/graphql/graphiql/commit/0219eef39146495749aca2487112db52fa3bb8fd)]: - @graphiql/react@0.12.0 - @graphiql/toolkit@0.7.1 ## 2.0.3 ### Patch Changes - [#2706](https://github.com/graphql/graphiql/pull/2706) [`ff20a381`](https://github.com/graphql/graphiql/commit/ff20a3818f10f648d7b8c18229138b0424b8b25c) Thanks [@mxstbr](https://github.com/mxstbr)! - Wrap the GraphiQL logo with a link to the repository * [#2715](https://github.com/graphql/graphiql/pull/2715) [`c922719e`](https://github.com/graphql/graphiql/commit/c922719e6b960776cd0a71f14d2b86c6bb69373c) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add the contents of `graphql` and `@graphiql/react` as static properties to the `GraphiQL` component in CDN bundles so that these modules can be reused from plugin CDN bundles. ## 2.0.2 ### Patch Changes - Updated dependencies [[`d65f00ea`](https://github.com/graphql/graphiql/commit/d65f00ea2d158cf532d1c71844630c5d9ec13410), [`f15ee38d`](https://github.com/graphql/graphiql/commit/f15ee38d56e4f749c145e0a17f0ed8e9a6096ac2), [`d65f00ea`](https://github.com/graphql/graphiql/commit/d65f00ea2d158cf532d1c71844630c5d9ec13410)]: - @graphiql/react@0.11.1 ## 2.0.1 ### Patch Changes - [#2699](https://github.com/graphql/graphiql/pull/2699) [`3b642aa3`](https://github.com/graphql/graphiql/commit/3b642aa31b306994e3052bb2454933307aa51426) Thanks [@patrick91](https://github.com/patrick91)! - Export hooks in CDN bundle * [#2700](https://github.com/graphql/graphiql/pull/2700) [`3acacf5b`](https://github.com/graphql/graphiql/commit/3acacf5b90040bbede30ad1a778e06bc969a5900) Thanks [@patrick91](https://github.com/patrick91)! - Fix cannot access `initialHeaders` before initialization ## 2.0.0 ### Major Changes - [#2694](https://github.com/graphql/graphiql/pull/2694) [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279) Thanks [@acao](https://github.com/acao)! - BREAKING: The `GraphiQL` component does no longer set a property `g` on the `window` object. * [#2694](https://github.com/graphql/graphiql/pull/2694) [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279) Thanks [@acao](https://github.com/acao)! - BREAKING: Implement a new design for the GraphiQL UI. This changes both DOM structure and class names. We consider this a breaking change as custom GraphQL IDEs built on top of GraphiQL relied on these internals, e.g. overriding styles using certain class names. - [#2694](https://github.com/graphql/graphiql/pull/2694) [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279) Thanks [@acao](https://github.com/acao)! - BREAKING: The following static properties of the `GraphiQL` component have been removed: - `GraphiQL.formatResult`: You can use the function `formatResult` from `@graphiql/toolkit` instead. - `GraphiQL.formatError`: You can use the function `formatError` from `@graphiql/toolkit` instead. - `GraphiQL.QueryEditor`: You can use the `QueryEditor` component from `@graphiql/react` instead. - `GraphiQL.VariableEditor`: You can use the `VariableEditor` component from `@graphiql/react` instead. - `GraphiQL.HeaderEditor`: You can use the `HeaderEditor` component from `@graphiql/react` instead. - `GraphiQL.ResultViewer`: You can use the `ResponseEditor` component from `@graphiql/react` instead. - `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'; function CustomGraphiQL() { return ( {/* Add custom styles for your buttons using the given class */}
); } ``` * [#2694](https://github.com/graphql/graphiql/pull/2694) [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279) Thanks [@acao](https://github.com/acao)! - 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` - `fillLeafs`: Now exported from `@graphiql/toolkit` as `fillLeafs` - `getSelectedOperationName`: Now exported from `@graphiql/toolkit` as `getSelectedOperationName` - `mergeAst`: Now exported from `@graphiql/toolkit` as `mergeAst` - `onHasCompletion`: Now exported from `@graphiql/react` as `onHasCompletion` - `QueryEditor`: Now exported from `@graphiql/react` as `QueryEditor` - `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` - `VariableEditor`: Now exported from `@graphiql/react` as `VariableEditor` - type `Fetcher`: Now exported from `@graphiql/toolkit` - type `FetcherOpts`: Now exported from `@graphiql/toolkit` - type `FetcherParams`: Now exported from `@graphiql/toolkit` - type `FetcherResult`: Now exported from `@graphiql/toolkit` - type `FetcherReturnType`: Now exported from `@graphiql/toolkit` - type `Observable`: Now exported from `@graphiql/toolkit` - type `Storage`: Now exported from `@graphiql/toolkit` - type `SyncFetcherResult`: Now exported from `@graphiql/toolkit` - [#2694](https://github.com/graphql/graphiql/pull/2694) [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279) Thanks [@acao](https://github.com/acao)! - BREAKING: The `GraphiQL` component has been refactored to be a function component. Attaching a ref to this component will no longer provide access to props, state or class methods. In order to interact with or change `GraphiQL` state you need to use the contexts and hooks provided by the `@graphiql/react` package. More details and examples can be found in the migration guide. * [#2694](https://github.com/graphql/graphiql/pull/2694) [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279) Thanks [@acao](https://github.com/acao)! - BREAKING: The following props of the `GraphiQL` component have been changed: - The props `defaultVariableEditorOpen` and `defaultSecondaryEditorOpen` have been merged into one prop `defaultEditorToolsVisibility`. The default behavior if this prop is not passed is that the editor tools are shown if at least one of the secondary editors has contents. You can pass the following values to the prop: - Passing `false` hides the editor tools. - Passing `true` shows the editor tools. - Passing `"variables"` explicitly shows the variables editor. - Passing `"headers"` explicitly shows the headers editor. - The props `docExplorerOpen`, `onToggleDocs` and `onToggleHistory` have been removed. They are replaced by the more generic props `visiblePlugin` (for controlling which plugin is visible) and `onTogglePluginVisibility` (which is called each time the visibility of any plugin changes). - The `headerEditorEnabled` prop has been renamed to `isHeadersEditorEnabled`. - The `ResultsTooltip` prop has been renamed to `responseTooltip`. - Tabs are now always enabled. The `tabs` prop has therefore been replaced with a prop `onTabChange`. If you used the `tabs` prop before to pass this function you can change your implementation like so: ```diff {/* do something */} }} + onTabChange={(tabState) => {/* do something */}} /> ``` ### Minor Changes - [#2694](https://github.com/graphql/graphiql/pull/2694) [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279) Thanks [@acao](https://github.com/acao)! - GraphiQL now ships with a dark theme. By default the interface respects the system settings, the theme can also be explicitly chosen via the new settings dialog. ### Patch Changes - Updated dependencies [[`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279), [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279), [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279), [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279), [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279), [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279)]: - @graphiql/react@0.11.0 - @graphiql/toolkit@0.7.0 ## 1.11.6 ### Patch Changes - Updated dependencies [[`d6ff4d7a`](https://github.com/graphql/graphiql/commit/d6ff4d7a5d535a0c43fe5914016bac9ef0c2b782)]: - graphql-language-service@5.1.0 - @graphiql/react@0.10.1 ## 1.11.5 ### Patch Changes - [#2678](https://github.com/graphql/graphiql/pull/2678) [`b3470b99`](https://github.com/graphql/graphiql/commit/b3470b993bd4c1b90ab7831581de2021af1bb6b0) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add the attribute `type="button"` to all buttons ## 1.11.4 ### Patch Changes - Updated dependencies [[`85d5af25`](https://github.com/graphql/graphiql/commit/85d5af25d77c29b7d02da90a431c8c15f610c22a), [`6ff0bab9`](https://github.com/graphql/graphiql/commit/6ff0bab978d63778b8ab4ba6e79fceb36c2db87f), [`0aff68a6`](https://github.com/graphql/graphiql/commit/0aff68a645cceb6b9689e0f394e8bece01710efc)]: - @graphiql/react@0.10.0 ## 1.11.3 ### Patch Changes - [#2642](https://github.com/graphql/graphiql/pull/2642) [`100af928`](https://github.com/graphql/graphiql/commit/100af9284de18ca89524c646e86854313c5d067b) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix controlling the operation name sent with the request using the `operationName` prop - Updated dependencies [[`100af928`](https://github.com/graphql/graphiql/commit/100af9284de18ca89524c646e86854313c5d067b), [`100af928`](https://github.com/graphql/graphiql/commit/100af9284de18ca89524c646e86854313c5d067b)]: - @graphiql/react@0.9.0 ## 1.11.2 ### Patch Changes - Updated dependencies [[`62317e0b`](https://github.com/graphql/graphiql/commit/62317e0bae6d4ccf89d9e1e6607fd8feeb100078)]: - @graphiql/react@0.8.0 ## 1.11.1 ### Patch Changes - Updated dependencies [[`ea732ea8`](https://github.com/graphql/graphiql/commit/ea732ea8e12272c998f1467af8b3b88b6b508e12)]: - @graphiql/toolkit@0.6.1 - @graphiql/react@0.7.1 ## 1.11.0 ### Minor Changes - [#2618](https://github.com/graphql/graphiql/pull/2618) [`4c814506`](https://github.com/graphql/graphiql/commit/4c814506183579b78731659d871cd4b0ba93305a) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add a toolbar button for manually triggering introspection ### Patch Changes - Updated dependencies [[`4c814506`](https://github.com/graphql/graphiql/commit/4c814506183579b78731659d871cd4b0ba93305a)]: - @graphiql/react@0.7.0 ## 1.10.0 ### Minor Changes - [#2574](https://github.com/graphql/graphiql/pull/2574) [`0c98fa59`](https://github.com/graphql/graphiql/commit/0c98fa5924eadaee33713ccd8a9be6419d50cab1) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Allow passing introspection data to the `schema` prop of the `GraphiQL` component ### Patch Changes - Updated dependencies [[`0c98fa59`](https://github.com/graphql/graphiql/commit/0c98fa5924eadaee33713ccd8a9be6419d50cab1), [`0c98fa59`](https://github.com/graphql/graphiql/commit/0c98fa5924eadaee33713ccd8a9be6419d50cab1)]: - @graphiql/react@0.6.0 ## 1.9.13 ### Patch Changes - Updated dependencies [[`f581b437`](https://github.com/graphql/graphiql/commit/f581b437e5bdab6f3ad817d230ee6d1b410bb591)]: - @graphiql/react@0.5.2 ## 1.9.12 ### Patch Changes - Updated dependencies [[`08346cba`](https://github.com/graphql/graphiql/commit/08346cba136825341881f9dfefc62a60d748e0ee)]: - @graphiql/react@0.5.1 ## 1.9.11 ### Patch Changes - [#2541](https://github.com/graphql/graphiql/pull/2541) [`788d84ef`](https://github.com/graphql/graphiql/commit/788d84ef2784188981f1b4cfb78fba24153bf0cb) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix the `onSchemaChange` prop, it is now again called after the schema is fetched (this was broken since v1.9.3) - Updated dependencies [[`8ce5b483`](https://github.com/graphql/graphiql/commit/8ce5b483ee190b5f5dd84eaf42e5d1359ce185e6), [`788d84ef`](https://github.com/graphql/graphiql/commit/788d84ef2784188981f1b4cfb78fba24153bf0cb)]: - @graphiql/react@0.5.0 ## 1.9.10 ### Patch Changes - Updated dependencies [[`26e44120`](https://github.com/graphql/graphiql/commit/26e44120a18d49af451c97619fe3386a65579e05)]: - @graphiql/react@0.4.3 ## 1.9.9 ### Patch Changes - [#2501](https://github.com/graphql/graphiql/pull/2501) [`5437ee61`](https://github.com/graphql/graphiql/commit/5437ee61e1ba6cd28ccc1cb3543df1ea788278f4) Thanks [@acao](https://github.com/acao)! - Allow Codemirror 5 `keyMap` to be defined, default `vim` or `emacs` allowed in addition to the original default of `sublime`. - Updated dependencies [[`5437ee61`](https://github.com/graphql/graphiql/commit/5437ee61e1ba6cd28ccc1cb3543df1ea788278f4), [`cccefa70`](https://github.com/graphql/graphiql/commit/cccefa70c0466d60e8496e1df61aeb1490af723c)]: - @graphiql/react@0.4.2 - graphql-language-service@5.0.6 ## 1.9.8 ### Patch Changes - [#2499](https://github.com/graphql/graphiql/pull/2499) [`731b3b72`](https://github.com/graphql/graphiql/commit/731b3b72e9f087a3b429ef5e8143219a0dcf7f00) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - fix the default value for the `headerEditorEnabled` prop to be `true` ## 1.9.7 ### Patch Changes - Updated dependencies [[`c9c51b8a`](https://github.com/graphql/graphiql/commit/c9c51b8a98e1f0427272d3e9ad60989b32f1a1aa)]: - graphql-language-service@5.0.5 - @graphiql/react@0.4.1 ## 1.9.6 ### Patch Changes - [#2475](https://github.com/graphql/graphiql/pull/2475) [`d6558e43`](https://github.com/graphql/graphiql/commit/d6558e43bd24a3af7c5f78dbae572bd8ca7b3995) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix using the `GraphiQL` export as type by exporting a class again * [#2461](https://github.com/graphql/graphiql/pull/2461) [`7dfe3ece`](https://github.com/graphql/graphiql/commit/7dfe3ece4e8ab6b3400888f7f357e394db63439d) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Use the `useDragResize` hook from `@graphiql/react` for the sizing of the editors and the docs explorer * Updated dependencies [[`7dfe3ece`](https://github.com/graphql/graphiql/commit/7dfe3ece4e8ab6b3400888f7f357e394db63439d)]: - @graphiql/react@0.4.0 ## 1.9.5 ### Patch Changes - [#2453](https://github.com/graphql/graphiql/pull/2453) [`1b41e33c`](https://github.com/graphql/graphiql/commit/1b41e33c4a871a345836de58f415b7c461ced1f8) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add execution context to `@graphiql/react` and move over the logic from `graphiql` * [#2454](https://github.com/graphql/graphiql/pull/2454) [`a53bec64`](https://github.com/graphql/graphiql/commit/a53bec64b511fca2da828d7c0ff100e3a110aec1) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Deprecate the public methods `getQueryEditor`, `getVariableEditor`, `getHeaderEditor`, and `refresh` on the `GraphiQL` class. - [#2451](https://github.com/graphql/graphiql/pull/2451) [`0659e96e`](https://github.com/graphql/graphiql/commit/0659e96e07f98d532619f29f52cba59e2d528327) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Always use the current value of the headers for the introspection request * [#2452](https://github.com/graphql/graphiql/pull/2452) [`ee0fd8bf`](https://github.com/graphql/graphiql/commit/ee0fd8bf4042053ec647080b83656dc5e54a7239) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move tab state from `graphiql` into editor context from `@graphiql/react` - [#2454](https://github.com/graphql/graphiql/pull/2454) [`a53bec64`](https://github.com/graphql/graphiql/commit/a53bec64b511fca2da828d7c0ff100e3a110aec1) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Continue forwarding the ref to the class component to not break public methods * [#2449](https://github.com/graphql/graphiql/pull/2449) [`a0b02eda`](https://github.com/graphql/graphiql/commit/a0b02edaa629c6113c1c5518fd3aa05b355a1921) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Assume all context values are nullable and create hooks to consume individual contexts - [#2450](https://github.com/graphql/graphiql/pull/2450) [`1e6fc68b`](https://github.com/graphql/graphiql/commit/1e6fc68b73941544ee64e0499e459f9c7d39aa14) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Extract the `copy`, `merge`, `prettify`, and `autoCompleteLeafs` functions into hooks and remove these functions from the editor context value - Updated dependencies [[`1b41e33c`](https://github.com/graphql/graphiql/commit/1b41e33c4a871a345836de58f415b7c461ced1f8), [`0659e96e`](https://github.com/graphql/graphiql/commit/0659e96e07f98d532619f29f52cba59e2d528327), [`ee0fd8bf`](https://github.com/graphql/graphiql/commit/ee0fd8bf4042053ec647080b83656dc5e54a7239), [`a0b02eda`](https://github.com/graphql/graphiql/commit/a0b02edaa629c6113c1c5518fd3aa05b355a1921), [`1e6fc68b`](https://github.com/graphql/graphiql/commit/1e6fc68b73941544ee64e0499e459f9c7d39aa14)]: - @graphiql/react@0.3.0 ## 1.9.4 ### Patch Changes - [#2437](https://github.com/graphql/graphiql/pull/2437) [`1f933505`](https://github.com/graphql/graphiql/commit/1f9335051fffc9e6a6f950b6f8060ed521b56789) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move prettify query functionality to editor context in `@graphiql/react` * [#2435](https://github.com/graphql/graphiql/pull/2435) [`89f0244f`](https://github.com/graphql/graphiql/commit/89f0244f7b7cdf01c168638a09f5137788401995) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move the logic for deriving operation facts from the current query to `@graphiql/react` and store these facts as properties on the query editor instance - [#2437](https://github.com/graphql/graphiql/pull/2437) [`1f933505`](https://github.com/graphql/graphiql/commit/1f9335051fffc9e6a6f950b6f8060ed521b56789) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move copy query functionality to editor context in `@graphiql/react` * [#2437](https://github.com/graphql/graphiql/pull/2437) [`1f933505`](https://github.com/graphql/graphiql/commit/1f9335051fffc9e6a6f950b6f8060ed521b56789) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move merge query functionality to editor context in `@graphiql/react` - [#2436](https://github.com/graphql/graphiql/pull/2436) [`3e5295f0`](https://github.com/graphql/graphiql/commit/3e5295f0fd3b5f999643ea97e6cee706554f0b50) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Inline logic for clicking a reference to open the docs and remove the `onClickReference` and `onHintInformationRender` props of the editor components and hooks * [#2436](https://github.com/graphql/graphiql/pull/2436) [`3e5295f0`](https://github.com/graphql/graphiql/commit/3e5295f0fd3b5f999643ea97e6cee706554f0b50) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move visibility state for doc explorer from `graphiql` to the explorer context in `@graphiql/react` * Updated dependencies [[`89f0244f`](https://github.com/graphql/graphiql/commit/89f0244f7b7cdf01c168638a09f5137788401995), [`1f933505`](https://github.com/graphql/graphiql/commit/1f9335051fffc9e6a6f950b6f8060ed521b56789), [`89f0244f`](https://github.com/graphql/graphiql/commit/89f0244f7b7cdf01c168638a09f5137788401995), [`3dae62fc`](https://github.com/graphql/graphiql/commit/3dae62fc871385e148a799cde55a52a5e6b41d19), [`1f933505`](https://github.com/graphql/graphiql/commit/1f9335051fffc9e6a6f950b6f8060ed521b56789), [`1f933505`](https://github.com/graphql/graphiql/commit/1f9335051fffc9e6a6f950b6f8060ed521b56789), [`3e5295f0`](https://github.com/graphql/graphiql/commit/3e5295f0fd3b5f999643ea97e6cee706554f0b50), [`3e5295f0`](https://github.com/graphql/graphiql/commit/3e5295f0fd3b5f999643ea97e6cee706554f0b50)]: - @graphiql/react@0.2.1 ## 1.9.3 ### Patch Changes - [#2419](https://github.com/graphql/graphiql/pull/2419) [`84d8985b`](https://github.com/graphql/graphiql/commit/84d8985b87701133cc41fd424a24bb61c9b7272e) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move the `fillLeafs` utility function from `graphiql` into `@graphiql/toolkit` and deprecate the export from `graphiql` * [#2413](https://github.com/graphql/graphiql/pull/2413) [`8be164b1`](https://github.com/graphql/graphiql/commit/8be164b1e158d00752d6d3f30630a797d07d08c9) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add a `StorageContext` and a `HistoryContext` to `@graphiql/react` that replaces the logic in the `graphiql` package - [#2419](https://github.com/graphql/graphiql/pull/2419) [`84d8985b`](https://github.com/graphql/graphiql/commit/84d8985b87701133cc41fd424a24bb61c9b7272e) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move the `mergeAst` utility function from `graphiql` into `@graphiql/toolkit` and deprecate the export from `graphiql` * [#2420](https://github.com/graphql/graphiql/pull/2420) [`3467cd33`](https://github.com/graphql/graphiql/commit/3467cd33264e0766a0a43cf53e52ec371df26962) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix sending multiple introspection requests when loading the page - [#2420](https://github.com/graphql/graphiql/pull/2420) [`3467cd33`](https://github.com/graphql/graphiql/commit/3467cd33264e0766a0a43cf53e52ec371df26962) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Deprecate the `autoCompleteLeafs` method of the `GraphiQL` component in favor of the function provided by the `EditorContext` from `@graphiql/react` * [#2420](https://github.com/graphql/graphiql/pull/2420) [`3467cd33`](https://github.com/graphql/graphiql/commit/3467cd33264e0766a0a43cf53e52ec371df26962) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add a `SchemaContext` to `@graphiql/react` that replaces the logic for fetching and validating the schema in the `graphiql` package - [#2419](https://github.com/graphql/graphiql/pull/2419) [`84d8985b`](https://github.com/graphql/graphiql/commit/84d8985b87701133cc41fd424a24bb61c9b7272e) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move the `getSelectedOperationName` utility function from `graphiql` into `@graphiql/toolkit` and deprecate the export from `graphiql` - Updated dependencies [[`84d8985b`](https://github.com/graphql/graphiql/commit/84d8985b87701133cc41fd424a24bb61c9b7272e), [`8be164b1`](https://github.com/graphql/graphiql/commit/8be164b1e158d00752d6d3f30630a797d07d08c9), [`8be164b1`](https://github.com/graphql/graphiql/commit/8be164b1e158d00752d6d3f30630a797d07d08c9), [`84d8985b`](https://github.com/graphql/graphiql/commit/84d8985b87701133cc41fd424a24bb61c9b7272e), [`3467cd33`](https://github.com/graphql/graphiql/commit/3467cd33264e0766a0a43cf53e52ec371df26962), [`84d8985b`](https://github.com/graphql/graphiql/commit/84d8985b87701133cc41fd424a24bb61c9b7272e)]: - @graphiql/toolkit@0.6.0 - @graphiql/react@0.2.0 ## 1.9.2 ### Patch Changes - Updated dependencies [[`ebc864f0`](https://github.com/graphql/graphiql/commit/ebc864f0ab05000758cb2898daaa73a2f15255ec), [`ebc864f0`](https://github.com/graphql/graphiql/commit/ebc864f0ab05000758cb2898daaa73a2f15255ec)]: - @graphiql/react@0.1.2 ## 1.9.1 ### Patch Changes - [#2423](https://github.com/graphql/graphiql/pull/2423) [`838e58da`](https://github.com/graphql/graphiql/commit/838e58dad652d8f5559af7b88d049b1c62348f2f) Thanks [@chentsulin](https://github.com/chentsulin)! - Fix peer dependency declaration by using `||` instead of `|` to link multiple major versions - Updated dependencies [[`838e58da`](https://github.com/graphql/graphiql/commit/838e58dad652d8f5559af7b88d049b1c62348f2f)]: - @graphiql/react@0.1.1 ## 1.9.0 ### Minor Changes - [#2412](https://github.com/graphql/graphiql/pull/2412) [`c2e2f53d`](https://github.com/graphql/graphiql/commit/c2e2f53d3b2ae369feb68537f92c73bcfd962f29) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move QueryStore from `graphiql` package to `@graphiql/toolkit` * [#2412](https://github.com/graphql/graphiql/pull/2412) [`c2e2f53d`](https://github.com/graphql/graphiql/commit/c2e2f53d3b2ae369feb68537f92c73bcfd962f29) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move HistoryStore from `graphiql` package to `@graphiql/toolkit` - [#2409](https://github.com/graphql/graphiql/pull/2409) [`f2025ba0`](https://github.com/graphql/graphiql/commit/f2025ba06c5aa8e8ac68d29538ff135f3efc8e46) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move the logic of the variable editor from the `graphiql` package into a hook `useVariableEditor` provided by `@graphiql/react` * [#2408](https://github.com/graphql/graphiql/pull/2408) [`d825bb75`](https://github.com/graphql/graphiql/commit/d825bb7569ca6b1ebbe534b893354645c790e003) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move the logic of the query editor from the `graphiql` package into a hook `useQueryEditor` provided by `@graphiql/react` - [#2411](https://github.com/graphql/graphiql/pull/2411) [`ad448693`](https://github.com/graphql/graphiql/commit/ad4486934ba69247efd33ee500e30f8236ecd079) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move the logic of the result viewer from the `graphiql` package into a hook `useResponseEditor` provided by `@graphiql/react` * [#2370](https://github.com/graphql/graphiql/pull/2370) [`7f695b10`](https://github.com/graphql/graphiql/commit/7f695b104f9b25ba8c6d36f7827c475b297b7482) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Include the context provider for the explorer from `@graphiql/react` and replace the local state for the nav stack of the docs with methods provided by hooks from `@graphiql/react`. - [#2412](https://github.com/graphql/graphiql/pull/2412) [`c2e2f53d`](https://github.com/graphql/graphiql/commit/c2e2f53d3b2ae369feb68537f92c73bcfd962f29) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move StorageAPI from `graphiql` package to `@graphiql/toolkit` * [#2404](https://github.com/graphql/graphiql/pull/2404) [`029ddf82`](https://github.com/graphql/graphiql/commit/029ddf82c29754ab8518ae7df66f9b25361a8247) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add a context provider for editors and move the logic of the headers editor from the `graphiql` package into a hook `useHeaderEditor` provided by `@graphiql/react` ### Patch Changes - [#2418](https://github.com/graphql/graphiql/pull/2418) [`6d7fb6e6`](https://github.com/graphql/graphiql/commit/6d7fb6e6fa4734e2274d8875971613a8254674e3) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix persisting headers in tab state and avoid opening duplicate tabs when reloading - Updated dependencies [[`c2e2f53d`](https://github.com/graphql/graphiql/commit/c2e2f53d3b2ae369feb68537f92c73bcfd962f29), [`bc3dc64c`](https://github.com/graphql/graphiql/commit/bc3dc64c37478ba6170c49c25fb755b4f2e020b2), [`c2e2f53d`](https://github.com/graphql/graphiql/commit/c2e2f53d3b2ae369feb68537f92c73bcfd962f29), [`f2025ba0`](https://github.com/graphql/graphiql/commit/f2025ba06c5aa8e8ac68d29538ff135f3efc8e46), [`d825bb75`](https://github.com/graphql/graphiql/commit/d825bb7569ca6b1ebbe534b893354645c790e003), [`ad448693`](https://github.com/graphql/graphiql/commit/ad4486934ba69247efd33ee500e30f8236ecd079), [`7f695b10`](https://github.com/graphql/graphiql/commit/7f695b104f9b25ba8c6d36f7827c475b297b7482), [`c2e2f53d`](https://github.com/graphql/graphiql/commit/c2e2f53d3b2ae369feb68537f92c73bcfd962f29), [`029ddf82`](https://github.com/graphql/graphiql/commit/029ddf82c29754ab8518ae7df66f9b25361a8247)]: - @graphiql/toolkit@0.5.0 - @graphiql/react@0.1.0 ## 1.8.10 ### Patch Changes - [#2397](https://github.com/graphql/graphiql/pull/2397) [`a63ff958`](https://github.com/graphql/graphiql/commit/a63ff958838cf4fcf31f7eaa3e3b022d02838f65) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - upgrade to React v17 * [#2401](https://github.com/graphql/graphiql/pull/2401) [`60a744b1`](https://github.com/graphql/graphiql/commit/60a744b1d73d1021afb7abeea1573f26178102b5) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - move async helper functions and formatting functions over into the @graphiql/toolkit package * Updated dependencies [[`60a744b1`](https://github.com/graphql/graphiql/commit/60a744b1d73d1021afb7abeea1573f26178102b5), [`60a744b1`](https://github.com/graphql/graphiql/commit/60a744b1d73d1021afb7abeea1573f26178102b5)]: - @graphiql/toolkit@0.4.5 ## 1.8.9 ### Patch Changes - [#2387](https://github.com/graphql/graphiql/pull/2387) [`e823697b`](https://github.com/graphql/graphiql/commit/e823697b5d47565671d5919be84f69919e70977f) Thanks [@benjie](https://github.com/benjie)! - Add 'children' type definition to various component props * [#2388](https://github.com/graphql/graphiql/pull/2388) [`d3ae074c`](https://github.com/graphql/graphiql/commit/d3ae074c9b9dae6ed4f69b0a79efaa0353dcea2d) Thanks [@benjie](https://github.com/benjie)! - Add 'pointer-events: none' to SVG style for dropdown arrow in GraphiQL.Menu component - [#2373](https://github.com/graphql/graphiql/pull/2373) [`5b2c1b20`](https://github.com/graphql/graphiql/commit/5b2c1b2054a70e8dca173f380f44766438cb5597) Thanks [@benjie](https://github.com/benjie)! - Fix TypeScript definition of FetcherParams to reflect that operationName is optional - Updated dependencies [[`5b2c1b20`](https://github.com/graphql/graphiql/commit/5b2c1b2054a70e8dca173f380f44766438cb5597)]: - @graphiql/toolkit@0.4.4 ## 1.8.8 ### Patch Changes - Updated dependencies [[`2dec55f2`](https://github.com/graphql/graphiql/commit/2dec55f2c5e979cc7bb1adadff4fb063775b088c), [`d22f6111`](https://github.com/graphql/graphiql/commit/d22f6111a60af25727d8dbc1058c79607df76af2)]: - codemirror-graphql@1.3.0 - graphql-language-service@5.0.4 ## 1.8.7 ### Patch Changes - [#2316](https://github.com/graphql/graphiql/pull/2316) [`3d8510c8`](https://github.com/graphql/graphiql/commit/3d8510c87b9f0cc73f747ed4cd88e112f9fe65f7) Thanks [@AlirezaHaghshenas](https://github.com/AlirezaHaghshenas)! - Fix: With tabs enabled, if a subscription is restored from storage, a query request is sent instead ## 1.8.6 ### Patch Changes - [#2312](https://github.com/graphql/graphiql/pull/2312) [`3c97cf63`](https://github.com/graphql/graphiql/commit/3c97cf63f0d6a8c27265905af1a2da243925ff01) Thanks [@AlirezaHaghshenas](https://github.com/AlirezaHaghshenas)! - Fix: After changing to a tab with a subscription, graphiql sends a query request - Updated dependencies [[`45cbc759`](https://github.com/graphql/graphiql/commit/45cbc759c732999e8b1eb4714d6047ab77c17902)]: - graphql-language-service@5.0.3 - codemirror-graphql@1.2.17 ## 1.8.5 ### Patch Changes - Updated dependencies [[`c36504a8`](https://github.com/graphql/graphiql/commit/c36504a804d8cc54a5136340152999b4a1a2c69f)]: - graphql-language-service@5.0.2 - codemirror-graphql@1.2.16 ## 1.8.4 ### Patch Changes - [#2274](https://github.com/graphql/graphiql/pull/2274) [`12950380`](https://github.com/graphql/graphiql/commit/12950380e92c38f6eec23499e7fca5dc9dcd8216) Thanks [@B2o5T](https://github.com/B2o5T)! - turn `valid-typeof` as `error`, SSR fix - Updated dependencies [[`12950380`](https://github.com/graphql/graphiql/commit/12950380e92c38f6eec23499e7fca5dc9dcd8216)]: - @graphiql/toolkit@0.4.3 ## 1.8.3 ### Patch Changes - [#2268](https://github.com/graphql/graphiql/pull/2268) [`b1886822`](https://github.com/graphql/graphiql/commit/b188682296ee04a87fbf09dc51385f127bffcec0) Thanks [@acao](https://github.com/acao)! - remove dependency on `global` for esbuild/etc users! * [#2265](https://github.com/graphql/graphiql/pull/2265) [`9458e10b`](https://github.com/graphql/graphiql/commit/9458e10ba24a6c919142ea1cebb409c7d055baf9) Thanks [@acao](https://github.com/acao)! - fix `codemirror` import bug for `onHasCompletion` for #2263. for esm/cjs users on autocomplete (umd bundle users not impacted) ## 1.8.2 ### Patch Changes - Updated dependencies [[`261f2044`](https://github.com/graphql/graphiql/commit/261f2044066412e40f9962bef55295f7c9c35aec)]: - codemirror-graphql@1.2.15 ## 1.8.1 ### Patch Changes - [#2257](https://github.com/graphql/graphiql/pull/2257) [`6cc95851`](https://github.com/graphql/graphiql/commit/6cc9585119f33ba80f960da310f7ef2747b7bc38) Thanks [@acao](https://github.com/acao)! - _security fix:_ replace the vulnerable `dset` dependency with `set-value` `dset` is vulnerable to prototype pollution attacks. this is only possible if you are doing all of the following: 1. running graphiql with an experimental graphql-js release tag that supports @stream and @defer 2. executing a properly @streamed or @deferred query ala IncrementalDelivery spec, with multipart chunks 3. consuming a malicious schema that contains field names like proto, prototype, or constructor that return malicious data designed to exploit a prototype pollution attack ## 1.8.0 ### Minor Changes - [#2197](https://github.com/graphql/graphiql/pull/2197) [`3137a6c4`](https://github.com/graphql/graphiql/commit/3137a6c4333dad8db8a0eb980d6c6464c7292946) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Now featuring: tabs! 🥳 🍾 just opt-in with new prop ``. You can also both opt-in and provide a handler via ``! ### Patch Changes - [#2249](https://github.com/graphql/graphiql/pull/2249) [`1540fd3d`](https://github.com/graphql/graphiql/commit/1540fd3d0df553798e41a153c5f0386d9d52be01) Thanks [@acao](https://github.com/acao)! - Finally remove inline `require()` for codemirror addon imports, replace with modern dynamic `import()` (which enables `esbuild`, `vite`, etc). This change should allow your bundler to code split codemirror-graphql and the codemirror addons based on which you import. For SSR support, GraphiQL must load these modules dynamically. If you want to use other codemirror addons (vim, etc) for non-ssr you can just import them top level, or for SSR, you can just dynamically import them. ## 1.7.2 ### Patch Changes - Updated dependencies [[`3626f8d5`](https://github.com/graphql/graphiql/commit/3626f8d5012ee77a39e984ae347396cb00fcc6fa), [`3626f8d5`](https://github.com/graphql/graphiql/commit/3626f8d5012ee77a39e984ae347396cb00fcc6fa)]: - graphql-language-service@5.0.1 - codemirror-graphql@1.2.14 ## 1.7.1 ### Patch Changes - Updated dependencies [[`2502a364`](https://github.com/graphql/graphiql/commit/2502a364b74dc754d92baa1579b536cf42139958)]: - graphql-language-service@5.0.0 - codemirror-graphql@1.2.13 ## 1.7.0 ### Minor Changes - [#2221](https://github.com/graphql/graphiql/pull/2221) [`64826c87`](https://github.com/graphql/graphiql/commit/64826c8776dfc8394a65c98663d47cc3c9d397b9) Thanks [@dwwoelfel](https://github.com/dwwoelfel)! - Fix to trigger codemirror update when externalFragments prop changes [#2220](https://github.com/graphql/graphiql/pull/2220) * [#2213](https://github.com/graphql/graphiql/pull/2213) [`ba85bc24`](https://github.com/graphql/graphiql/commit/ba85bc242b8271cbd09ade9d69a93d86e4e1a49f) Thanks [@hatappi](https://github.com/hatappi)! - remove IE7 CSS star property hack ### Patch Changes - [#2205](https://github.com/graphql/graphiql/pull/2205) [`91500d4e`](https://github.com/graphql/graphiql/commit/91500d4eba8b99bf779ff6ac899c814070c6dff3) Thanks [@francisu](https://github.com/francisu)! - Fixed problem where 'global' variable is referenced when it might not be present (#2155) ## 1.6.0 ### Minor Changes - [#2191](https://github.com/graphql/graphiql/pull/2191) [`eb8af7b5`](https://github.com/graphql/graphiql/commit/eb8af7b5666e7ed01497a862127011524fc400f5) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Allow inserting content before the topBar element via the `beforeTopBarContent` property. ```jsx } /> ``` * [#2189](https://github.com/graphql/graphiql/pull/2189) [`96d47267`](https://github.com/graphql/graphiql/commit/96d4726716b782fcafa9d6c1671f3a3050ebe0b7) Thanks [@n1ru4l](https://github.com/n1ru4l)! - Apply variable editor title text styles via class `variable-editor-title-text` instead of using inline-styles. This allows better customization of styles. An active element also has the class `active`. This allows overriding the inactive state color using the selector `.graphiql-container .variable-editor-title-text` and overriding the active state color using the selector `.graphiql-container .variable-editor-title-text.active`. - [#2190](https://github.com/graphql/graphiql/pull/2190) [`d5179899`](https://github.com/graphql/graphiql/commit/d517989996cf6f33ef7e08d18a870e2bed565cca) Thanks [@n1ru4l](https://github.com/n1ru4l)! - New callback property `onSchemaChange` for `GraphiQL`. The callback is invoked with the successfully fetched schema from the remote. **Usage example:** ```tsx console.log(schema)} /> ``` ## 1.5.20 ### Patch Changes - Updated dependencies [[`484c0523`](https://github.com/graphql/graphiql/commit/484c0523cdd529f9e261d61a38616b6745075c7f), [`5852ba47`](https://github.com/graphql/graphiql/commit/5852ba47c720a2577817aed512bef9a262254f2c), [`48c5df65`](https://github.com/graphql/graphiql/commit/48c5df654e323cee3b8c57d7414247465235d1b5)]: - graphql-language-service@4.1.5 - codemirror-graphql@1.2.12 ## 1.5.19 ### Patch Changes - [#2167](https://github.com/graphql/graphiql/pull/2167) [`bc81f0ee`](https://github.com/graphql/graphiql/commit/bc81f0ee6d382fe996d92e55f90cdc3be10910a7) Thanks [@acao](https://github.com/acao)! - Fix legacy bug where global is expected ## 1.5.18 ### Patch Changes - [#2156](https://github.com/graphql/graphiql/pull/2156) [`ae5ea77b`](https://github.com/graphql/graphiql/commit/ae5ea77b4c2ec2a25e25c542ae72b2c3dabbe256) Thanks [@francisu](https://github.com/francisu)! - Fixed problem where 'global' variable is referenced when it might not be present (#2155) ## 1.5.17 ### Patch Changes - [#2138](https://github.com/graphql/graphiql/pull/2138) [`8700b4bb`](https://github.com/graphql/graphiql/commit/8700b4bbaadb17136f649f504c9575a8c853cd0b) Thanks [@danielleletarte](https://github.com/danielleletarte)! - Correctly render line breaks for Descriptions in Doc Explorer - #2137 - @danielleletarte ## 1.5.16 ### Patch Changes - Updated dependencies []: - graphql-language-service@4.1.4 - codemirror-graphql@1.2.11 ## 1.5.15 ### Patch Changes - Updated dependencies [[`a44772d6`](https://github.com/graphql/graphiql/commit/a44772d6af97254c4f159ea7237e842a3e3719e8)]: - graphql-language-service@4.1.3 - codemirror-graphql@1.2.10 ## 1.5.14 ### Patch Changes - Updated dependencies [[`e20760fb`](https://github.com/graphql/graphiql/commit/e20760fbd95c13d6d549cba3faa15a59aee9a2c0)]: - graphql-language-service@4.1.2 - codemirror-graphql@1.2.9 ## 1.5.13 ### Patch Changes - [#2097](https://github.com/graphql/graphiql/pull/2097) [`4d3eeaa4`](https://github.com/graphql/graphiql/commit/4d3eeaa4446c84e92cd77f213e454059602a72e5) Thanks [@acao](https://github.com/acao)! - Disable introspection of schema.description by default ## 1.5.12 ### Patch Changes - [#2091](https://github.com/graphql/graphiql/pull/2091) [`ff9cebe5`](https://github.com/graphql/graphiql/commit/ff9cebe515a3539f85b9479954ae644dfeb68b63) Thanks [@acao](https://github.com/acao)! - Fix graphql 15 related issues. Should now build & test interchangeably. - Updated dependencies [[`ff9cebe5`](https://github.com/graphql/graphiql/commit/ff9cebe515a3539f85b9479954ae644dfeb68b63)]: - codemirror-graphql@1.2.8 - graphql-language-service@4.1.1 ## 1.5.11 ### Patch Changes - Updated dependencies [[`0f1f90ce`](https://github.com/graphql/graphiql/commit/0f1f90ce8f4a25ddebdaf7a9ddbe136214aa64a3)]: - graphql-language-service@4.1.0 - codemirror-graphql@1.2.7 ## 1.5.10 ### Patch Changes - [#2087](https://github.com/graphql/graphiql/pull/2087) [`45a9075d`](https://github.com/graphql/graphiql/commit/45a9075d718046e0f17c930162fa9752dfe052ec) Thanks [@acao](https://github.com/acao)! - Fix issue with introspection in servers which don't support `inputValueDeprecation`. make `inputValueDeprecation` an opt-in prop for DocExplorer features ## 1.5.9 ### Patch Changes - [#2077](https://github.com/graphql/graphiql/pull/2077) [`701ca13f`](https://github.com/graphql/graphiql/commit/701ca13f625735564d71931e6d917e5bf69c8aa5) Thanks [@acao](https://github.com/acao)! - Include schema description in DocExplorer for schema introspection requests. Enables the `schemaDescription` option for `getIntrospectionQuery()`. Also includes `deprecationReason` support in DocExplorer for arguments! Enables `inputValueDeprecation` in `getIntrospectionQuery()` and displays deprecation section on field doc view. - Updated dependencies [[`9df315b4`](https://github.com/graphql/graphiql/commit/9df315b44896efa313ed6744445fc8f9e702ebc3)]: - graphql-language-service@4.0.0 - codemirror-graphql@1.2.6 ## 1.5.8 ### Patch Changes - Updated dependencies [[`df57cd25`](https://github.com/graphql/graphiql/commit/df57cd2556302d6aa5dd140e7bee3f7bdab4deb1)]: - graphql-language-service@3.2.5 - codemirror-graphql@1.2.5 ## 1.5.7 ### Patch Changes - [`49bce429`](https://github.com/graphql/graphiql/commit/49bce429f0780a5e2856cfb7ccda50d10d38f724) [#2051](https://github.com/graphql/graphiql/pull/2051) Thanks [@willstott101](https://github.com/willstott101)! - Include source maps for minified JS and CSS in the graphiql package. ## 1.5.6 ### Patch Changes - Updated dependencies []: - graphql-language-service@3.2.4 - codemirror-graphql@1.2.4 ## 1.5.5 ### Patch Changes - Updated dependencies [[`c42b145f`](https://github.com/graphql/graphiql/commit/c42b145fffeaefbd1103bc7addee1873e939bc83)]: - codemirror-graphql@1.2.3 ## 1.5.4 ### Patch Changes - [`bdd57312`](https://github.com/graphql/graphiql/commit/bdd573129844168749aba0aaa20e31b9da81aacf) [#2047](https://github.com/graphql/graphiql/pull/2047) Thanks [@willstott101](https://github.com/willstott101)! - Source code included in all packages to fix source maps. codemirror-graphql includes esm build in package. - Updated dependencies [[`bdd57312`](https://github.com/graphql/graphiql/commit/bdd573129844168749aba0aaa20e31b9da81aacf), [`8b486555`](https://github.com/graphql/graphiql/commit/8b486555e2aa4d90891070a1bbc52b59d9c670c4)]: - codemirror-graphql@1.2.2 - graphql-language-service@3.2.3 ## 1.5.3 ### Patch Changes - [`c83d1d4c`](https://github.com/graphql/graphiql/commit/c83d1d4c518ad1b0862aae5f46359dfaee00dda1) Thanks [@kikkupico](https://github.com/kikkupico)! - fix `schema` type nullability for #2028 * [`858907d2`](https://github.com/graphql/graphiql/commit/858907d2106742a65ec52eb017f2e91268cc37bf) [#2045](https://github.com/graphql/graphiql/pull/2045) Thanks [@acao](https://github.com/acao)! - fix graphql-js peer dependencies - [#2044](https://github.com/graphql/graphiql/pull/2044) * Updated dependencies [[`858907d2`](https://github.com/graphql/graphiql/commit/858907d2106742a65ec52eb017f2e91268cc37bf)]: - codemirror-graphql@1.2.1 - @graphiql/toolkit@0.4.2 - graphql-language-service@3.2.2 ## 1.5.2 ### Patch Changes - Updated dependencies [[`dec207e7`](https://github.com/graphql/graphiql/commit/dec207e74f0506db069482cc30f8cd1f045d8107), [`b79bf304`](https://github.com/graphql/graphiql/commit/b79bf304045add4b5c3b2539dd6b551a64e6ed87), [`d0c22c4f`](https://github.com/graphql/graphiql/commit/d0c22c4fce5ea39611c7ecee553943fdf27fd03e)]: - @graphiql/toolkit@0.4.1 - codemirror-graphql@1.2.0 ## 1.5.1 ### Patch Changes - [`9a6ed03f`](https://github.com/graphql/graphiql/commit/9a6ed03fbe4de9652ff5d81a8f584234995dd2ce) [#2013](https://github.com/graphql/graphiql/pull/2013) Thanks [@PabloSzx](https://github.com/PabloSzx)! - Update utils - Updated dependencies [[`9a6ed03f`](https://github.com/graphql/graphiql/commit/9a6ed03fbe4de9652ff5d81a8f584234995dd2ce)]: - graphql-language-service@3.2.1 ## 1.5.0 ### Minor Changes - [`716cf786`](https://github.com/graphql/graphiql/commit/716cf786aea6af42ea637ca3c56ae6c6ebc17c7a) [#2010](https://github.com/graphql/graphiql/pull/2010) Thanks [@acao](https://github.com/acao)! - upgrade to `graphql@16.0.0-experimental-stream-defer.5`. thanks @saihaj! ### Patch Changes - Updated dependencies [[`716cf786`](https://github.com/graphql/graphiql/commit/716cf786aea6af42ea637ca3c56ae6c6ebc17c7a)]: - codemirror-graphql@1.1.0 - @graphiql/toolkit@0.4.0 - graphql-language-service@3.2.0 ## 1.4.8 ### Patch Changes - [`e63696de`](https://github.com/graphql/graphiql/commit/e63696de57a85c34d937bfb53345e2e0d0b874a4) [#2005](https://github.com/graphql/graphiql/pull/2005) Thanks [@acao](https://github.com/acao)! - Correct the npm readme security fix version number and links, thanks [@glasser](https://github.com/glasser) & [@dotansimha](https://github.com/dotansimha)! ## 1.4.7 ### Patch Changes - [`130ddad6`](https://github.com/graphql/graphiql/commit/130ddad6d0394356ec32070a6fee1840450a4660) Thanks [@acao](https://github.com/acao)! - **CRITICAL SECURITY PATCH** for the [GraphiQL introspection schema template injection attack](https://github.com/graphql/graphiql/security/advisories/GHSA-x4r7-m2q9-69c8) ## 1.4.6 ### Patch Changes - [`d3a88283`](https://github.com/graphql/graphiql/commit/d3a88283c7b618376ad4a06c7db20e60b066d1a0) [#1934](https://github.com/graphql/graphiql/pull/1934) Thanks [@tonyfromundefined](https://github.com/tonyfromundefined)! - add react 17, 18 in peerDependencies * [`afaa36c1`](https://github.com/graphql/graphiql/commit/afaa36c198648e84f305986a0b1dfefa97e70221) [#1883](https://github.com/graphql/graphiql/pull/1883) Thanks [@Sweetabix1](https://github.com/Sweetabix1)! - Updating font colors for line numbers, comments & brackets from #999 to #666 for accessibility purposes. #666 passes AA accessibility standards for small text, with a contrast ratio of over 5:1. - [`75dbb0b1`](https://github.com/graphql/graphiql/commit/75dbb0b18e2102d271a5cfe78faf54fe22e83ac8) [#1777](https://github.com/graphql/graphiql/pull/1777) Thanks [@dwwoelfel](https://github.com/dwwoelfel)! - adopt block string parsing for variables in language parser - Updated dependencies [[`0e2c1a02`](https://github.com/graphql/graphiql/commit/0e2c1a020cc2761155f7c9467d3ed4cb45941aeb), [`75dbb0b1`](https://github.com/graphql/graphiql/commit/75dbb0b18e2102d271a5cfe78faf54fe22e83ac8)]: - graphql-language-service@3.1.6 - codemirror-graphql@1.0.3 ## 1.4.5 ### Patch Changes - [`86795d5f`](https://github.com/graphql/graphiql/commit/86795d5ffa2d3e6c8aee74f761d02f054b428d46) Thanks [@acao](https://github.com/acao)! - Remove bad type definition from `subscriptions-transport-ws` #1992 closes #1989 - Updated dependencies [[`86795d5f`](https://github.com/graphql/graphiql/commit/86795d5ffa2d3e6c8aee74f761d02f054b428d46)]: - @graphiql/toolkit@0.3.2 ## 1.4.4 ### Patch Changes - [`62e786b5`](https://github.com/graphql/graphiql/commit/62e786b57cc5748eccac59814dfc8ecd0104c748) [#1990](https://github.com/graphql/graphiql/pull/1990) Thanks [@acao](https://github.com/acao)! - Remove type definition from `subscriptions-transport-ws` - Updated dependencies [[`62e786b5`](https://github.com/graphql/graphiql/commit/62e786b57cc5748eccac59814dfc8ecd0104c748)]: - @graphiql/toolkit@0.3.1 ## 1.4.3 ### Patch Changes - [`6a459f4c`](https://github.com/graphql/graphiql/commit/6a459f4c235bb0d70725ae6ad7fc1cfa34f49dca) [#1968](https://github.com/graphql/graphiql/pull/1968) Thanks [@acao](https://github.com/acao)! - Remove `optionalDependencies` entirely, remove `subscriptions-transport-ws` which introduces vulnerabilities, upgrade `@n1ru4l/push-pull-async-iterable-iterator` to 3.0.0, upgrade `graphql-ws` several minor versions - the `graphql-ws@5.x` upgrade will come in a later minor release. * [`eb2d91fa`](https://github.com/graphql/graphiql/commit/eb2d91fa8e4a03cb5663f27f724db2c95989a40f) [#1914](https://github.com/graphql/graphiql/pull/1914) Thanks [@harshithpabbati](https://github.com/harshithpabbati)! - fix: history can now be saved even when query history panel is not opened feat: create a new maxHistoryLength prop to allow more than 20 queries in history panel - [`04fad79c`](https://github.com/graphql/graphiql/commit/04fad79c094318d4b4c9e0250c5cff55d9fc5116) [#1889](https://github.com/graphql/graphiql/pull/1889) Thanks [@henryqdineen](https://github.com/henryqdineen)! - feat: export ToolbarSelectOption and ToolbarMenuItem * [`cd685435`](https://github.com/graphql/graphiql/commit/cd6854352ac6beff57af76db7de38e8157ff13aa) [#1923](https://github.com/graphql/graphiql/pull/1923) Thanks [@cgarnier](https://github.com/cgarnier)! - Fix result window theme * Updated dependencies [[`6a459f4c`](https://github.com/graphql/graphiql/commit/6a459f4c235bb0d70725ae6ad7fc1cfa34f49dca), [`2fd5bf72`](https://github.com/graphql/graphiql/commit/2fd5bf7239edb78339e5ac7211f09c245e47c3bb)]: - @graphiql/toolkit@0.3.0 - graphql-language-service@3.1.5 ## 1.4.2 ### Patch Changes - [`5b8a057d`](https://github.com/graphql/graphiql/commit/5b8a057dd64ebecc391be32176a2403bb9d9ff92) [#1838](https://github.com/graphql/graphiql/pull/1838) Thanks [@acao](https://github.com/acao)! - Set all cross-runtime build targets to es6 ## 1.4.1 ### Patch Changes - [`9f8c78ce`](https://github.com/graphql/graphiql/commit/9f8c78ce8c72a9dcf35b3e82bd3129ac17d845e6) [#1821](https://github.com/graphql/graphiql/pull/1821) Thanks [@harshithpabbati](https://github.com/harshithpabbati)! - fix: render query history panel only when it's toggled, instead of hiding with CSS * [`dd9397e4`](https://github.com/graphql/graphiql/commit/dd9397e4c693b5ceadbd26d6fa92aa6246aac9c3) [#1819](https://github.com/graphql/graphiql/pull/1819) Thanks [@acao](https://github.com/acao)! - `GraphiQL.createClient()` accepts custom `legacyClient`, exports typescript types, fixes #1800. `createGraphiQLFetcher` now only attempts an `graphql-ws` connection when only `subscriptionUrl` is provided. In order to use `graphql-transport-ws`, you'll need to provide the `legacyClient` option only, and no `subscriptionUrl` or `wsClient` option. - [`1f92d1dc`](https://github.com/graphql/graphiql/commit/1f92d1dcc0102bdec078263b87ca20cd670a1c86) [#1804](https://github.com/graphql/graphiql/pull/1804) Thanks [@maraisr](https://github.com/maraisr)! - Fixes issue where with IncrementalDelivery directives objects wouldn't deep-merge. * [`6869ce77`](https://github.com/graphql/graphiql/commit/6869ce7767050787db5f1017abf82fa5a52fc97a) [#1816](https://github.com/graphql/graphiql/pull/1816) Thanks [@acao](https://github.com/acao)! - improve peer resolutions for graphql 14 & 15. `14.5.0` minimum is for built-in typescript types, and another method only available in `14.4.0` * Updated dependencies [[`dd9397e4`](https://github.com/graphql/graphiql/commit/dd9397e4c693b5ceadbd26d6fa92aa6246aac9c3), [`6869ce77`](https://github.com/graphql/graphiql/commit/6869ce7767050787db5f1017abf82fa5a52fc97a)]: - @graphiql/toolkit@0.2.0 ## 1.4.0 ### Patch Changes - Updated dependencies [[`b4fc16c0`](https://github.com/graphql/graphiql/commit/b4fc16c025da6f466727dc17cab6026d14c6e7fe)]: - codemirror-graphql@1.0.0 ## 1.4.0 ### Bugfixes - Fixes the search icon misalignment. (#1776) by [@iifawzi](https://github.com/iifawzi) - run `onToggleDocs` when setting `docExplorerOpen` to false (#1768) by [@ChiragKasat](https://github.com/ChiragKasat) ### Minor Changes - 1c119386: `@defer`, `@stream`, and `graphql-ws` support in a `createGraphiQLFetcher` utility (#1770) - support for `@defer` and `@stream` in `GraphiQL` itself on fetcher execution and when handling stream payloads - introduce `@graphiql/toolkit` for types and utilities used to compose `GraphiQL` and other related libraries - introduce `@graphiql/create-fetcher` to accept simplified parameters to generate a `fetcher` that covers the most commonly used `graphql-over-http` transport spec proposals. using `meros` for multipart http, and `graphql-ws` for websockets subscriptions. - use `graphql` and `graphql-express` `experimental-defer-stream` branch in development until it's merged - add cypress e2e tests for `@stream` in different scenarios - add some unit tests for `createGraphiQLFetcher` ### Patch Changes - Updated dependencies [1c119386] - @graphiql/create-fetcher@0.1.0 - @graphiql/toolkit@0.1.0 ## [1.3.2](https://github.com/graphql/graphiql/compare/graphiql@1.3.1...graphiql@1.3.2) (2021-01-07) **Note:** Version bump only for package graphiql ## [1.3.1](https://github.com/graphql/graphiql/compare/graphiql@1.3.0...graphiql@1.3.1) (2021-01-07) **Note:** Version bump only for package graphiql ## [1.3.0](https://github.com/graphql/graphiql/compare/graphiql@1.2.2...graphiql@1.3.0) (2021-01-07) ### Features - also support fetcher functions that return Promise or Promise ([#1739](https://github.com/graphql/graphiql/issues/1739)) ([a804f3c](https://github.com/graphql/graphiql/commit/a804f3c011e7cafb4f8a48a1ba101b875be3540d)) - implied or external fragments, for [#612](https://github.com/graphql/graphiql/issues/612) ([#1750](https://github.com/graphql/graphiql/issues/1750)) ([cfed265](https://github.com/graphql/graphiql/commit/cfed265e3cf31875b39ea517781a217fcdfcadc2)) ## [1.2.2](https://github.com/graphql/graphiql/compare/graphiql@1.2.1...graphiql@1.2.2) (2021-01-03) **Note:** Version bump only for package graphiql ## [1.2.1](https://github.com/graphql/graphiql/compare/graphiql@1.2.0...graphiql@1.2.1) (2020-12-28) ### Bug Fixes - display schema description if available ([050c506](https://github.com/graphql/graphiql/commit/050c506ed4ed2852bf9a5b099f967928d9856156)) - fix linting issue ([7117b7c](https://github.com/graphql/graphiql/commit/7117b7ccd2a2872e0051c8751252040d4042e190)) ## [1.2.0](https://github.com/graphql/graphiql/compare/graphiql@1.1.0...graphiql@1.2.0) (2020-12-08) ### Features - add AsyncIterable support to fetcher function ([#1724](https://github.com/graphql/graphiql/issues/1724)) ([a568af3](https://github.com/graphql/graphiql/commit/a568af3674404b8a15055792c2c35128b2bd711c)) - provide validation rules via props ([#1716](https://github.com/graphql/graphiql/issues/1716)) ([0c5785c](https://github.com/graphql/graphiql/commit/0c5785c82adbd4affb25300ae2d128b42c9b81fe)) ## [1.1.0](https://github.com/graphql/graphiql/compare/graphiql@1.0.6...graphiql@1.1.0) (2020-11-28) ### Bug Fixes - improve props in GraphiQL readme ([b9b2c8d](https://github.com/graphql/graphiql/commit/b9b2c8d8bde6064a4cdcb01911b024602fcdbe9f)) ### Features - **graphiql:** add prop for adding toolbar content while preserving the default buttons ([ea81056](https://github.com/graphql/graphiql/commit/ea81056e09b0a95e1536c79fab27e027739808c4)) - deeper fragment merging ([238d0b5](https://github.com/graphql/graphiql/commit/238d0b5e52cfa9354757c9d52050692d152aae21)) ## [1.0.6](https://github.com/graphql/graphiql/compare/graphiql@1.0.5...graphiql@1.0.6) (2020-10-20) ### Bug Fixes - enable variable editor when header editor is not enabled ([#1682](https://github.com/graphql/graphiql/issues/1682)) ([205fbad](https://github.com/graphql/graphiql/commit/205fbad84806d175d66a6f5598e0a0f521129a16)) ## [1.0.5](https://github.com/graphql/graphiql/compare/graphiql@1.0.4...graphiql@1.0.5) (2020-09-18) **Note:** Version bump only for package graphiql ## [1.0.4](https://github.com/graphql/graphiql/compare/graphiql@2.0.0-alpha.5...graphiql@1.0.4) (2020-09-11) ### Bug Fixes - don't use initial query on every re-render ([#1663](https://github.com/graphql/graphiql/issues/1663)) ([5aa890f](https://github.com/graphql/graphiql/commit/5aa890f6e145a7ad49f82cc122e209a291060709)) ## [1.0.3](https://github.com/graphql/graphiql/compare/graphiql@1.0.2...graphiql@1.0.3) (2020-06-24) ### Bug Fixes - headers tab - highlighting and schema fetch ([#1593](https://github.com/graphql/graphiql/issues/1593)) ([0d050ca](https://github.com/graphql/graphiql/commit/0d050caeb5278799f2b1c206d0c61f3ac768e7cd)) ## [1.0.2](https://github.com/graphql/graphiql/compare/graphiql@1.0.1...graphiql@1.0.2) (2020-06-19) **Note:** Version bump only for package graphiql ## [1.0.1](https://github.com/graphql/graphiql/compare/graphiql@1.0.0...graphiql@1.0.1) (2020-06-17) ### Bug Fixes - more server side rendering fixes ([#1581](https://github.com/graphql/graphiql/issues/1581)) ([881a19f](https://github.com/graphql/graphiql/commit/881a19fbd5fbe5f65678de8074e593be7deb2ede)), closes [#1573](https://github.com/graphql/graphiql/issues/1573) - network cancellation for 1.0 ([#1582](https://github.com/graphql/graphiql/issues/1582)) ([ad3cc0d](https://github.com/graphql/graphiql/commit/ad3cc0d1567ea49ff5677d4cd8524e5e072b605e)) - Set headers to localStorage ([#1578](https://github.com/graphql/graphiql/issues/1578)) ([cc7a7e2](https://github.com/graphql/graphiql/commit/cc7a7e2f6d25d7e8150dc89c6984e6a04b01566b)) ## [1.0.0](https://github.com/graphql/graphiql/compare/graphiql@1.0.0-alpha.13...graphiql@1.0.0) (2020-06-11) ### Bug Fixes - call debounce statements as they are functions ([#1571](https://github.com/graphql/graphiql/issues/1571)) ([8541250](https://github.com/graphql/graphiql/commit/85412501307ccfffe258b7fbca74bb9309726a73)) - fix server side rendering by using type only codemirror import ([#1573](https://github.com/graphql/graphiql/issues/1573)) ([1ee60a6](https://github.com/graphql/graphiql/commit/1ee60a6db87d54c7a1e8f1089e52a65f335351b6)), closes [#118](https://github.com/graphql/graphiql/issues/118) - Move all componentWillUnMount functionality to respective events ([#1544](https://github.com/graphql/graphiql/issues/1544)) ([046b09f](https://github.com/graphql/graphiql/commit/046b09f541e6a9f2ce4b46de590d49c04c916716)) ## [1.0.0-alpha.13](https://github.com/graphql/graphiql/compare/graphiql@1.0.0-alpha.12...graphiql@1.0.0-alpha.13) (2020-06-04) **Note:** Version bump only for package graphiql ## [1.0.0-alpha.12](https://github.com/graphql/graphiql/compare/graphiql@1.0.0-alpha.11...graphiql@1.0.0-alpha.12) (2020-06-04) ### Bug Fixes - cleanup cache entry from lerna publish ([4a26218](https://github.com/graphql/graphiql/commit/4a2621808a1aea8b30d5d27b8d86a60bf2b44b01)) - display variable editor when headers are not enabled ([ce7b2e2](https://github.com/graphql/graphiql/commit/ce7b2e2b45d530b61e916112e864074cf3a6ddc7)) ## [1.0.0-alpha.11](https://github.com/graphql/graphiql/compare/graphiql@1.0.0-alpha.10...graphiql@1.0.0-alpha.11) (2020-05-28) ### Bug Fixes - Safe setState ([#1547](https://github.com/graphql/graphiql/issues/1547)) ([f85969c](https://github.com/graphql/graphiql/commit/f85969c7e77e8fd269e026be36cc5065d6d33237)) - trigger edit variables on first render ([#1545](https://github.com/graphql/graphiql/issues/1545)) ([e54e1a8](https://github.com/graphql/graphiql/commit/e54e1a8691483f1d336231314130d9822481b3be)) ### Features - Add Headers Editor to GraphiQL ([#1543](https://github.com/graphql/graphiql/issues/1543)) ([3faa1ac](https://github.com/graphql/graphiql/commit/3faa1ac46514252e90abf2b2bda0841edf6115ea)) ## [1.0.0-alpha.10](https://github.com/graphql/graphiql/compare/graphiql@1.0.0-alpha.9...graphiql@1.0.0-alpha.10) (2020-05-19) ### Bug Fixes - graphiql non-relative import issues ([#1534](https://github.com/graphql/graphiql/issues/1534)) fixes [#1530](https://github.com/graphql/graphiql/issues/1530) ([0ac9fa0](https://github.com/graphql/graphiql/commit/0ac9fa0a8dcdf8464c8ce31c487ebcfd6b9536a8)) ## [1.0.0-alpha.9](https://github.com/graphql/graphiql/compare/graphiql@1.0.0-alpha.8...graphiql@1.0.0-alpha.9) (2020-05-17) ### Bug Fixes - remove problematic file resolution module from webpack sco… ([#1489](https://github.com/graphql/graphiql/issues/1489)) ([8dab038](https://github.com/graphql/graphiql/commit/8dab0385772f443f73b559e2c668080733168236)) ### Features - introduce proper vscode completion kinds ([#1488](https://github.com/graphql/graphiql/issues/1488)) ([f19aa0d](https://github.com/graphql/graphiql/commit/f19aa0ddde6109526c101c8a487f43bbb8238394)) - Monaco Mode - Phase 2 - Mode & Worker ([#1459](https://github.com/graphql/graphiql/issues/1459)) ([bc95fb4](https://github.com/graphql/graphiql/commit/bc95fb46459a4437ff9471ff43c98e1c5c50f51e)) ## [1.0.0-alpha.8](https://github.com/graphql/graphiql/compare/graphiql@1.0.0-alpha.7...graphiql@1.0.0-alpha.8) (2020-04-10) **Note:** Version bump only for package graphiql ## [1.0.0-alpha.7](https://github.com/graphql/graphiql/compare/graphiql@1.0.0-alpha.6...graphiql@1.0.0-alpha.7) (2020-04-10) **Note:** Version bump only for package graphiql ## [1.0.0-alpha.6](https://github.com/graphql/graphiql/compare/graphiql@1.0.0-alpha.5...graphiql@1.0.0-alpha.6) (2020-04-10) **Note:** Version bump only for package graphiql ## [1.0.0-alpha.5](https://github.com/graphql/graphiql/compare/graphiql@1.0.0-alpha.4...graphiql@1.0.0-alpha.5) (2020-04-06) ### Features - upgrade to graphql@15.0.0 for [#1191](https://github.com/graphql/graphiql/issues/1191) ([#1204](https://github.com/graphql/graphiql/issues/1204)) ([f13c8e9](https://github.com/graphql/graphiql/commit/f13c8e9d0e66df4b051b332c7d02f4bb83e07ffd)) ## [1.0.0-alpha.4](https://github.com/graphql/graphiql/compare/graphiql@1.0.0-alpha.3...graphiql@1.0.0-alpha.4) (2020-04-03) ### Bug Fixes - fix query argument missing from onEditQuery call ([#1440](https://github.com/graphql/graphiql/issues/1440)) ([6c335a8](https://github.com/graphql/graphiql/commit/6c335a813f6101afded00c0e869c337a7ca44020)) ## [1.0.0-alpha.3](https://github.com/graphql/graphiql/compare/graphiql@1.0.0-alpha.2...graphiql@1.0.0-alpha.3) (2020-03-20) **Note:** Version bump only for package graphiql ## [1.0.0-alpha.2](https://github.com/graphql/graphiql/compare/graphiql@1.0.0-alpha.0...graphiql@1.0.0-alpha.2) (2020-03-20) ### Bug Fixes - Fix typo in documentation (comments) ([#1431](https://github.com/graphql/graphiql/issues/1431)) ([fdda8f0](https://github.com/graphql/graphiql/commit/fdda8f04479412d22e9a3e9215c7caa5369e7d83)) - initial request cache set, import tsc bugs ([#1266](https://github.com/graphql/graphiql/issues/1266)) ([6b98f8a](https://github.com/graphql/graphiql/commit/6b98f8a442d4a8ea160fb90a29acf33f5382db2e)) ## [1.0.0-alpha.1](https://github.com/graphql/graphiql/compare/graphiql@0.17.5...graphiql@1.0.0-alpha.1) (2020-01-18) ### Bug Fixes - hmr, file resolution warnings ([69bf701](https://github.com/graphql/graphiql/commit/69bf701)) - prefer displayName over type equality for children overrides ([e4cec0a](https://github.com/graphql/graphiql/commit/e4cec0a)) - remove use of `findDOMNode` ([0b12323](https://github.com/graphql/graphiql/commit/0b12323)) by [@ryan-m-walker](https://github.com/ryan-m-walker) ### Features - deprecate support for 15, support react 16 features ([#1107](https://github.com/graphql/graphiql/issues/1107)) ([bc4b6fc](https://github.com/graphql/graphiql/commit/bc4b6fc)) - **graphiql-theming:** Toolbar component ([#1203](https://github.com/graphql/graphiql/issues/1203)) by [@walaura](https://github.com/walaura) ([adb73f5](https://github.com/graphql/graphiql/commit/adb73f5)) - [new-ui] Tabs & Tab-bars ([#1198](https://github.com/graphql/graphiql/issues/1198)) ([033f971](https://github.com/graphql/graphiql/commit/033f971)) by [@walaura](https://github.com/walaura) - replace use of enzyme with react-testing-library ([#1144](https://github.com/graphql/graphiql/issues/1144)) by [@ryan-m-walker](https://github.com/ryan-m-walker) ([de73d6c](https://github.com/graphql/graphiql/commit/de73d6c)) - storybook+theme-ui for the new design ([#1145](https://github.com/graphql/graphiql/issues/1145)) ([7f97c0c](https://github.com/graphql/graphiql/commit/7f97c0c)) by [@walaura](https://github.com/walaura) ### BREAKING CHANGES - Deprecate support for React 15. Please use React 16.8 or greater for hooks support. Co-authored-by: @ryan-m-walker, @acao Reviewed-by: @benjie ## [0.17.5](https://github.com/graphql/graphiql/compare/graphiql@0.17.4...graphiql@0.17.5) (2019-12-09) **Note:** Version bump only for package graphiql ## [0.17.4](https://github.com/graphql/graphiql/compare/graphiql@0.17.3...graphiql@0.17.4) (2019-12-09) ### Bug Fixes - graphiql babel test ignore paths ([e1588d9](https://github.com/graphql/graphiql/commit/e1588d9)) ## [0.17.3](https://github.com/graphql/graphiql/compare/graphiql@0.17.2...graphiql@0.17.3) (2019-12-09) ### Bug Fixes - express-graphql version ([e9848b0](https://github.com/graphql/graphiql/commit/e9848b0)) - test output, webpack resolution, clean build ([3b1c2c1](https://github.com/graphql/graphiql/commit/3b1c2c1)) ## [0.17.2](https://github.com/graphql/graphiql/compare/graphiql@0.17.1...graphiql@0.17.2) (2019-12-03) ### Bug Fixes - ensure css files move with babel dist ([ca95547](https://github.com/graphql/graphiql/commit/ca95547)) - remove css from downstream components. soon to be replaced w styled ([e765543](https://github.com/graphql/graphiql/commit/e765543)) ## [0.17.1](https://github.com/graphql/graphiql/compare/graphiql@0.17.0...graphiql@0.17.1) (2019-12-03) ### Bug Fixes - **graphiql:** duplicate query history key issue, fixes [#988](https://github.com/graphql/graphiql/issues/988) ([#1035](https://github.com/graphql/graphiql/issues/1035)) ([69c6826](https://github.com/graphql/graphiql/commit/69c6826)) - convert browserify build to webpack, fixes [#976](https://github.com/graphql/graphiql/issues/976) ([#1001](https://github.com/graphql/graphiql/issues/1001)) ([3caf041](https://github.com/graphql/graphiql/commit/3caf041)) - hints vertical scroll ([216eaeb](https://github.com/graphql/graphiql/commit/216eaeb)) ## [0.17.0](https://github.com/graphql/graphiql/compare/graphiql@0.16.0...graphiql@0.17.0) (2019-11-26) ### Bug Fixes - security bump, resolves [#1004](https://github.com/graphql/graphiql/issues/1004), SNYK-JS-MARKDOWNIT-459438 ([89c83db](https://github.com/graphql/graphiql/commit/89c83db)) - webpack resolutions for [#882](https://github.com/graphql/graphiql/issues/882), add webpack example ([ea9df3e](https://github.com/graphql/graphiql/commit/ea9df3e)) ### Features - **graphiql:** Prettify also formats query variables ([b7d0bfd](https://github.com/graphql/graphiql/commit/b7d0bfd)) ## [0.16.0](https://github.com/graphql/graphiql/compare/graphiql@0.15.1...graphiql@0.16.0) (2019-10-19) ### Bug Fixes - **accessibility:** improve accessibility of all components ([#967](https://github.com/graphql/graphiql/issues/967)) ([73a3f90](https://github.com/graphql/graphiql/commit/73a3f90)) - **css:** added minimum width for result panel in GraphiQL ([#980](https://github.com/graphql/graphiql/issues/980)) ([0c8b7ad](https://github.com/graphql/graphiql/commit/0c8b7ad)) - **graphiql:** better quota management ([#764](https://github.com/graphql/graphiql/issues/764)) ([7efed6c](https://github.com/graphql/graphiql/commit/7efed6c)) ### Features - **css:** beautify code tag in doc explorer ([#959](https://github.com/graphql/graphiql/issues/959)) resolves [#949](https://github.com/graphql/graphiql/issues/949) ([30810a2](https://github.com/graphql/graphiql/commit/30810a2)) ### [0.15.1](https://github.com/graphql/graphiql/compare/graphiql@0.15.0...graphiql@0.15.1) (2019-10-04) ### Bug Fixes - build tweaks ([0bc6a7c](https://github.com/graphql/graphiql/commit/0bc6a7c)) ## 0.15.0 (2019-10-04) ### Bug Fixes - check `window` is defined before using it ([#962](https://github.com/graphql/graphiql/issues/962)) ([e4866ad](https://github.com/graphql/graphiql/commit/e4866ad)) - **graphiql:** prettify keybinding bug for Firefox. Fixes [#905](https://github.com/graphql/graphiql/issues/905) ([fdf98ba](https://github.com/graphql/graphiql/commit/fdf98ba)) - check `this.editor` exist before `this.editor.off` in QueryEditor ([#669](https://github.com/graphql/graphiql/issues/669)) ([ca226ee](https://github.com/graphql/graphiql/commit/ca226ee)), closes [#665](https://github.com/graphql/graphiql/issues/665) - extraKeys bugfix window regression ([f3d0427](https://github.com/graphql/graphiql/commit/f3d0427)) - preserve ctrl-f key for macOS ([7c381f9](https://github.com/graphql/graphiql/commit/7c381f9)) ### Features - convert LSP from flow to typescript ([#957](https://github.com/graphql/graphiql/issues/957)) [@acao](https://github.com/acao) @Neitsch [@benjie](https://github.com/benjie) ([36ed669](https://github.com/graphql/graphiql/commit/36ed669)) ## 0.13.2 (2019-06-21) ## 0.14.3 (2019-09-01) ### Bug Fixes - check `this.editor` exist before `this.editor.off` in QueryEditor ([#669](https://github.com/graphql/graphiql/issues/669)) ([ca226ee](https://github.com/graphql/graphiql/commit/ca226ee)), closes [#665](https://github.com/graphql/graphiql/issues/665) - extraKeys bugfix window regression ([f3d0427](https://github.com/graphql/graphiql/commit/f3d0427)) - preserve ctrl-f key for macOS ([7c381f9](https://github.com/graphql/graphiql/commit/7c381f9)) - remove newline ([19f5d1d](https://github.com/graphql/graphiql/commit/19f5d1d)) ## 0.13.2 (2019-06-21) ## 0.13.2 (2019-06-21) ================================================ FILE: packages/graphiql/LICENSE ================================================ MIT License Copyright (c) 2021 GraphQL Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/graphiql/README.md ================================================ # GraphiQL > **Security Notice:** All versions of `graphiql` < `1.4.3` are vulnerable to an > XSS attack in cases where the GraphQL server to which the GraphiQL web app > connects is not trusted. Learn more in > [our security advisory](https://github.com/graphql/graphiql/tree/main/docs/security/2021-introspection-schema-xss.md). [![NPM](https://img.shields.io/npm/v/graphiql.svg)](https://npmjs.com/graphiql) ![jsDelivr hits (npm)](https://img.shields.io/jsdelivr/npm/hm/graphiql) ![npm downloads](https://img.shields.io/npm/dm/graphiql?label=npm%20downloads) ![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/graphiql) ![npm bundle size (version)](https://img.shields.io/bundlephobia/min/graphiql/latest) ![npm bundle size (version)](https://img.shields.io/bundlephobia/minzip/graphiql/latest) [![License](https://img.shields.io/npm/l/graphiql.svg?style=flat-square)](LICENSE) [![](https://dcbadge.vercel.app/api/server/NP5vbPeUFp?style=flat)](https://discord.gg/NP5vbPeUFp) _/ˈɡrafək(ə)l/_ A graphical interactive in-browser GraphQL IDE. [Try the live demo](https://graphql.org/swapi-graphql). [![](resources/graphiql.png)](https://graphql.org/swapi-graphql) ## Features - Full language support of the latest [GraphQL Specification](https://spec.graphql.org/draft/#sec-Language): - Syntax highlighting - Intelligent type ahead of fields, arguments, types, and more - Real-time error highlighting and reporting for queries and variables - Automatic query and variables completion - Automatic leaf node insertion for non-scalar fields - Documentation explorer with search and markdown support - Persisted state using `localStorage` - Simple API for adding custom plugins ## Live Demos - The [latest stable version](https://graphql.org/swapi-graphql) - The current state of the `main` branch: - An [installable PWA](https://graphiql-test.netlify.com/webpack) with plugins ([source](../../examples//graphiql-webpack)) - Using the [minified bundles](https://graphiql-test.netlify.com) - Using the [development bundles](https://graphiql-test.netlify.com/dev) (good for inspecting, debugging, etc) - Each pull request will also get its own preview deployment on Netlify, you'll find a link in the GitHub checks ## Examples - [`CDN (ESM-based)`](../../examples/graphiql-cdn) - A single HTML file using [JavaScript modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) from http URLs and a `
Loading…
================================================ FILE: packages/graphiql/package.json ================================================ { "name": "graphiql", "version": "5.2.2", "sideEffects": [ "dist/setup-workers/*" ], "description": "An graphical interactive in-browser GraphQL IDE.", "contributors": [ "Dimitri POSTOLOV (https://dimaMachina.com)", "Hyohyeon Jeong ", "Lee Byron (https://leebyron.com)" ], "repository": { "type": "git", "url": "https://github.com/graphql/graphiql", "directory": "packages/graphiql" }, "homepage": "https://github.com/graphql/graphiql/tree/master/packages/graphiql#readme", "bugs": { "url": "https://github.com/graphql/graphiql/issues?q=issue+label:graphiql" }, "license": "MIT", "main": "dist/index.js", "types": "dist/index.d.ts", "files": [ "dist", "!dist/e2e.*", "!dist/workers/*", "!dist/index.umd.*", "!dist/cdn.*" ], "exports": { "./package.json": "./package.json", "./style.css": "./dist/style.css", "./graphiql.css": "./dist/graphiql.css", ".": "./dist/index.js", "./setup-workers/*": { "types": "./dist/setup-workers/*.d.ts", "import": "./dist/setup-workers/*.js" } }, "scripts": { "types:check": "tsc --noEmit", "build": "vite build && UMD=true vite build", "cypress-open": "cypress open --browser electron", "dev": "concurrently 'cross-env PORT=8080 node test/e2e-server' vite", "e2e": "yarn e2e-server 'cypress run'", "e2e-server": "start-server-and-test 'cross-env PORT=8080 node test/e2e-server' 'http-get://localhost:8080/graphql?query={test { id }}'", "test": "vitest" }, "dependencies": { "@graphiql/plugin-doc-explorer": "^0.4.1", "@graphiql/plugin-history": "^0.4.1", "@graphiql/react": "^0.37.3", "react-compiler-runtime": "19.1.0-rc.1" }, "peerDependencies": { "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", "react": "^18 || ^19", "react-dom": "^18 || ^19" }, "devDependencies": { "@graphiql/toolkit": "^0.11.3", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.3.0", "@vitejs/plugin-react": "^4.4.1", "@vitest/web-worker": "3.1.4", "babel-plugin-react-compiler": "19.1.0-rc.1", "cross-env": "^7.0.2", "cypress": "^13.13.2", "graphql": "^16.11.0", "lightningcss": "^1.29.3", "react": "^19.1.0", "react-dom": "^19.1.0", "start-server-and-test": "^1.10.11", "typescript": "^4.6.3", "vite": "^6.3.4", "vite-plugin-dts": "^4.5.3", "vitest-canvas-mock": "0.3.3" }, "browser": { "//": "esm.sh polyfills `process`, we don't need it", "process": false } } ================================================ FILE: packages/graphiql/setup-files.ts ================================================ 'use no memo'; import '@testing-library/jest-dom'; import { configure } from '@testing-library/react'; // to make it works like Jest (auto-mocking) vi.mock('zustand'); vi.mock('monaco-editor'); // Since we load `monaco-editor` dynamically, we need to allow more time for tests that assert editor values configure({ asyncUtilTimeout: 9_000 }); ================================================ FILE: packages/graphiql/setup-window.ts ================================================ /** * Fixes TypeError: mainWindow.matchMedia is not a function * @see https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom */ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!window.matchMedia) { Object.defineProperty(window, 'matchMedia', { writable: false, value: vi.fn().mockImplementation(query => ({ matches: false, media: query, onchange: null, addListener: vi.fn(), // deprecated removeListener: vi.fn(), // deprecated addEventListener: vi.fn(), removeEventListener: vi.fn(), dispatchEvent: vi.fn(), })), }); } export {}; ================================================ FILE: packages/graphiql/src/GraphiQL.spec.tsx ================================================ 'use no memo'; /** * Copyright (c) 2021 GraphQL Contributors. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ import { act, render, waitFor, fireEvent } from '@testing-library/react'; import { Component, FC, useEffect } from 'react'; import { GraphiQL } from './GraphiQL'; import type { Fetcher } from '@graphiql/toolkit'; import { ToolbarButton, useGraphiQL, useOperationsEditorState, MonacoEditor, } from '@graphiql/react'; import '@graphiql/react/setup-workers/vite'; // The smallest possible introspection result that builds a schema. const simpleIntrospection = { data: { __schema: { queryType: { name: 'Q' }, types: [ { kind: 'OBJECT', name: 'Q', interfaces: [], fields: [{ name: 'q', args: [], type: { name: 'Q' } }], }, ], }, }, }; beforeEach(() => { localStorage.clear(); }); describe('GraphiQL', () => { // @ts-expect-error -- fixme const noOpFetcher: Fetcher = () => {}; describe('fetcher', () => { it('should throw error without fetcher', () => { const spy = vi.spyOn(console, 'error').mockImplementation(() => {}); // @ts-expect-error fetcher is a required prop to GraphiQL expect(() => render()).toThrow( 'The `GraphiQLProvider` component requires a `fetcher` function to be passed as prop.', ); spy.mockRestore(); }); it('should construct correctly with fetcher', () => { // `return` fix error: // Warning: An update to GraphiQLInterface inside a test was not wrapped in act(...). return act(() => { expect(() => render()).not.toThrow(); }); }); it('should refetch schema with new fetcher', async () => { let firstCalled = false; function firstFetcher() { firstCalled = true; return Promise.resolve(simpleIntrospection); } let secondCalled = false; function secondFetcher() { secondCalled = true; return Promise.resolve(simpleIntrospection); } // Initial render calls fetcher const { rerender } = render(); await waitFor(() => { expect(firstCalled).toEqual(true); }); // Re-render does not call fetcher again firstCalled = false; await act(async () => { rerender(); }); await waitFor(() => { expect(firstCalled).toEqual(false); }); // Re-render with new fetcher is called. await act(async () => { rerender(); }); await waitFor(() => { expect(secondCalled).toEqual(true); }); }); it('should refresh schema with new fetcher after a fetchError', async () => { function firstFetcher() { return Promise.reject('Schema Error'); } function secondFetcher() { return Promise.resolve(simpleIntrospection); } // Use a bad fetcher for our initial render const { rerender, container, getByLabelText } = render( , ); const showDocExplorerButton = getByLabelText( 'Show Documentation Explorer', ); await waitFor(() => { expect(showDocExplorerButton).not.toBe(null); }); act(() => { fireEvent.click(showDocExplorerButton); }); await waitFor(() => { expect( container.querySelector('.graphiql-doc-explorer-error'), ).not.toBe(null); }); // Re-render with valid fetcher await act(async () => { rerender(); }); await waitFor(() => { expect(container.querySelector('.graphiql-doc-explorer-error')).toBe( null, ); }); }); }); // fetcher describe('schema', () => { it('should not throw error if schema missing and query provided', async () => { await act(async () => { expect(() => render(), ).not.toThrow(); }); }); }); // schema describe('default query', () => { it('defaults to the built-in default query', async () => { const { container } = render(); await waitFor(() => { const queryEditor = container.querySelector( '.graphiql-editor .monaco-scrollable-element', ); expect(queryEditor).toBeVisible(); expect(queryEditor!.textContent).toBe('# Welcome to GraphiQL'); }); }); it('accepts a custom default query', async () => { const { container } = render( , ); await waitFor(() => { const queryEditor = container.querySelector( '.graphiql-editor .monaco-scrollable-element', ); expect(queryEditor).toBeVisible(); expect(queryEditor!.textContent).toBe('GraphQL Party!!'); }); }); }); // default query // TODO: rewrite these plugin tests after plugin API has more structure describe('plugins', () => { it('displays correct plugin when visiblePlugin prop is used', async () => { const { container } = render( , ); await waitFor(() => { expect( container.querySelector('.graphiql-doc-explorer'), ).toBeInTheDocument(); }); }); it('defaults to not displaying plugin pane', async () => { const { container } = render(); await waitFor(() => { expect(container.querySelector('.graphiql-plugin')).not.toBeVisible(); }); }); }); // plugins describe('editor tools', () => { it('can control the default editor tools visibility', async () => { const { container } = render(); const editorToolTabPanelWrap = container.querySelector( '.graphiql-editor-tool', ); await waitFor(() => { expect(editorToolTabPanelWrap).not.toBeVisible(); }); const secondaryEditorTitle = container.querySelector( '.graphiql-editor-tools', )!; // drag the editor tools handle up act(() => { fireEvent.mouseDown(secondaryEditorTitle); fireEvent.mouseMove(secondaryEditorTitle, { buttons: 1, clientY: 50 }); }); await waitFor(() => { expect(editorToolTabPanelWrap).toBeVisible(); }); }); it('correctly displays variables editor when using defaultEditorToolsVisibility prop', async () => { const { container } = render( , ); await waitFor(() => { expect( container.querySelector('[aria-label="Variables"]'), ).toBeVisible(); }); }); it('correctly displays request headers editor when using defaultEditorToolsVisibility prop', async () => { const { container } = render( , ); await waitFor(() => { expect(container.querySelector('[aria-label="Headers"]')).toBeVisible(); }); }); it('correctly hides editor tools when using defaultEditorToolsVisibility prop is false but either of the editors has a value', async () => { const { container } = render( , ); const editorToolTabPanelWrap = container.querySelector( '.graphiql-editor-tool', ); await waitFor(() => { expect(editorToolTabPanelWrap).not.toBeVisible(); }); }); }); // editor tools describe('panel resizing', () => { it('readjusts the query wrapper flex style field when the result panel is resized', async () => { // Mock the drag bar width const clientWidthSpy = vi .spyOn(Element.prototype, 'clientWidth', 'get') .mockReturnValue(0); // Mock the container width const boundingClientRectSpy = vi .spyOn(Element.prototype, 'getBoundingClientRect') .mockReturnValue({ left: 0, right: 900 } as DOMRect); const { container } = render(); const dragBar = container.querySelector('.graphiql-horizontal-drag-bar')!; const editors = container.querySelector('.graphiql-editors')!; act(() => { fireEvent.mouseDown(dragBar, { button: 0, ctrlKey: false, }); fireEvent.mouseMove(dragBar, { buttons: 1, clientX: 700, }); fireEvent.mouseUp(dragBar); }); await waitFor(() => { // 700 / (900 - 700) = 3.5 expect(editors.style.flex).toEqual('3.5'); }); clientWidthSpy.mockRestore(); boundingClientRectSpy.mockRestore(); }); it('allows for resizing the doc explorer correctly', async () => { // Mock the drag bar width const clientWidthSpy = vi .spyOn(Element.prototype, 'clientWidth', 'get') .mockReturnValue(0); // Mock the container width const boundingClientRectSpy = vi .spyOn(Element.prototype, 'getBoundingClientRect') .mockReturnValue({ left: 0, right: 1200 } as DOMRect); const { container } = render(); act(() => { fireEvent.click( container.querySelector( '[aria-label="Show Documentation Explorer"]', )!, ); }); const dragBar = container.querySelector('.graphiql-horizontal-drag-bar')!; act(() => { fireEvent.mouseDown(dragBar, { clientX: 3, }); fireEvent.mouseMove(dragBar, { buttons: 1, clientX: 800, }); fireEvent.mouseUp(dragBar); }); await waitFor(() => { // 797 / (1200 - 797) = 1.977667493796526 expect( container.querySelector('.graphiql-plugin')!.style .flex, ).toBe('1.977667493796526'); }); clientWidthSpy.mockRestore(); boundingClientRectSpy.mockRestore(); }); }); // panel resizing it('allows the user to control persisting headers if it is true', async () => { const { container, findByText } = render( , ); act(() => { fireEvent.click( container.querySelector('[aria-label="Open settings dialog"]')!, ); }); const element = await findByText('Persist headers'); expect(element).toBeInTheDocument(); }); it('allows the user to control persisting headers if it is not passed in', async () => { const { container, findByText } = render( , ); act(() => { fireEvent.click( container.querySelector('[aria-label="Open settings dialog"]')!, ); }); const element = await findByText('Persist headers'); expect(element).toBeInTheDocument(); }); it('does not allow the user to control persisting headers is false', async () => { const { container, findByText } = render( , ); act(() => { fireEvent.click( container.querySelector('[aria-label="Open settings dialog"]')!, ); }); const callback = async () => { try { await findByText('Persist headers'); } catch { // eslint-disable-next-line no-throw-literal throw 'failed'; } }; await expect(callback).rejects.toEqual('failed'); }); describe('Tabs', () => { it('show tabs', async () => { const { container } = render(); await waitFor(() => { expect( container.querySelectorAll('.graphiql-tabs .graphiql-tab'), ).toHaveLength(1); }); act(() => { fireEvent.click(container.querySelector('.graphiql-tab-add')!); }); await waitFor(() => { expect( container.querySelectorAll('.graphiql-tabs .graphiql-tab'), ).toHaveLength(2); }); act(() => { fireEvent.click(container.querySelector('.graphiql-tab-add')!); }); await waitFor(() => { expect( container.querySelectorAll('.graphiql-tabs .graphiql-tab'), ).toHaveLength(3); }); }); it('each tab has a close button when multiple tabs are open', async () => { const { container } = render(); await waitFor(() => { expect( container.querySelectorAll('.graphiql-tab .graphiql-tab-close'), ).toHaveLength(0); }); act(() => { fireEvent.click(container.querySelector('.graphiql-tab-add')!); }); await waitFor(() => { expect( container.querySelectorAll('.graphiql-tab .graphiql-tab-close'), ).toHaveLength(2); }); act(() => { fireEvent.click(container.querySelector('.graphiql-tab-add')!); }); await waitFor(() => { expect( container.querySelectorAll('.graphiql-tab .graphiql-tab-close'), ).toHaveLength(3); }); }); it('close button removes a tab', async () => { const { container } = render(); act(() => { fireEvent.click(container.querySelector('.graphiql-tab-add')!); }); await waitFor(() => { expect( container.querySelectorAll('.graphiql-tab .graphiql-tab-close'), ).toHaveLength(2); }); act(() => { fireEvent.click( container.querySelector('.graphiql-tab .graphiql-tab-close')!, ); }); await waitFor(() => { expect( container.querySelectorAll('.graphiql-tabs .graphiql-tab'), ).toHaveLength(1); expect( container.querySelectorAll('.graphiql-tab .graphiql-tab-close'), ).toHaveLength(0); }); }); it('shows default tabs', async () => { const { container } = render( , ); await waitFor(() => { expect( container.querySelectorAll('.graphiql-tabs .graphiql-tab'), ).toHaveLength(2); }); }); }); describe('children overrides', () => { const MyFunctionalComponent = () => { return null; }; it('properly ignores fragments', async () => { const myFragment = ( <> ); const { container, getByRole } = render( {myFragment}, ); await waitFor(() => { expect( container.querySelector('.graphiql-container'), ).toBeInTheDocument(); expect(container.querySelector('.graphiql-logo')).toBeInTheDocument(); expect(getByRole('toolbar')).toBeInTheDocument(); }); }); it('properly ignores non-override children components', async () => { const { container, getByRole } = render( , ); await waitFor(() => { expect( container.querySelector('.graphiql-container'), ).toBeInTheDocument(); expect(container.querySelector('.graphiql-logo')).toBeInTheDocument(); expect(getByRole('toolbar')).toBeInTheDocument(); }); }); it('properly ignores non-override class components', async () => { // eslint-disable-next-line react/prefer-stateless-function class MyClassComponent extends Component { render() { return null; } } const { container, getByRole } = render( , ); await waitFor(() => { expect( container.querySelector('.graphiql-container'), ).toBeInTheDocument(); expect(container.querySelector('.graphiql-logo')).toBeInTheDocument(); expect(getByRole('toolbar')).toBeInTheDocument(); }); }); describe('GraphiQL.Logo', () => { it('can be overridden using the exported type', async () => { const { getByText } = render( My Exported Type Logo , ); await waitFor(() => { expect(getByText('My Exported Type Logo')).toBeInTheDocument(); }); }); }); describe('GraphiQL.Toolbar', () => { it('can be overridden using the exported type', async () => { const { container } = render( {() => } , ); await waitFor(() => { expect( container.querySelectorAll( '[role="toolbar"] .graphiql-toolbar-button', ), ).toHaveLength(1); }); }); }); describe('GraphiQL.Footer', () => { it('can be overridden using the exported type', async () => { const { container } = render( , ); await waitFor(() => { expect( container.querySelectorAll('.graphiql-footer button'), ).toHaveLength(1); }); }); }); }); it('should support multiple instances', async () => { const queryEditors: Record<0 | 1, MonacoEditor> = Object.create(null); const HookConsumer: FC<{ id: 0 | 1 }> = ({ id }) => { const $queryEditor = useGraphiQL(state => state.queryEditor); useEffect(() => { queryEditors[id] = $queryEditor!; }, [$queryEditor, id]); return null; }; const { container, getAllByLabelText } = render( <> , ); const [firstEl, secondEl] = container.querySelectorAll( '.graphiql-container', ); expect(firstEl).toBeInTheDocument(); expect(secondEl).toBeInTheDocument(); const [showDocExplorerButton] = getAllByLabelText( 'Show Documentation Explorer', ); const [addTab] = getAllByLabelText('New tab'); fireEvent.click(showDocExplorerButton!); fireEvent.click(addTab!); await waitFor(() => { // Plugin store expect( firstEl!.querySelector('.graphiql-doc-explorer'), ).toBeInTheDocument(); expect( secondEl!.querySelector('.graphiql-doc-explorer'), ).not.toBeInTheDocument(); // Editor store expect(firstEl!.querySelectorAll('.graphiql-tab').length).toBe(2); expect(secondEl!.querySelectorAll('.graphiql-tab').length).toBe(1); // Query queryEditors[0].setValue('{__typename}'); queryEditors[1].setValue('bar'); const editors = container.querySelectorAll( '.graphiql-query-editor .monaco-scrollable-element', ); expect(editors[0]!.textContent).toBe('{__typename}'); expect(editors[1]!.textContent).toBe('bar'); }); }); it('`useOperationsEditorState` hook', async () => { let hookResult: ReturnType; let queryEditor: MonacoEditor; const HookConsumer: FC = () => { const $hookResult = useOperationsEditorState(); const $queryEditor = useGraphiQL(state => state.queryEditor); useEffect(() => { hookResult = $hookResult; queryEditor = $queryEditor!; }, [$hookResult, $queryEditor]); return null; }; const { container } = render( , ); let editor: HTMLDivElement = null!; // Assert initial values await waitFor(() => { editor = container.querySelector( '.graphiql-editor .monaco-scrollable-element', )!; expect(editor.textContent).toBe('query { hello }'); expect(hookResult[0]).toBe('query { hello }'); }); // Assert value was changed after UI editing await waitFor(() => { const newValue = 'bar'; queryEditor.setValue(newValue); expect(editor.textContent).toBe(newValue); expect(hookResult[0]).toBe(newValue); }); // Assert using hook handler await waitFor(() => { const newValue = 'foo'; hookResult[1](newValue); expect(editor.textContent).toBe(newValue); expect(hookResult[0]).toBe(newValue); }); }); }); ================================================ FILE: packages/graphiql/src/GraphiQL.tsx ================================================ /** * Copyright (c) 2020 GraphQL Contributors. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ import type { MouseEventHandler, ReactNode, FC, ComponentPropsWithoutRef, } from 'react'; import { useState, Children, useRef, Fragment } from 'react'; import { ChevronDownIcon, ChevronUpIcon, ExecuteButton, GraphiQLProvider, HeaderEditor, PlusIcon, QueryEditor, ResponseEditor, Spinner, Tab, Tabs, Tooltip, UnStyledButton, useDragResize, useGraphiQL, pick, VariableEditor, EditorProps, cn, useGraphiQLActions, useMonaco, } from '@graphiql/react'; import { HistoryStore, HISTORY_PLUGIN } from '@graphiql/plugin-history'; import { DocExplorerStore, DOC_EXPLORER_PLUGIN, } from '@graphiql/plugin-doc-explorer'; import { GraphiQLLogo, GraphiQLToolbar, GraphiQLFooter, Sidebar } from './ui'; /** * API docs for this live here: * * https://graphiql-test.netlify.app/typedoc/modules/graphiql.html#graphiqlprops */ export interface GraphiQLProps // `children` prop should be optional extends GraphiQLInterfaceProps, Omit, 'children'>, Omit, 'children'> {} /** * The top-level React component for GraphiQL, intended to encompass the entire * browser viewport. * * @see https://github.com/graphql/graphiql#usage */ const GraphiQL_: FC = ({ maxHistoryLength, plugins = [HISTORY_PLUGIN], referencePlugin = DOC_EXPLORER_PLUGIN, onEditQuery, onEditVariables, onEditHeaders, responseTooltip, defaultEditorToolsVisibility, isHeadersEditorEnabled, showPersistHeadersSettings, forcedTheme, confirmCloseTab, className, children, ...props }) => { // @ts-expect-error -- Prop is removed if (props.toolbar?.additionalContent) { throw new TypeError( 'The `toolbar.additionalContent` prop has been removed. Use render props on `GraphiQL.Toolbar` component instead.', ); } // @ts-expect-error -- Prop is removed if (props.toolbar?.additionalComponent) { throw new TypeError( 'The `toolbar.additionalComponent` prop has been removed. Use render props on `GraphiQL.Toolbar` component instead.', ); } // @ts-expect-error -- Prop is removed if (props.keyMap) { throw new TypeError( '`keyMap` was removed. To use Vim or Emacs keybindings in Monaco, you can use community plugins. Monaco Vim: https://github.com/brijeshb42/monaco-vim. Monaco Emacs: https://github.com/aioutecism/monaco-emacs', ); } // @ts-expect-error -- Prop is removed if (props.readOnly) { throw new TypeError('The `readOnly` prop has been removed.'); } const interfaceProps: GraphiQLInterfaceProps = { // TODO check if `showPersistHeadersSettings` prop is needed, or we can just use `shouldPersistHeaders` instead showPersistHeadersSettings: showPersistHeadersSettings ?? props.shouldPersistHeaders !== false, onEditQuery, onEditVariables, onEditHeaders, responseTooltip, defaultEditorToolsVisibility, isHeadersEditorEnabled, forcedTheme, confirmCloseTab, className, }; const hasHistoryPlugin = plugins.includes(HISTORY_PLUGIN); const HistoryToUse = hasHistoryPlugin ? HistoryStore : Fragment; const DocExplorerToUse = referencePlugin === DOC_EXPLORER_PLUGIN ? DocExplorerStore : Fragment; return ( {children} ); }; type AddSuffix, Suffix extends string> = { [Key in keyof Obj as `${string & Key}${Suffix}`]: Obj[Key]; }; type QueryEditorProps = ComponentPropsWithoutRef; type VariableEditorProps = ComponentPropsWithoutRef; type HeaderEditorProps = ComponentPropsWithoutRef; type ResponseEditorProps = ComponentPropsWithoutRef; export interface GraphiQLInterfaceProps extends EditorProps, AddSuffix, 'Query'>, AddSuffix, 'Variables'>, AddSuffix, 'Headers'>, Pick, Pick< ComponentPropsWithoutRef, 'forcedTheme' | 'showPersistHeadersSettings' > { children?: ReactNode; /** * Set the default state for the editor tools. * - `false` hides the editor tools * - `true` shows the editor tools * - `'variables'` specifically shows the variables editor * - `'headers'` specifically shows the request headers editor * By default, the editor tools are initially shown when at least one of the * editors has contents. */ defaultEditorToolsVisibility?: boolean | 'variables' | 'headers'; /** * Toggle if the headers' editor should be shown inside the editor tools. * @default true */ isHeadersEditorEnabled?: boolean; /** * Additional class names which will be appended to the container element. */ className?: string; /** * When the user clicks a close tab button, this function is invoked with * the index of the tab that is about to be closed. It can return a promise * that should resolve to `true` (meaning the tab may be closed) or `false` * (meaning the tab may not be closed). * @param index - The index of the tab that should be closed. */ confirmCloseTab?(index: number): Promise | boolean; } const TAB_CLASS_PREFIX = 'graphiql-session-tab-'; type ButtonHandler = MouseEventHandler; const LABEL = { newTab: 'New tab', }; export const GraphiQLInterface: FC = ({ forcedTheme, isHeadersEditorEnabled = true, defaultEditorToolsVisibility, children: $children, confirmCloseTab, className, onEditQuery, onEditVariables, onEditHeaders, responseTooltip, showPersistHeadersSettings, }) => { const { addTab, moveTab, closeTab, changeTab, setVisiblePlugin } = useGraphiQLActions(); const { initialVariables, initialHeaders, tabs, activeTabIndex, isFetching, visiblePlugin, } = useGraphiQL( pick( 'initialVariables', 'initialHeaders', 'tabs', 'activeTabIndex', 'isFetching', 'visiblePlugin', ), ); const hasMonaco = useMonaco(state => Boolean(state.monaco)); const PluginContent = visiblePlugin?.content; const pluginResize = useDragResize({ defaultSizeRelation: 1 / 3, direction: 'horizontal', initiallyHidden: visiblePlugin ? undefined : 'first', onHiddenElementChange(resizableElement) { if (resizableElement === 'first') { setVisiblePlugin(null); } }, sizeThresholdSecond: 200, storageKey: 'docExplorerFlex', }); const editorResize = useDragResize({ direction: 'horizontal', storageKey: 'editorFlex', }); const editorToolsResize = useDragResize({ defaultSizeRelation: 3, direction: 'vertical', initiallyHidden: ((d: typeof defaultEditorToolsVisibility) => { if (d === 'variables' || d === 'headers') { return; } if (typeof d === 'boolean') { return d ? undefined : 'second'; } return initialVariables || initialHeaders ? undefined : 'second'; })(defaultEditorToolsVisibility), sizeThresholdSecond: 60, storageKey: 'secondaryEditorFlex', }); const [activeSecondaryEditor, setActiveSecondaryEditor] = useState< 'variables' | 'headers' >(() => { if ( defaultEditorToolsVisibility === 'variables' || defaultEditorToolsVisibility === 'headers' ) { return defaultEditorToolsVisibility; } return !initialVariables && initialHeaders && isHeadersEditorEnabled ? 'headers' : 'variables'; }); const { logo, toolbar, footer, children } = Children.toArray( $children, ).reduce<{ logo?: ReactNode; toolbar?: ReactNode; footer?: ReactNode; children: ReactNode[]; }>( (acc, curr) => { switch (getChildComponentType(curr)) { case GraphiQL.Logo: acc.logo = curr; break; case GraphiQL.Toolbar: acc.toolbar = curr; break; case GraphiQL.Footer: acc.footer = curr; break; default: acc.children.push(curr); } return acc; }, { logo: , toolbar: , children: [], }, ); function onClickReference() { if (pluginResize.hiddenElement === 'first') { pluginResize.setHiddenElement(null); } } const handleToolsTabClick: ButtonHandler = event => { if (editorToolsResize.hiddenElement === 'second') { editorToolsResize.setHiddenElement(null); } const tabName = event.currentTarget.dataset.name as 'variables' | 'headers'; setActiveSecondaryEditor(tabName); }; const toggleEditorTools: ButtonHandler = () => { editorToolsResize.setHiddenElement( editorToolsResize.hiddenElement === 'second' ? null : 'second', ); }; const handleTabClose: ButtonHandler = async event => { const tabButton = event.currentTarget.previousSibling as HTMLButtonElement; const index = Number(tabButton.id.replace(TAB_CLASS_PREFIX, '')); const shouldCloseTab = confirmCloseTab ? await confirmCloseTab(index) : true; if (!shouldCloseTab) { return; } closeTab(index); }; const handleTabClick: ButtonHandler = event => { const index = Number(event.currentTarget.id.replace(TAB_CLASS_PREFIX, '')); changeTab(index); }; const editorToolsText = `${editorToolsResize.hiddenElement === 'second' ? 'Show' : 'Hide'} editor tools`; const EditorToolsIcon = editorToolsResize.hiddenElement === 'second' ? ChevronUpIcon : ChevronDownIcon; const editors = (
{hasMonaco ? ( ) : ( )}
{toolbar}
Variables {isHeadersEditorEnabled && ( Headers )}
{isHeadersEditorEnabled && ( )}
); const tabContainerRef = useRef(null!); return (
{PluginContent && }
{visiblePlugin && (
)}
{tabs.map((tab, index, arr) => ( {tab.title} {arr.length > 1 && } ))} {logo}
{editors}
{isFetching && } {footer}
{children} ); }; function getChildComponentType(child: ReactNode) { if ( child && typeof child === 'object' && 'type' in child && typeof child.type === 'function' ) { return child.type; } } // Export main windows/panes to be used separately if desired. export const GraphiQL = Object.assign(GraphiQL_, { Logo: GraphiQLLogo, Toolbar: GraphiQLToolbar, Footer: GraphiQLFooter, }); ================================================ FILE: packages/graphiql/src/cdn.ts ================================================ /** * Copyright (c) 2025 GraphQL Contributors. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ import { version } from 'react'; import * as GraphiQLReact from '@graphiql/react'; import { createGraphiQLFetcher, createLocalStorage } from '@graphiql/toolkit'; import * as GraphQL from 'graphql'; import { GraphiQL } from './GraphiQL'; import './setup-workers/vite'; const majorVersion = parseInt(version.slice(0, 2), 10); if (majorVersion < 16) { throw new Error( [ 'GraphiQL 0.18.0 and after is not compatible with React 15 or below.', 'If you are using a CDN source (jsdelivr, unpkg, etc), follow this example:', 'https://github.com/graphql/graphiql/blob/master/examples/graphiql-cdn/index.html#L49', ].join('\n'), ); } /** * For the CDN bundle we add some static properties to the component function * so that they can be accessed in the inline-script in the HTML file. */ export default Object.assign(GraphiQL, { /** * This function is needed in order to easily create a fetcher function. */ createFetcher: createGraphiQLFetcher, /** * This function is needed in order to easily generate a custom storage namespace */ createLocalStorage, /** * We also add the complete `graphiql-js` exports so that this instance of * `graphiql-js` can be reused from plugin CDN bundles. */ GraphQL, /** * We also add the complete `@graphiql/react` exports. These will be included * in the bundle anyway since they make up the `GraphiQL` component, so by * doing this we can reuse them from plugin CDN bundles. */ React: GraphiQLReact, }); ================================================ FILE: packages/graphiql/src/e2e.ts ================================================ 'use no memo'; import React, { ComponentProps } from 'react'; import ReactDOM from 'react-dom/client'; import GraphiQL from './cdn'; import type { TabsState, Theme } from '@graphiql/react'; import './style.css'; /** * CDN GraphiQL Example * * This is a simple example that provides a primitive query string parser on top of GraphiQL props * It assumes a global umd GraphiQL, which would be provided by an index.html in the default example * * It is used by: * - the netlify demo * - end-to-end tests * - vite dev server */ interface Params { query?: string; variables?: string; headers?: string; defaultQuery?: string; defaultHeaders?: string; confirmCloseTab?: 'true'; onPrettifyQuery?: 'true'; forcedTheme?: 'light' | 'dark' | 'system'; defaultTheme?: Theme; } // Parse the search string to get url parameters. 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: string): void { parameters.query = newQuery; updateURL(); } function onEditVariables(newVariables: string): void { parameters.variables = newVariables; updateURL(); } function onEditHeaders(newHeaders: string): void { parameters.headers = newHeaders; updateURL(); } function onTabChange(tabsState: TabsState): void { const activeTab = tabsState.tabs[tabsState.activeTabIndex]!; parameters.query = activeTab.query ?? undefined; parameters.variables = activeTab.variables ?? undefined; parameters.headers = activeTab.headers ?? undefined; updateURL(); } 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 onPrettifyQuery(query: string): string { return query.replaceAll(/([ \n])+/g, ' '); } function updateURL(): void { const newSearch = Object.entries(parameters) .filter(([_key, value]) => value) .map( ([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value), ) .join('&'); history.replaceState(null, '', `?${newSearch}`); } function getSchemaUrl(): string { const isDev = /localhost$/.test(location.hostname); if (isDev) { return '/graphql'; } return '/.netlify/functions/graphql'; } // Render into the body. // See the README in the top level of this module to learn more about // how you can customize GraphiQL by providing different values or // additional child elements. const root = ReactDOM.createRoot(document.getElementById('graphiql')!); const graphqlVersion = GraphiQL.GraphQL.version; const props: ComponentProps = { fetcher: GraphiQL.createFetcher({ url: getSchemaUrl(), subscriptionUrl: 'ws://localhost:8081/subscriptions', }), initialQuery: parameters.query, initialVariables: parameters.variables, initialHeaders: parameters.headers, defaultQuery: parameters.defaultQuery, defaultHeaders: parameters.defaultHeaders, onEditQuery, onEditVariables, onEditHeaders, defaultEditorToolsVisibility: true, isHeadersEditorEnabled: true, shouldPersistHeaders: true, inputValueDeprecation: !graphqlVersion.includes('15.5'), confirmCloseTab: parameters.confirmCloseTab === 'true' ? confirmCloseTab : undefined, onPrettifyQuery: parameters.onPrettifyQuery === 'true' ? onPrettifyQuery : undefined, onTabChange, forcedTheme: parameters.forcedTheme, defaultTheme: parameters.defaultTheme, }; function App() { return React.createElement( React.StrictMode, null, React.createElement(GraphiQL, props), ); } root.render(React.createElement(App)); ================================================ FILE: packages/graphiql/src/graphiql.css ================================================ /* Everything */ .graphiql-container { background-color: hsl(var(--color-base)); display: flex; height: 100%; margin: 0; overflow: hidden; width: 100%; } /* The sidebar */ .graphiql-container .graphiql-sidebar { display: flex; flex-direction: column; padding: var(--px-8); width: var(--sidebar-width); gap: var(--px-8); overflow-y: auto; } .graphiql-container .graphiql-sidebar > button { display: flex; align-items: center; justify-content: center; color: hsla(var(--color-neutral), var(--alpha-secondary)); height: calc(var(--sidebar-width) - (2 * var(--px-8))); width: calc(var(--sidebar-width) - (2 * var(--px-8))); flex-shrink: 0; } .graphiql-container .graphiql-sidebar button.active { color: hsl(var(--color-neutral)); } .graphiql-container .graphiql-sidebar button > svg { height: var(--px-20); width: var(--px-20); } /* The main content, i.e. everything except the sidebar */ .graphiql-container .graphiql-main { display: flex; flex: 1; min-width: 0; } /* The current session and tabs */ .graphiql-container .graphiql-sessions { background-color: hsla(var(--color-neutral), var(--alpha-background-light)); /* Adding the 8px of padding to the inner border radius of the operation editor */ border-radius: calc(var(--border-radius-12) + var(--px-8)); display: flex; flex-direction: column; flex: 1; max-height: 100%; margin: var(--px-16); margin-left: 0; min-width: 0; } /* The session header containing tabs and the logo */ .graphiql-container .graphiql-session-header { height: var(--session-header-height); align-items: center; display: flex; padding: var(--px-8) var(--px-8) 0; gap: var(--px-8); } /* The button to add a new tab */ button.graphiql-tab-add { padding: var(--px-4); & > svg { color: hsla(var(--color-neutral), var(--alpha-secondary)); display: block; height: var(--px-16); width: var(--px-16); } } /* The GraphiQL logo */ .graphiql-container .graphiql-logo { margin-left: auto; color: hsla(var(--color-neutral), var(--alpha-secondary)); font-size: var(--font-size-h4); font-weight: var(--font-weight-medium); } /* Undo default link styling for the default GraphiQL logo link */ .graphiql-container .graphiql-logo .graphiql-logo-link { color: hsla(var(--color-neutral), var(--alpha-secondary)); text-decoration: none; &:focus { outline: hsla(var(--color-neutral), var(--alpha-background-heavy)) auto 1px; } } /* The editor of the session */ .graphiql-container #graphiql-session { display: flex; flex: 1; padding: 0 var(--px-8) var(--px-8); } /* All editors (operation, variable, request headers) */ .graphiql-container .graphiql-editors { background-color: hsl(var(--color-base)); border-radius: 0 0 var(--border-radius-12) var(--border-radius-12); box-shadow: var(--popover-box-shadow); display: flex; flex: 1; flex-direction: column; } /* The operation editor and the toolbar */ .graphiql-container .graphiql-query-editor { border-bottom: 1px solid hsla(var(--color-neutral), var(--alpha-background-heavy)); padding: var(--px-16); column-gap: var(--px-16); display: flex; width: 100%; } /* The vertical toolbar next to the operation editor */ .graphiql-container .graphiql-toolbar { width: var(--toolbar-width); display: flex; flex-direction: column; gap: var(--px-8); } .graphiql-container .graphiql-toolbar > button { flex-shrink: 0; } /* The toolbar icons */ .graphiql-toolbar-icon { color: hsla(var(--color-neutral), var(--alpha-tertiary)); display: block; height: calc(var(--toolbar-width) - (var(--px-8) * 2)); width: calc(var(--toolbar-width) - (var(--px-8) * 2)); } /* The tab bar for editor tools */ .graphiql-container .graphiql-editor-tools { cursor: row-resize; display: flex; width: 100%; column-gap: var(--px-8); padding: var(--px-8); } .graphiql-container .graphiql-editor-tools button { color: hsla(var(--color-neutral), var(--alpha-secondary)); } .graphiql-container .graphiql-editor-tools button.active { color: hsl(var(--color-neutral)); } /* The tab buttons to switch between editor tools */ .graphiql-container .graphiql-editor-tools > button:not(.graphiql-toggle-editor-tools) { padding: var(--px-8) var(--px-12); } .graphiql-container .graphiql-editor-tools .graphiql-toggle-editor-tools { margin-left: auto; } /* An editor tool, e.g. variables or request headers editor */ .graphiql-container .graphiql-editor-tool { flex: 1; padding: var(--px-16); } /** * The way CodeMirror editors are styled they overflow their containing * element. For some OS-browser-combinations this might cause overlap issues, * setting the position of this to `relative` makes sure this element will * always be on top of any editors. */ .graphiql-container .graphiql-toolbar, .graphiql-container .graphiql-editor-tools, .graphiql-container .graphiql-editor-tool { position: relative; } /* The response view */ .graphiql-container .graphiql-response { /* Add some padding so it doesn’t touch the tabs */ padding-top: var(--px-16); display: flex; width: 100%; flex-direction: column; } /* The results editor wrapping container */ .graphiql-container .graphiql-response .result-window { position: relative; flex: 1; } /* The footer below the response view */ .graphiql-container .graphiql-footer { border-top: 1px solid hsla(var(--color-neutral), var(--alpha-background-heavy)); } /* The plugin container */ .graphiql-container .graphiql-plugin { border-left: 1px solid hsla(var(--color-neutral), var(--alpha-background-heavy)); flex: 1; overflow-y: auto; padding: var(--px-16); } /* Generic drag bar for horizontal resizing */ .graphiql-horizontal-drag-bar { width: var(--px-12); cursor: col-resize; } .graphiql-horizontal-drag-bar:hover::after { border: var(--px-2) solid hsla(var(--color-neutral), var(--alpha-background-heavy)); border-radius: var(--border-radius-2); content: ''; display: block; height: 25%; margin: 0 auto; position: relative; /* (100% - 25%) / 2 = 37.5% */ top: 37.5%; width: 0; } .graphiql-container .graphiql-chevron-icon { color: hsla(var(--color-neutral), var(--alpha-tertiary)); display: block; height: var(--px-12); margin: var(--px-12); width: var(--px-12); } /* Generic spin animation */ .graphiql-spin { animation: spin 0.8s linear 0s infinite; } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } /* The header of the settings dialog */ .graphiql-dialog .graphiql-dialog-header { align-items: center; display: flex; justify-content: space-between; padding: var(--px-24); } /* The title of the settings dialog */ .graphiql-dialog .graphiql-dialog-title { font-size: var(--font-size-h3); font-weight: var(--font-weight-medium); margin: 0; } /* A section inside the settings dialog */ .graphiql-dialog .graphiql-dialog-section { align-items: center; border-top: 1px solid hsla(var(--color-neutral), var(--alpha-background-heavy)); display: flex; justify-content: space-between; padding: var(--px-24); } .graphiql-dialog .graphiql-dialog-section > :not(:first-child) { margin-left: var(--px-24); } /* The section title in the settings dialog */ .graphiql-dialog .graphiql-dialog-section-title { font-size: var(--font-size-h4); font-weight: var(--font-weight-medium); } /* The section caption in the settings dialog */ .graphiql-dialog .graphiql-dialog-section-caption { color: hsla(var(--color-neutral), var(--alpha-secondary)); } .graphiql-dialog .graphiql-warning-text { color: hsl(var(--color-warning)); font-weight: var(--font-weight-medium); } .graphiql-dialog .graphiql-table { border-collapse: collapse; width: 100%; } .graphiql-dialog .graphiql-table :is(th, td) { border: 1px solid hsla(var(--color-neutral), var(--alpha-background-heavy)); padding: var(--px-8) var(--px-12); } /* A single key the short-key dialog */ .graphiql-dialog .graphiql-key { background-color: hsla(var(--color-neutral), var(--alpha-background-medium)); border-radius: var(--border-radius-4); padding: var(--px-4); } /* Avoid showing native tooltips for icons with titles */ .graphiql-container svg { pointer-events: none; } ================================================ FILE: packages/graphiql/src/index.ts ================================================ 'use no memo'; /** * Copyright (c) 2025 GraphQL Contributors. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ import './graphiql.css'; import './style.css'; export { GraphiQL, // https://github.com/graphql/graphiql/issues/4057 GraphiQLInterface, type GraphiQLProps, type GraphiQLInterfaceProps, } from './GraphiQL'; export { HISTORY_PLUGIN } from '@graphiql/plugin-history'; ================================================ FILE: packages/graphiql/src/setup-workers/esm.sh.ts ================================================ import '@graphiql/react/setup-workers/esm.sh'; ================================================ FILE: packages/graphiql/src/setup-workers/vite.ts ================================================ import '@graphiql/react/setup-workers/vite'; ================================================ FILE: packages/graphiql/src/setup-workers/webpack.ts ================================================ import '@graphiql/react/setup-workers/webpack'; ================================================ FILE: packages/graphiql/src/style.css ================================================ /* Monaco import is only needed for CDN bundle */ @import 'monaco-editor/min/vs/editor/editor.main.css'; @import '@graphiql/react/font/roboto.css'; @import '@graphiql/react/font/fira-code.css'; @import '@graphiql/react/style.css'; @import '@graphiql/plugin-history/style.css'; @import '@graphiql/plugin-doc-explorer/style.css'; /** * Separate CSS without importing fonts/etc * * @see https://github.com/graphql/graphiql/issues/4058 */ @import './graphiql.css'; ================================================ FILE: packages/graphiql/src/ui/footer.tsx ================================================ import type { FC, ReactNode } from 'react'; // Configure the UI by providing this Component as a child of GraphiQL. export const GraphiQLFooter: FC<{ children: ReactNode }> = ({ children }) => { return
{children}
; }; ================================================ FILE: packages/graphiql/src/ui/index.ts ================================================ export { GraphiQLFooter } from './footer'; export { GraphiQLLogo } from './logo'; export { ShortKeys } from './short-keys'; export { Sidebar } from './sidebar'; export { GraphiQLToolbar } from './toolbar'; ================================================ FILE: packages/graphiql/src/ui/logo.tsx ================================================ import type { FC, ReactNode } from 'react'; const defaultGraphiqlLogo = ( Graph i QL ); // Configure the UI by providing this Component as a child of GraphiQL. export const GraphiQLLogo: FC<{ children?: ReactNode }> = ({ children = defaultGraphiqlLogo, }) => { return
{children}
; }; ================================================ FILE: packages/graphiql/src/ui/short-keys.tsx ================================================ import { FC, Fragment } from 'react'; import { formatShortcutForOS, KEY_MAP } from '@graphiql/react'; const SHORT_KEYS = Object.entries({ 'Execute query': formatShortcutForOS(KEY_MAP.runQuery.key), 'Open the Command Palette (you must have focus in the editor)': 'F1', 'Prettify editors': KEY_MAP.prettify.key, 'Copy query': KEY_MAP.copyQuery.key, 'Re-fetch schema using introspection': KEY_MAP.refetchSchema.key, 'Search in documentation': formatShortcutForOS(KEY_MAP.searchInDocs.key), 'Search in editor': formatShortcutForOS(KEY_MAP.searchInEditor.key), 'Merge fragments definitions into operation definition': KEY_MAP.mergeFragments.key, }); export const ShortKeys: FC = () => { return (
{SHORT_KEYS.map(([title, keys]) => ( ))}
Short Key Function
{keys.split('-').map((key, index, array) => ( {key} {index !== array.length - 1 && ' + '} ))} {title}

This GraphiQL editor uses{' '} Monaco editor shortcuts , with keybindings similar to VS Code. See the full list of shortcuts for{' '} macOS {' '} or{' '} Windows .

); }; ================================================ FILE: packages/graphiql/src/ui/sidebar.tsx ================================================ import { FC, type MouseEventHandler, useEffect, useState } from 'react'; import { Button, ButtonGroup, cn, Dialog, isMacOs, KEY_MAP, KeyboardShortcutIcon, pick, ReloadIcon, SettingsIcon, Tooltip, UnStyledButton, useDragResize, useGraphiQL, useGraphiQLActions, VisuallyHidden, } from '@graphiql/react'; import { ShortKeys } from './short-keys'; type ButtonHandler = MouseEventHandler; const LABEL = { refetchSchema: `Re-fetch GraphQL schema (${KEY_MAP.refetchSchema.key})`, shortCutDialog: 'Open short keys dialog', settingsDialogs: 'Open settings dialog', }; const THEMES = ['light', 'dark', 'system'] as const; interface SidebarProps { /** * `forcedTheme` allows enforcement of a specific theme for GraphiQL. * This is useful when you want to make sure that GraphiQL is always * rendered with a specific theme. */ forcedTheme?: (typeof THEMES)[number]; /** * Indicates if settings for persisting headers should appear in the * settings modal. */ showPersistHeadersSettings?: boolean; setHiddenElement: ReturnType['setHiddenElement']; } export const Sidebar: FC = ({ forcedTheme: $forcedTheme, showPersistHeadersSettings, setHiddenElement, }) => { const forcedTheme = $forcedTheme && THEMES.includes($forcedTheme) ? $forcedTheme : undefined; const { setShouldPersistHeaders, introspect, setVisiblePlugin, setTheme } = useGraphiQLActions(); const { shouldPersistHeaders, isIntrospecting, visiblePlugin, plugins, theme, storage, } = useGraphiQL( pick( 'shouldPersistHeaders', 'isIntrospecting', 'visiblePlugin', 'plugins', 'theme', 'storage', ), ); useEffect(() => { if (forcedTheme === 'system') { setTheme(null); } else if (forcedTheme === 'light' || forcedTheme === 'dark') { setTheme(forcedTheme); } }, [forcedTheme, setTheme]); const [showDialog, setShowDialog] = useState< 'settings' | 'short-keys' | null >(null); const [clearStorageStatus, setClearStorageStatus] = useState< 'success' | 'error' | undefined >(); useEffect(() => { function openSettings(event: KeyboardEvent) { if ((isMacOs ? event.metaKey : event.ctrlKey) && event.key === ',') { event.preventDefault(); // prevent default browser settings dialog setShowDialog(prev => (prev === 'settings' ? null : 'settings')); } } window.addEventListener('keydown', openSettings); return () => { window.removeEventListener('keydown', openSettings); }; }, []); function handleOpenShortKeysDialog(isOpen: boolean) { if (!isOpen) { setShowDialog(null); } } function handleOpenSettingsDialog(isOpen: boolean) { if (!isOpen) { setShowDialog(null); setClearStorageStatus(undefined); } } function handleClearData() { try { storage.clear(); setClearStorageStatus('success'); } catch { setClearStorageStatus('error'); } } const handlePersistHeaders: ButtonHandler = event => { setShouldPersistHeaders(event.currentTarget.dataset.value === 'true'); }; const handleChangeTheme: ButtonHandler = event => { const selectedTheme = event.currentTarget.dataset.theme as | 'light' | 'dark' | undefined; setTheme(selectedTheme || null); }; const handleShowDialog: ButtonHandler = event => { setShowDialog( event.currentTarget.dataset.value as 'short-keys' | 'settings', ); }; const handlePluginClick: ButtonHandler = event => { const pluginIndex = Number(event.currentTarget.dataset.index!); const plugin = plugins.find((_, index) => pluginIndex === index)!; const isVisible = plugin === visiblePlugin; if (isVisible) { setVisiblePlugin(null); setHiddenElement('first'); } else { setVisiblePlugin(plugin); setHiddenElement(null); } }; return (
{plugins.map((plugin, index) => { const isVisible = plugin === visiblePlugin; const label = `${isVisible ? 'Hide' : 'Show'} ${plugin.title}`; return ( ); })}
Short Keys {/* Fixes Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent} */} This modal provides a list of available keyboard shortcuts and their functions.
Settings {/* Fixes Warning: Missing `Description` or `aria-describedby={undefined}` for {DialogContent} */} This modal lets you adjust header persistence, interface theme, and clear local storage.
{showPersistHeadersSettings ? (
Persist headers
Save headers upon reloading.{' '} Only enable if you trust this device.
) : null} {!forcedTheme && (
Theme
Adjust how the interface appears.
)}
Clear storage
Remove all locally stored data and start fresh.
); }; ================================================ FILE: packages/graphiql/src/ui/toolbar.tsx ================================================ import type { FC, ReactElement, ReactNode } from 'react'; import { CopyIcon, KEY_MAP, MergeIcon, PrettifyIcon, ToolbarButton, useGraphiQLActions, } from '@graphiql/react'; const DefaultToolbarRenderProps: FC<{ prettify: ReactNode; copy: ReactNode; merge: ReactNode; }> = ({ prettify, copy, merge }) => ( <> {prettify} {merge} {copy} ); /** * Configure the UI by providing this Component as a child of GraphiQL. */ export const GraphiQLToolbar: FC<{ children?: typeof DefaultToolbarRenderProps | ReactNode; }> = ({ children = DefaultToolbarRenderProps }) => { const isRenderProp = typeof children === 'function'; const { copyQuery, prettifyEditors, mergeQuery } = useGraphiQLActions(); if (!isRenderProp) { return children as ReactElement; } const prettify = ( ); const merge = ( ); const copy = ( ); return children({ prettify, copy, merge }); }; ================================================ FILE: packages/graphiql/test/README.md ================================================ # Test GraphiQL Application This test folder serves as a basis for testing in-development changes and offers watching/compiling of the `src` folder. To utilize this, simply: 1. Run `npm install` 2. Run `npm run dev` 3. Open your browser to the address listed in your console. e.g. `Started on http://localhost:49811/` ================================================ FILE: packages/graphiql/test/e2e-server.js ================================================ /** * Copyright (c) 2021 GraphQL Contributors. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ /* eslint-disable no-console */ import { createServer } from 'node:http'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import express from 'express'; import { useServer } from 'graphql-ws/use/ws'; import { WebSocketServer } from 'ws'; import { getGraphQLParameters, processRequest, sendResult, } from 'graphql-helix'; // update when `graphql-http` is upgraded to support multipart requests for incremental delivery https://github.com/graphql/graphiql/pull/3682#discussion_r1715545279 import * as graphql from 'graphql'; import { createSchema } from './schema.js'; import { createExecute } from './execute.js'; const schema = createSchema(graphql); const customExecute = createExecute(graphql); const app = express(); async function handler(req, res) { const request = { body: req.body, headers: req.headers, method: req.method, query: req.query, }; const { operationName, query, variables } = getGraphQLParameters(request); const result = await processRequest({ operationName, query, variables, request, schema, execute: customExecute, }); sendResult(result, res); } // Server app.use(express.json()); app.post('/graphql', handler); app.get('/graphql', handler); // On CI we test the UMD build if (process.env.CI === 'true') { const __dirname = path.dirname(fileURLToPath(import.meta.url)); // const __dirname = import.meta.dirname; // can be converted to, after Node.js upgrade to v20 app.use(express.static(path.join(__dirname, '..'))); } else { app.get('/', (req, res) => { res.redirect('http://localhost:5173'); }); } // messy but it allows close const server = createServer(app); server.listen(process.env.PORT || 3100, function () { const { port } = this.address(); console.log(`Started on http://localhost:${port}`); console.log('PID', process.pid); process.once('SIGINT', () => { process.exit(); }); process.once('SIGTERM', () => { process.exit(); }); }); const wsServer = new WebSocketServer({ path: '/subscriptions', port: 8081, }); // eslint-disable-next-line react-hooks/rules-of-hooks useServer({ schema }, wsServer); ================================================ FILE: packages/graphiql/test/execute.js ================================================ export function createExecute({ execute, experimentalExecuteIncrementally, version, }) { if (parseInt(version, 10) < 17) { return execute; } return async (...args) => { const result = await experimentalExecuteIncrementally(...args); if (!('subsequentResults' in result)) { return result; } const { initialResult, subsequentResults } = result; if (typeof subsequentResults[Symbol.asyncIterator] !== 'function') { return result; } return (async function* () { yield initialResult; yield* subsequentResults; })(); }; } ================================================ FILE: packages/graphiql/test/package.json ================================================ { "type": "module", "name": "test-server", "private": true, "dependencies": { "express": "^4.20.0", "graphql": "^17.0.0-alpha.8", "graphql-helix": "^1.13.0", "graphql-ws": "^6.0.5", "ws": "8.17.1" } } ================================================ FILE: packages/graphiql/test/schema.js ================================================ /* eslint-disable no-await-in-loop */ /** * Copyright (c) 2021 GraphQL Contributors. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ /** * Create GraphQL schema from `graphql-js` 16 or 17. */ export function createSchema({ GraphQLSchema, GraphQLObjectType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, GraphQLInterfaceType, GraphQLBoolean, GraphQLInt, GraphQLFloat, GraphQLString, GraphQLID, GraphQLList, GraphQLDeferDirective, GraphQLStreamDirective, specifiedDirectives, version, }) { const directives = parseInt(version, 10) > 16 ? [...specifiedDirectives, GraphQLDeferDirective, GraphQLStreamDirective] : specifiedDirectives; // Test Schema const TestEnum = new GraphQLEnumType({ name: 'TestEnum', description: 'An enum of super cool colors.', values: { RED: { description: 'A rosy color' }, GREEN: { description: 'The color of martians and slime' }, BLUE: { description: "A feeling you might have if you can't use GraphQL", }, GRAY: { description: 'A really dull color', deprecationReason: 'Colors are available now.', }, }, }); const TestInputObject = new GraphQLInputObjectType({ name: 'TestInput', description: 'Test all sorts of inputs in this input object type.', fields: () => ({ string: { type: GraphQLString, description: 'Repeats back this string', }, int: { type: GraphQLInt }, float: { type: GraphQLFloat }, boolean: { type: GraphQLBoolean }, id: { type: GraphQLID }, enum: { type: TestEnum }, object: { type: TestInputObject }, defaultValueString: { type: GraphQLString, defaultValue: 'test default value', }, defaultValueBoolean: { type: GraphQLBoolean, defaultValue: false, }, defaultValueInt: { type: GraphQLInt, defaultValue: 5, }, // List listString: { type: new GraphQLList(GraphQLString) }, listInt: { type: new GraphQLList(GraphQLInt) }, listFloat: { type: new GraphQLList(GraphQLFloat) }, listBoolean: { type: new GraphQLList(GraphQLBoolean) }, listID: { type: new GraphQLList(GraphQLID) }, listEnum: { type: new GraphQLList(TestEnum) }, listObject: { type: new GraphQLList(TestInputObject) }, }), }); const TestInterface = new GraphQLInterfaceType({ name: 'TestInterface', description: 'Test interface.', fields: () => ({ name: { type: GraphQLString, description: 'Common name string.', }, }), resolveType(check) { return check ? UnionFirst : UnionSecond; }, }); const UnionFirst = new GraphQLObjectType({ name: 'First', fields: () => ({ name: { type: GraphQLString, description: 'Common name string for UnionFirst.', }, first: { type: new GraphQLList(TestInterface), resolve: () => true, }, }), interfaces: [TestInterface], }); const UnionSecond = new GraphQLObjectType({ name: 'Second', fields: () => ({ name: { type: GraphQLString, description: 'Common name string for UnionFirst.', }, second: { type: TestInterface, resolve: () => false, }, }), interfaces: [TestInterface], }); const TestUnion = new GraphQLUnionType({ name: 'TestUnion', types: [UnionFirst, UnionSecond], resolveType: () => UnionFirst, }); const Greeting = new GraphQLObjectType({ name: 'Greeting', fields: { text: { type: GraphQLString, }, }, }); const delayArgument = (defaultValue = 400) => ({ description: 'delay in milliseconds for subsequent results, for demonstration purposes', type: GraphQLInt, defaultValue, }); const DeferrableObject = new GraphQLObjectType({ name: 'Deferrable', fields: { normalString: { type: GraphQLString, resolve: () => 'Nice', }, deferredString: { args: { delay: delayArgument(600), }, type: GraphQLString, resolve: async function lazilyReturnValue(_value, args) { const seconds = args.delay / 1000; await sleep(args.delay); return `Oops, this took ${seconds} seconds longer than I thought it would!`; }, }, }, }); const Person = new GraphQLObjectType({ name: 'Person', fields: () => ({ name: { type: GraphQLString, resolve: obj => obj.name, }, age: { args: { delay: delayArgument(600), }, type: GraphQLInt, resolve: async function lazilyReturnValue(_value, args) { await sleep(args.delay); return Math.ceil(args.delay); }, }, friends: { type: new GraphQLList(Person), async *resolve(_value, _args) { const names = ['James', 'Mary', 'John', 'Patrica']; // Top 4 names https://ssa.gov/oact/babynames/decades/century.html for (const name of names) { await sleep(100); yield { name }; } }, }, }), }); const sleep = async timeout => new Promise(resolve => setTimeout(resolve, timeout)); const longDescription = ` The \`longDescriptionType\` field on the \`Test\` type has a long, verbose, description to test inline field docs. > We want to test several \`markdown\` styles! Check out [Markdown](https://markdownguide.org) by the way. Some notes: - Lists - work - also nested - and with very very very very very very very very very very long items that span multiple lines - you get the gist TO-DO's: 1. Open GraphiQL 1. Write a query 1. Maybe add some variables 1. Could also add headers 1. Send the request Example query: \`\`\`graphql { test { id } hasArgs(string: "very very very very very long string") } \`\`\` And we have a local image: ![GraphQL Logo](/resources/logo.svg) And external image: ![Cat](https://placecats.com/300/200) `.trim(); const TestType = new GraphQLObjectType({ name: 'Test', description: 'Test type for testing\n New line works', fields: () => ({ test: { type: TestType, description: '`test` field from `Test` type.', resolve: () => ({}), }, deferrable: { type: DeferrableObject, resolve: () => ({}), }, streamable: { type: new GraphQLList(Greeting), args: { delay: delayArgument(300), }, async *resolve(_value, args) { let i = 0; for (const hi of [ 'Hi', '你好', 'Hola', 'أهلاً', 'Bonjour', 'سلام', '안녕', 'Ciao', 'हेलो', 'Здорово', ]) { if (i > 2) { await sleep(args.delay); } i++; yield { text: hi }; } }, }, person: { type: Person, resolve: () => ({ name: 'Mark' }), }, longDescriptionType: { type: TestType, description: longDescription, resolve: () => ({}), }, union: { type: TestUnion, resolve: () => ({}), }, id: { type: GraphQLID, description: 'id field from Test type.', resolve: () => 'abc123', }, isTest: { type: GraphQLBoolean, description: 'Is this a test schema? Sure it is.', resolve: () => true, }, image: { type: GraphQLString, description: 'field that returns an image URI.', resolve: () => '/resources/logo.svg', }, deprecatedField: { type: TestType, description: 'This field is an example of a deprecated field', deprecationReason: 'No longer in use, try `test` instead.', }, alsoDeprecated: { type: TestType, description: 'This field is an example of a deprecated field with markdown in its deprecation reason', deprecationReason: longDescription, }, hasArgs: { type: GraphQLString, resolve(_value, args) { return JSON.stringify(args); }, args: { string: { type: GraphQLString, description: 'A string' }, int: { type: GraphQLInt }, float: { type: GraphQLFloat }, boolean: { type: GraphQLBoolean }, id: { type: GraphQLID }, enum: { type: TestEnum }, object: { type: TestInputObject }, defaultValue: { type: GraphQLString, defaultValue: 'test default value', }, // List listString: { type: new GraphQLList(GraphQLString) }, listInt: { type: new GraphQLList(GraphQLInt) }, listFloat: { type: new GraphQLList(GraphQLFloat) }, listBoolean: { type: new GraphQLList(GraphQLBoolean) }, listID: { type: new GraphQLList(GraphQLID) }, listEnum: { type: new GraphQLList(TestEnum) }, listObject: { type: new GraphQLList(TestInputObject) }, deprecatedArg: { type: GraphQLString, deprecationReason: 'Argument "deprecatedArg" is deprecated. Use "string" instead.', description: 'Hello!', }, }, }, }), }); const TestMutationType = new GraphQLObjectType({ name: 'MutationType', description: 'This is a simple mutation type', fields: { setString: { type: GraphQLString, description: 'Set the string field', args: { value: { type: GraphQLString }, }, }, }, }); const TestSubscriptionType = new GraphQLObjectType({ name: 'SubscriptionType', description: 'This is a simple subscription type. Learn more at https://npmjs.com/package/graphql-ws', fields: { message: { type: GraphQLString, description: 'Subscribe to a message', args: { delay: delayArgument(600), }, async *subscribe(root, args) { for (const hi of ['Hi', 'Bonjour', 'Hola', 'Ciao', 'Zdravo']) { if (args?.delay) { await sleep(args.delay); } yield { message: hi }; } }, }, }, }); return new GraphQLSchema({ query: TestType, mutation: TestMutationType, subscription: TestSubscriptionType, description: 'This is a test schema for GraphiQL', directives, }); } ================================================ FILE: packages/graphiql/tsconfig.json ================================================ { "extends": "../graphiql-react/tsconfig.json", // https://github.com/testing-library/jest-dom/issues/546#issuecomment-2558621842 "exclude": ["cypress", "cypress.config.ts"] } ================================================ FILE: packages/graphiql/vite.config.mts ================================================ import path from 'node:path'; import { defineConfig, PluginOption } from 'vite'; import dts from 'vite-plugin-dts'; import react from '@vitejs/plugin-react'; import { reactCompilerConfig as $reactCompilerConfig } from '../graphiql-react/vite.config.mjs'; import type { PluginOptions as ReactCompilerConfig } from 'babel-plugin-react-compiler'; import packageJSON from './package.json'; const reactCompilerConfig: Partial = { ...$reactCompilerConfig, sources(filename) { if ( filename.includes('__tests__') || /\.(spec|test)\.tsx?$/.test(filename) ) { return false; } return filename.includes(`packages${path.sep}graphiql${path.sep}src`); }, }; export const plugins: PluginOption[] = [ react({ babel: { plugins: [['babel-plugin-react-compiler', reactCompilerConfig]], }, }), ]; const umdConfig = defineConfig({ define: { // graphql v17 'globalThis.process.env.NODE_ENV': 'true', // 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"', }, plugins, css: { transformer: 'lightningcss', }, build: { minify: 'terser', // produce less bundle size sourcemap: true, emptyOutDir: false, lib: { entry: 'src/cdn.ts', /** * The name of the exposed global variable. Required when the `formats` option includes `umd` * or `iife`. */ name: 'GraphiQL', fileName: 'index', formats: ['umd'], }, rollupOptions: { external: ['react', 'react-dom'], output: { globals: { react: 'React', 'react-dom': 'ReactDOM', }, }, }, }, worker: { format: 'es', rollupOptions: { output: { entryFileNames: 'workers/[name].js', // Just to group worker assets, add shared/internal chunks too chunkFileNames: 'workers/[name].js', }, }, }, }); const esmConfig = defineConfig({ build: { cssCodeSplit: true, minify: false, sourcemap: true, lib: { entry: [ 'src/index.ts', 'src/e2e.ts', 'src/setup-workers/webpack.ts', 'src/setup-workers/vite.ts', 'src/setup-workers/esm.sh.ts', ], fileName: (_format, filePath) => `${filePath}.js`, formats: ['es'], cssFileName: 'style', }, rollupOptions: { external: [ 'react/jsx-runtime', // Exclude peer dependencies and dependencies from bundle ...Object.keys({ ...packageJSON.peerDependencies, ...packageJSON.dependencies, }), /^@graphiql\/react\//, ], output: { // Separate chunks for all modules preserveModules: true, }, }, }, server: { // Prevent a browser window from opening automatically open: false, proxy: { '/graphql': 'http://localhost:8080', '/subscriptions': { target: 'ws://localhost:8081', ws: true, }, }, }, plugins: [ ...plugins, htmlPlugin(), process.env.NODE_ENV === 'production' && removeImportsFromE2EFile(), dts({ include: ['src/**'], outDir: ['dist'], exclude: ['**/*.spec.{ts,tsx}', '**/__tests__/'], }), ], worker: { format: 'es', }, }); function htmlPlugin(): PluginOption { return { name: 'html-replace-umd-with-src', transformIndexHtml: { order: 'pre', handler(html) { const start = ''; const end = ''; const contentToReplace = html.slice( html.indexOf(start), html.indexOf(end) + end.length, ); return html.replace( contentToReplace, '', ); }, }, }; } function removeImportsFromE2EFile(): PluginOption { return { name: 'remove-imports-from-e2e-file', enforce: 'pre', // Ensure it runs before Vite's own transformers transform(code: string, id: string) { if (id.endsWith('e2e.ts')) { const transformedCode = code .split('\n') .filter(line => !line.startsWith('import ')) .join('\n'); return { code: transformedCode, // Remove source map to clean vite warning: // a plugin (remove-imports-from-e2e-file) was used to transform files, but didn't generate a sourcemap for the transformation map: null, }; } }, }; } export default process.env.UMD === 'true' ? umdConfig : esmConfig; ================================================ FILE: packages/graphiql/vitest.config.mts ================================================ import path from 'node:path'; import { defineConfig } from 'vitest/config'; import { plugins } from './vite.config.mjs'; export default defineConfig({ plugins, test: { globals: true, environment: 'jsdom', setupFiles: ['./setup-files.ts', './setup-window.ts'], // Since we increased `waitFor` timeout in setup-files.ts testTimeout: 9_000, alias: [ { // Fixes Error: Failed to resolve entry for package "monaco-editor". The package may have incorrect main/module/exports specified in its package.json. find: /^monaco-editor$/, replacement: path.resolve( '../../node_modules/monaco-editor/esm/vs/editor/editor.api', ), }, ], }, }); ================================================ FILE: packages/graphiql-plugin-code-exporter/CHANGELOG.md ================================================ # @graphiql/plugin-code-exporter ## 5.1.1 ### Patch Changes - Updated dependencies [[`6e5d5fc`](https://github.com/graphql/graphiql/commit/6e5d5fce9a7eb5770f40300fc153e0b9b10edfbf), [`293beed`](https://github.com/graphql/graphiql/commit/293beed772baa2be834cad5f19e1aee0628e15cc)]: - @graphiql/react@0.37.0 ## 5.1.0 ### Minor Changes - [#4077](https://github.com/graphql/graphiql/pull/4077) [`3d41e11`](https://github.com/graphql/graphiql/commit/3d41e113fbf53930fd1b519b6d1330d0f4b23b7b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - add new example [Usage GraphiQL 5 with Vite, React Router and `ssr: true`](https://github.com/graphql/graphiql/tree/main/examples/example-graphiql-vite-react-router) ### Patch Changes - Updated dependencies [[`3a0a755`](https://github.com/graphql/graphiql/commit/3a0a75569c6b318f5dc27d62000bcc9b0536c6fd), [`fd3f9e6`](https://github.com/graphql/graphiql/commit/fd3f9e6a91be728a69a136ad8680f6e3c7241198), [`416e3a0`](https://github.com/graphql/graphiql/commit/416e3a05e9473eb2abd444da61ecfb8614020d14), [`3d41e11`](https://github.com/graphql/graphiql/commit/3d41e113fbf53930fd1b519b6d1330d0f4b23b7b)]: - @graphiql/react@0.36.0 ## 5.0.0 ### Major Changes - [#4002](https://github.com/graphql/graphiql/pull/4002) [`2d9faec`](https://github.com/graphql/graphiql/commit/2d9faec57830b38aa175929c47a55c959c327535) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove UMD builds ### Minor Changes - [#4025](https://github.com/graphql/graphiql/pull/4025) [`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - set "importsNotUsedAsValues": "error" in tsconfig ### Patch Changes - [#3234](https://github.com/graphql/graphiql/pull/3234) [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Migration from Codemirror to [Monaco Editor](https://github.com/microsoft/monaco-editor) Replacing `codemirror-graphql` with [`monaco-graphql`](https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql) Support for comments in **Variables** and **Headers** editors ## 5.0.0-rc.2 ### Minor Changes - [#4025](https://github.com/graphql/graphiql/pull/4025) [`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - set "importsNotUsedAsValues": "error" in tsconfig ## 5.0.0-rc.1 ### Major Changes - [#4002](https://github.com/graphql/graphiql/pull/4002) [`2d9faec`](https://github.com/graphql/graphiql/commit/2d9faec57830b38aa175929c47a55c959c327535) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove UMD builds ## 4.0.6-rc.0 ### Patch Changes - [#3234](https://github.com/graphql/graphiql/pull/3234) [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Migration from Codemirror to [Monaco Editor](https://github.com/microsoft/monaco-editor) Replacing `codemirror-graphql` with [`monaco-graphql`](https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql) Support for comments in **Variables** and **Headers** editors - Updated dependencies [[`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e), [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91), [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb)]: - @graphiql/react@0.35.0-rc.0 ## 4.0.5 ### Patch Changes - Updated dependencies [[`71755b7`](https://github.com/graphql/graphiql/commit/71755b7f412f8f3dd9f5194d3f1e0168b9ad07af), [`6d631e2`](https://github.com/graphql/graphiql/commit/6d631e2e558d038476fe235b1506bc52ecf68781)]: - @graphiql/react@0.34.0 ## 4.0.4 ### Patch Changes - Updated dependencies [[`117627b`](https://github.com/graphql/graphiql/commit/117627b451607198dd7b9dc19e76da8a71d14b71), [`fa78481`](https://github.com/graphql/graphiql/commit/fa784819ce020346052901019079fb5b44af6ef0), [`7275472`](https://github.com/graphql/graphiql/commit/727547236bbd4fc721069ceae63eb8a6acffa57e), [`00c8605`](https://github.com/graphql/graphiql/commit/00c8605e1f3068e6547a5a9e969571a86a57f921)]: - @graphiql/react@0.33.0 ## 4.0.3 ### Patch Changes - [#3939](https://github.com/graphql/graphiql/pull/3939) [`69ad489`](https://github.com/graphql/graphiql/commit/69ad489678d0096432d5c4b1749d87343f4ed1f7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - prefer `React.FC` type when declaring React components ## 4.0.2 ### Patch Changes - Updated dependencies [[`98d13a3`](https://github.com/graphql/graphiql/commit/98d13a3e515eb70aaf5a5ba669c680d5959fef67)]: - @graphiql/react@0.32.0 ## 4.0.1 ### Patch Changes - [#3915](https://github.com/graphql/graphiql/pull/3915) [`bc31cd9`](https://github.com/graphql/graphiql/commit/bc31cd99a92693238e7359456e3cc22ed0387df0) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix unpkg.com results to `Not found` when `main` field isn't specified in `package.json` - Updated dependencies [[`e7c436b`](https://github.com/graphql/graphiql/commit/e7c436b329a68981bdbd2b662be94875a546a1d6)]: - @graphiql/react@0.31.0 ## 4.0.0 ### Major Changes - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - `style.css` import was changed ## Migration ```diff -import '@graphiql/plugin-code-exporter/dist/style.css'; +import '@graphiql/plugin-code-exporter/style.css'; ``` - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - drop commonjs build files - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - 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 ### Minor Changes - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Update GraphiQL CDN example using ESM-based CDN esm.sh - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - generate types with `vite-plugin-dts` - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update `vite` and related dependencies ### Patch Changes - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix types incorrect types entry - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - use `vite build --watch` instead of `vite` for `dev` script because we don't need development server for them do not use `vite-plugin-dts` when generating umd build - Updated dependencies [[`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602)]: - @graphiql/react@0.30.0 ## 4.0.0-alpha.1 ### Patch Changes - [#3740](https://github.com/graphql/graphiql/pull/3740) [`3c12ce0`](https://github.com/graphql/graphiql/commit/3c12ce01eb3b2ec9a317a2fea2bb92602b748a8b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix types incorrect types entry ## 4.0.0-alpha.0 ### Major Changes - [#3709](https://github.com/graphql/graphiql/pull/3709) [`9baf1f0`](https://github.com/graphql/graphiql/commit/9baf1f0fc9f32404fbb8bf57b3d1c2c2c8778ddb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - `style.css` import was changed ## Migration ```diff -import '@graphiql/plugin-code-exporter/dist/style.css'; +import '@graphiql/plugin-code-exporter/style.css'; ``` ### Minor Changes - [#3702](https://github.com/graphql/graphiql/pull/3702) [`00415d2`](https://github.com/graphql/graphiql/commit/00415d2940c4d76a4a9e683e9fa0504ba97dd627) Thanks [@dimaMachina](https://github.com/dimaMachina)! - generate types with `vite-plugin-dts` ### Patch Changes - [#3705](https://github.com/graphql/graphiql/pull/3705) [`8ff87d7`](https://github.com/graphql/graphiql/commit/8ff87d7b6b3d5d12b539612a39ca3abf7e631106) Thanks [@dimaMachina](https://github.com/dimaMachina)! - use `vite build --watch` instead of `vite` for `dev` script because we don't need development server for them do not use `vite-plugin-dts` when generating umd build - Updated dependencies [[`00415d2`](https://github.com/graphql/graphiql/commit/00415d2940c4d76a4a9e683e9fa0504ba97dd627), [`9baf1f0`](https://github.com/graphql/graphiql/commit/9baf1f0fc9f32404fbb8bf57b3d1c2c2c8778ddb), [`8ff87d7`](https://github.com/graphql/graphiql/commit/8ff87d7b6b3d5d12b539612a39ca3abf7e631106), [`82bc961`](https://github.com/graphql/graphiql/commit/82bc961a33c4e9da29dffb4a603035a4909f49ad), [`3c1a345`](https://github.com/graphql/graphiql/commit/3c1a345acd9bf07b45bc230009cb57c51c425673)]: - @graphiql/react@1.0.0-alpha.0 ## 3.1.5 ### Patch Changes - Updated dependencies [[`cb29e9f`](https://github.com/graphql/graphiql/commit/cb29e9fbe1362778bc327513fc884c4ec419775e), [`1adc40c`](https://github.com/graphql/graphiql/commit/1adc40cc56dbf79296bb857156e6adce1c44dcbe)]: - @graphiql/react@0.29.0 ## 3.1.4 ### Patch Changes - Updated dependencies [[`3633d61`](https://github.com/graphql/graphiql/commit/3633d61c3c597adf60c0ec1bbf98cf6a1f49beed)]: - @graphiql/react@0.28.0 ## 3.1.3 ### Patch Changes - Updated dependencies [[`f86e2bc`](https://github.com/graphql/graphiql/commit/f86e2bce40826b3d07755f91b37a72051de00f9c)]: - @graphiql/react@0.27.0 ## 3.1.2 ### Patch Changes - Updated dependencies [[`959ed21`](https://github.com/graphql/graphiql/commit/959ed21815682fc439f64d78e23e603a8f313a6f), [`9aef83a`](https://github.com/graphql/graphiql/commit/9aef83a32aeb5f193a3ff0f191c95d09eb0d70b6)]: - @graphiql/react@0.26.0 ## 3.1.1 ### Patch Changes - Updated dependencies [[`7404e8e`](https://github.com/graphql/graphiql/commit/7404e8e6c62b06107f452142493297ec70f1649c)]: - @graphiql/react@0.25.0 ## 3.1.0 ### Minor Changes - [#3682](https://github.com/graphql/graphiql/pull/3682) [`6c9f0df`](https://github.com/graphql/graphiql/commit/6c9f0df83ea4afe7fa59f84d83d59fba73dc3931) Thanks [@yaacovCR](https://github.com/yaacovCR)! - Support v17 of `graphql-js` from `17.0.0-alpha.2` forward. Includes support for the latest incremental delivery response format. For further details, see https://github.com/graphql/defer-stream-wg/discussions/69. ### Patch Changes - Updated dependencies [[`6c9f0df`](https://github.com/graphql/graphiql/commit/6c9f0df83ea4afe7fa59f84d83d59fba73dc3931)]: - @graphiql/react@0.24.0 ## 3.0.5 ### Patch Changes - [#3657](https://github.com/graphql/graphiql/pull/3657) [`5bc7b84`](https://github.com/graphql/graphiql/commit/5bc7b84531b6404553787615d61a5cbcc96c1d6f) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update vite to v5 - [#3656](https://github.com/graphql/graphiql/pull/3656) [`93c7e9f`](https://github.com/graphql/graphiql/commit/93c7e9fd224cb4f1e9a86b3391efc1e0ef6e1e3f) Thanks [@dimaMachina](https://github.com/dimaMachina)! - set `build.minify: false` for cjs/esm builds since minified variable names change every build time - Updated dependencies [[`5bc7b84`](https://github.com/graphql/graphiql/commit/5bc7b84531b6404553787615d61a5cbcc96c1d6f), [`fdec377`](https://github.com/graphql/graphiql/commit/fdec377f28ac0d918a219b78dfa2d8f0996ff84d), [`93c7e9f`](https://github.com/graphql/graphiql/commit/93c7e9fd224cb4f1e9a86b3391efc1e0ef6e1e3f)]: - @graphiql/react@0.23.0 ## 3.0.4 ### Patch Changes - [#3634](https://github.com/graphql/graphiql/pull/3634) [`adf0ba01`](https://github.com/graphql/graphiql/commit/adf0ba019902dcac2e49ccee69b79a6665c4766d) Thanks [@dimaMachina](https://github.com/dimaMachina)! - when alpha is `1`, use `hsl` instead of `hsla` - Updated dependencies [[`adf0ba01`](https://github.com/graphql/graphiql/commit/adf0ba019902dcac2e49ccee69b79a6665c4766d)]: - @graphiql/react@0.22.4 ## 3.0.3 ### Patch Changes - Updated dependencies [[`335d830c`](https://github.com/graphql/graphiql/commit/335d830c2a4e551ef97fbeff8ed7c538ff5cd4af)]: - @graphiql/react@0.22.3 ## 3.0.2 ### Patch Changes - Updated dependencies [[`03ab3a6b`](https://github.com/graphql/graphiql/commit/03ab3a6b76378591ef79a828d80cc69b0b8f2842)]: - @graphiql/react@0.22.2 ## 3.0.1 ### Patch Changes - Updated dependencies [[`224b43f5`](https://github.com/graphql/graphiql/commit/224b43f5473456f264a82998d48a34a441537f54)]: - @graphiql/react@0.22.1 ## 3.0.0 ### Patch Changes - Updated dependencies [[`d48f4ef5`](https://github.com/graphql/graphiql/commit/d48f4ef56578dad7ec90f33458353791e463ef7b)]: - @graphiql/react@0.22.0 ## 2.0.0 ### Patch Changes - Updated dependencies [[`5d051054`](https://github.com/graphql/graphiql/commit/5d05105469c3f0cbeb5e294da1cf6ff2355e4eb5)]: - @graphiql/react@0.21.0 ## 1.0.5 ### Patch Changes - Updated dependencies []: - @graphiql/react@0.20.4 ## 1.0.4 ### Patch Changes - Updated dependencies [[`2b6ea316`](https://github.com/graphql/graphiql/commit/2b6ea3166c8d8e152f16d87c878aa8a66f1b3775)]: - @graphiql/react@0.20.3 ## 1.0.3 ### Patch Changes - [#3439](https://github.com/graphql/graphiql/pull/3439) [`d07d5fc0`](https://github.com/graphql/graphiql/commit/d07d5fc0cf764518bc1184ef168361cedf61540b) Thanks [@xonx4l](https://github.com/xonx4l)! - FIX: Unexpected duplicate CSS "display" property ## 1.0.2 ### Patch Changes - Updated dependencies [[`e89c432d`](https://github.com/graphql/graphiql/commit/e89c432d8d2b91f087b683360f23e0686462bc02)]: - @graphiql/react@0.20.2 ## 1.0.1 ### Patch Changes - Updated dependencies [[`39bf31d1`](https://github.com/graphql/graphiql/commit/39bf31d15b1e7fb5f235ec9adc1ce8081536de4a)]: - @graphiql/react@0.20.1 ## 1.0.0 ### Patch Changes - Updated dependencies [[`f6afd22d`](https://github.com/graphql/graphiql/commit/f6afd22d3f5a20089759042f16fd865646a32038)]: - @graphiql/react@0.20.0 ## 0.3.5 ### Patch Changes - Updated dependencies []: - @graphiql/react@0.19.4 ## 0.3.4 ### Patch Changes - Updated dependencies [[`2348641c`](https://github.com/graphql/graphiql/commit/2348641c07748691c478ac5f67032b7e9081f9cb)]: - @graphiql/react@0.19.3 ## 0.3.3 ### Patch Changes - Updated dependencies [[`d67c13f6`](https://github.com/graphql/graphiql/commit/d67c13f6e1f478b171801afd0767b98312db04c9)]: - @graphiql/react@0.19.2 ## 0.3.2 ### Patch Changes - [#3341](https://github.com/graphql/graphiql/pull/3341) [`e4a36207`](https://github.com/graphql/graphiql/commit/e4a362071edf1db53f87f271c523ab2f3a5c4717) Thanks [@acao](https://github.com/acao)! - Fix code exporter plugin on early init, add hooks - Updated dependencies [[`17069e7a`](https://github.com/graphql/graphiql/commit/17069e7a0224dbce3f5523630a898e093f5c47c9), [`e4a36207`](https://github.com/graphql/graphiql/commit/e4a362071edf1db53f87f271c523ab2f3a5c4717)]: - @graphiql/react@0.19.1 ## 0.3.1 ### Patch Changes - [#3350](https://github.com/graphql/graphiql/pull/3350) [`119775ed`](https://github.com/graphql/graphiql/commit/119775ed191ce075532a6e85cbfeac2364c0ba40) Thanks [@acao](https://github.com/acao)! - handle null editor in explorer plugin [(PR)](https://github.com/graphql/graphiql/pull/3340) ## 0.3.0 ### Minor Changes - [#3330](https://github.com/graphql/graphiql/pull/3330) [`bed5fc86`](https://github.com/graphql/graphiql/commit/bed5fc86173eb0e770f966fa529ee035b97a1349) Thanks [@acao](https://github.com/acao)! - **BREAKING CHANGE**: fix lifecycle issue in plugin-explorer, change implementation pattern `value` and `setValue` is no longer an implementation detail, and are handled internally by plugins. the plugin signature has changed slightly as well. now, instead of something like this: ```jsx import { useExplorerPlugin } from '@graphiql/plugin-explorer'; import { snippets } from './snippets'; import { useExporterPlugin } from '@graphiql/plugin-code-exporter'; const App = () => { const [query, setQuery] = React.useState(''); const explorerPlugin = useExplorerPlugin({ query, onEdit: setQuery, }); const codeExporterPlugin = useExporterPlugin({ query, snippets, }); const plugins = React.useMemo( () => [explorerPlugin, codeExporterPlugin], [explorerPlugin, codeExporterPlugin], ); return ( ); }; ``` you can just do this: ```jsx import { explorerPlugin } from '@graphiql/plugin-explorer'; import { snippets } from './snippets'; import { codeExporterPlugin } from '@graphiql/plugin-code-exporter'; import { createGraphiQLFetcher } from '@graphiql/toolkit'; // only invoke these inside the component lifecycle // if there are dynamic values, and then use useMemo() (see below) const explorer = explorerPlugin(); const exporter = codeExporterPlugin({ snippets }); const fetcher = createGraphiQLFetcher({ url: '/graphql' }); const App = () => { return ; }; ``` or this, for more complex state-driven needs: ```jsx import { useMemo } from 'react'; import { explorerPlugin } from '@graphiql/plugin-explorer'; import { snippets } from './snippets'; import { codeExporterPlugin } from '@graphiql/plugin-code-exporter'; const explorer = explorerPlugin(); const fetcher = createGraphiQLFetcher({ url: '/graphql' }); const App = () => { const { snippets } = useMyUserSuppliedState(); const exporter = useMemo( () => codeExporterPlugin({ snippets }), [snippets], ); return ; }; ``` ## 0.2.0 ### Minor Changes - [#3293](https://github.com/graphql/graphiql/pull/3293) [`1b8f3fe9`](https://github.com/graphql/graphiql/commit/1b8f3fe9c41697855378ec13a76f1a908fda778a) Thanks [@B2o5T](https://github.com/B2o5T)! - BREAKING CHANGE: umd build was renamed to `index.umd.js` ## 0.1.4 ### Patch Changes - [#3292](https://github.com/graphql/graphiql/pull/3292) [`f86e4172`](https://github.com/graphql/graphiql/commit/f86e41721d4d990535253b579c810bc5e291b40b) Thanks [@B2o5T](https://github.com/B2o5T)! - fix umd build names `graphiql-plugin-code-exporter.umd.js` and `graphiql-plugin-explorer.umd.js` ## 0.1.3 ### Patch Changes - [#3229](https://github.com/graphql/graphiql/pull/3229) [`0a65e720`](https://github.com/graphql/graphiql/commit/0a65e7207b6bc4174896f6acca8a40f45d2fb1b8) Thanks [@B2o5T](https://github.com/B2o5T)! - exclude peer dependencies and dependencies from bundle - [#3251](https://github.com/graphql/graphiql/pull/3251) [`f8d8509b`](https://github.com/graphql/graphiql/commit/f8d8509b432803eaeb2e53b6b6d4321535e11c1d) Thanks [@B2o5T](https://github.com/B2o5T)! - always bundle `package.json#dependencies` for UMD build for `@graphiql/plugin-code-exporter` and `@graphiql/plugin-explorer` - [#3236](https://github.com/graphql/graphiql/pull/3236) [`64da8c30`](https://github.com/graphql/graphiql/commit/64da8c3074628bb411eb1c28aa4738843f60910c) Thanks [@B2o5T](https://github.com/B2o5T)! - update vite ## 0.1.3-alpha.0 ### Patch Changes - [#3229](https://github.com/graphql/graphiql/pull/3229) [`0a65e720`](https://github.com/graphql/graphiql/commit/0a65e7207b6bc4174896f6acca8a40f45d2fb1b8) Thanks [@B2o5T](https://github.com/B2o5T)! - exclude peer dependencies and dependencies from bundle ## 0.1.2 ### Patch Changes - [#3017](https://github.com/graphql/graphiql/pull/3017) [`4a2284f5`](https://github.com/graphql/graphiql/commit/4a2284f54809f91d03ba51b9eb4e3ba7b8b7e773) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Avoid bundling code from `react/jsx-runtime` so that the package can be used with Preact - [#3063](https://github.com/graphql/graphiql/pull/3063) [`5792aaa5`](https://github.com/graphql/graphiql/commit/5792aaa5b26b68dc396f7bfb5dc3defd9331b831) Thanks [@B2o5T](https://github.com/B2o5T)! - avoid `useMemo` with empty array `[]` since React can't guarantee stable reference, + lint restrict syntax for future mistakes ## 0.1.1 ### Patch Changes - [#2864](https://github.com/graphql/graphiql/pull/2864) [`f61a5574`](https://github.com/graphql/graphiql/commit/f61a55747a6ff3a125c54e2bf3512f8f4b8f4c50) Thanks [@LekoArts](https://github.com/LekoArts)! - chore(@graphiql/plugin-code-exporter): Fix Typo ## 0.1.0 ### Minor Changes - [#2758](https://github.com/graphql/graphiql/pull/2758) [`d63801fa`](https://github.com/graphql/graphiql/commit/d63801fad08e840eff7ff26f55694c6d18769466) Thanks [@LekoArts](https://github.com/LekoArts)! - Add code exported plugin ================================================ FILE: packages/graphiql-plugin-code-exporter/README.md ================================================ # GraphiQL Code Exporter Plugin This package provides a plugin that integrates the [GraphiQL Code Exporter](https://github.com/OneGraph/graphiql-code-exporter) into the GraphiQL UI. ## Installation Install the plugin using your preferred package manager: ```sh npm install @graphiql/plugin-code-exporter ``` Make sure to also install the required peer dependencies: ```sh npm install react react-dom graphql ``` ## Usage Refer to the [GraphiQL Code Exporter README](https://github.com/OneGraph/graphiql-code-exporter) for full details on available `props` and how to [create snippets](https://github.com/OneGraph/graphiql-code-exporter#snippets). Example integration: ```jsx import { GraphiQL } from 'graphiql'; import { createGraphiQLFetcher } from '@graphiql/toolkit'; import { codeExporterPlugin } from '@graphiql/plugin-code-exporter'; import 'graphiql/style.css'; import '@graphiql/plugin-code-exporter/style.css'; const fetcher = createGraphiQLFetcher({ url: 'https://countries.trevorblades.com', }); function getQuery(arg, spaceCount = 2) { const spaces = ' '.repeat(spaceCount); const { query } = arg.operationDataList[0]; return spaces + query.replaceAll('\n', '\n' + spaces); } const codeExporter = codeExporterPlugin({ /** * Example code for snippets. See https://github.com/OneGraph/graphiql-code-exporter#snippets for details. */ snippets: [ { name: 'Example One', language: 'JavaScript', codeMirrorMode: 'jsx', options: [], generate: arg => ['export const query = graphql`', getQuery(arg), '`'].join('\n'), }, { name: 'Example Two', language: 'JavaScript', codeMirrorMode: 'jsx', options: [], generate: arg => [ "import { graphql } from 'graphql'", '', 'export const query = graphql`', getQuery(arg), '`', ].join('\n'), }, ], }); function App() { return ; } ``` ## CDN bundles You can also use this plugin via an ESM-based CDN like [esm.sh](https://esm.sh). See the [CDN example](./example/index.html) for a working demo. ================================================ FILE: packages/graphiql-plugin-code-exporter/example/index.html ================================================ GraphiQL 5 with React 19 and GraphiQL Code Exporter
Loading…
================================================ FILE: packages/graphiql-plugin-code-exporter/package.json ================================================ { "name": "@graphiql/plugin-code-exporter", "version": "5.1.1", "sideEffects": false, "repository": { "type": "git", "url": "https://github.com/graphql/graphiql", "directory": "packages/graphiql-plugin-code-exporter" }, "author": "LekoArts", "main": "dist/index.js", "types": "dist/index.d.ts", "license": "MIT", "keywords": [ "react", "graphql", "graphiql", "plugin", "explorer" ], "files": [ "dist" ], "exports": { "./package.json": "./package.json", "./style.css": "./dist/style.css", ".": "./dist/index.js" }, "scripts": { "types:check": "tsc --noEmit", "dev": "vite build --watch --emptyOutDir=false", "build": "vite build", "postbuild": "cp src/graphiql-code-exporter.d.ts dist/graphiql-code-exporter.d.ts" }, "dependencies": { "graphiql-code-exporter": "^3.0.3" }, "peerDependencies": { "@graphiql/react": "^0.37.0", "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0-alpha.2", "react": "^18 || ^19", "react-dom": "^18 || ^19" }, "devDependencies": { "@graphiql/react": "^0.37.0", "@vitejs/plugin-react": "^4.4.1", "graphql": "^16.9.0", "react": "^19.1.0", "react-dom": "^19.1.0", "typescript": "^4.6.3", "vite": "^6.3.4", "vite-plugin-dts": "^4.0.1" } } ================================================ FILE: packages/graphiql-plugin-code-exporter/src/graphiql-code-exporter.d.ts ================================================ declare module 'graphiql-code-exporter' { import { ComponentType } from 'react'; import { GraphQLSchema, OperationTypeNode, OperationDefinitionNode, FragmentDefinitionNode, } from 'graphql'; type OperationData = { query: string; name: string; displayName: string; type: OperationTypeNode | 'fragment'; variableName: string; variables: Record; operationDefinition: OperationDefinitionNode | FragmentDefinitionNode; fragmentDependencies: Array; }; type GenerateOptions = { serverUrl: string; headers: Record; context: Record; operationDataList: Array; options: Record; }; type Snippet = { language: string; codeMirrorMode: string; name: string; options: Array<{ id: string; label: string; initial: boolean; }>; generate: (options: GenerateOptions) => string; }; export type GraphiQLCodeExporterProps = { query: string; snippets: Array; codeMirrorTheme?: string; variables?: string; context?: Record; schema?: GraphQLSchema | null | undefined; }; const GraphiQLCodeExporter: ComponentType; export default GraphiQLCodeExporter; } ================================================ FILE: packages/graphiql-plugin-code-exporter/src/index.css ================================================ .docExplorerWrap { height: unset !important; min-width: unset !important; width: unset !important; } .doc-explorer-title { font-size: var(--font-size-h2); font-weight: var(--font-weight-medium); } .doc-explorer-rhs { display: none; } .doc-explorer-contents { border-top: none !important; } .graphiql-code-exporter { min-width: unset !important; position: relative; padding: var(--px-16) 0; & > div { font-family: var(--font-family) !important; padding: 0 !important; font-size: var(--font-size-body) !important; } & > div:first-of-type { display: flex; flex-direction: column; gap: var(--px-16); & > div { padding: 0 !important; } & > div:first-of-type { display: flex; flex-direction: row; gap: var(--px-16); } & > div:last-of-type { & > div:first-of-type { color: hsla(var(--color-neutral), var(--alpha-secondary)) !important; font-variant: unset !important; text-transform: unset !important; font-weight: unset !important; margin-bottom: var(--px-12); } } } & button.toolbar-button { height: var(--toolbar-width) !important; width: var(--toolbar-width) !important; border-radius: var(--border-radius-4) !important; cursor: pointer; display: inline-flex; font-size: unset !important; left: unset !important; margin-top: unset !important; top: var(--px-16); right: 0; justify-content: center; align-items: center; background-color: unset !important; & svg { fill: hsla(var(--color-neutral), var(--alpha-tertiary)); } } & > div:last-of-type { border-top: none !important; display: flex; flex: 1; margin-top: var(--px-24) !important; & > div { position: relative; min-height: 600px; width: 100%; } } & .toolbar-menu.toolbar-button { position: relative; cursor: pointer; text-decoration: none; padding: var(--px-8) var(--px-12); color: hsl(var(--color-neutral)) !important; border-radius: var(--border-radius-4) !important; &:hover { background-color: hsla( var(--color-neutral), var(--alpha-background-light) ) !important; } } & .toolbar-menu-items { background-color: hsl(var(--color-base)) !important; border: var(--popover-border); border-radius: var(--border-radius-8); box-shadow: var(--popover-box-shadow) !important; padding: var(--px-4); max-width: 250px; font-size: inherit; display: block; white-space: nowrap; outline: none; position: absolute; z-index: 100; margin-top: var(--px-8); visibility: hidden; left: 0; &.open { visibility: visible; } & > li { cursor: pointer; display: block; color: inherit; font: inherit; text-decoration: initial; border-radius: var(--border-radius-4); margin: var(--px-4); overflow: hidden; padding: var(--px-6) var(--px-8); text-overflow: ellipsis; white-space: nowrap; &:hover { color: inherit; background-color: hsla( var(--color-neutral), var(--alpha-background-light) ); } } } & .CodeMirror { box-shadow: var(--popover-box-shadow); border-radius: var(--border-radius-12); padding: var(--px-16); } } ================================================ FILE: packages/graphiql-plugin-code-exporter/src/index.tsx ================================================ import { useOperationsEditorState, type GraphiQLPlugin } from '@graphiql/react'; import type { FC } from 'react'; import GraphiQLCodeExporter, { GraphiQLCodeExporterProps, } from 'graphiql-code-exporter'; import './index.css'; type GraphiQLCodeExporterPluginProps = Omit; const GraphiQLCodeExporterPlugin: FC< GraphiQLCodeExporterPluginProps > = props => { const [operationsString] = useOperationsEditorState(); return ( ); }; export function codeExporterPlugin( props: GraphiQLCodeExporterPluginProps, ): GraphiQLPlugin { return { title: 'GraphiQL Code Exporter', icon: () => ( ), content() { return ; }, }; } ================================================ FILE: packages/graphiql-plugin-code-exporter/tsconfig.json ================================================ { "extends": "../graphiql-react/tsconfig.json" } ================================================ FILE: packages/graphiql-plugin-code-exporter/vite.config.mts ================================================ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import packageJSON from './package.json'; import dts from 'vite-plugin-dts'; export default defineConfig({ plugins: [react(), dts({ include: ['src/**'] })], css: { transformer: 'lightningcss', }, build: { minify: false, lib: { entry: 'src/index.tsx', fileName: (_format, filePath) => `${filePath}.js`, formats: ['es'], cssFileName: 'style', }, rollupOptions: { external: [ 'react/jsx-runtime', // Exclude peer dependencies and dependencies from bundle ...Object.keys({ ...packageJSON.peerDependencies, ...packageJSON.dependencies, }), ], }, }, }); ================================================ FILE: packages/graphiql-plugin-doc-explorer/CHANGELOG.md ================================================ # @graphiql/plugin-doc-explorer ## 0.4.1 ### Patch Changes - Updated dependencies [[`6e5d5fc`](https://github.com/graphql/graphiql/commit/6e5d5fce9a7eb5770f40300fc153e0b9b10edfbf), [`293beed`](https://github.com/graphql/graphiql/commit/293beed772baa2be834cad5f19e1aee0628e15cc)]: - @graphiql/react@0.37.0 ## 0.4.0 ### Minor Changes - [#4074](https://github.com/graphql/graphiql/pull/4074) [`fd3f9e6`](https://github.com/graphql/graphiql/commit/fd3f9e6a91be728a69a136ad8680f6e3c7241198) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Ensure `storage` and `theme` store values aren't shared between GraphiQL instances. Deprecate `useTheme` and `useStorage` hooks in favour of values from `useGraphiQL` and `useGraphiQLActions` hooks feat(`@graphiql/plugin-history`/`@graphiql/plugin-doc-explorer`): move `@graphiql/react` to `peerDependencies` - [#4077](https://github.com/graphql/graphiql/pull/4077) [`3d41e11`](https://github.com/graphql/graphiql/commit/3d41e113fbf53930fd1b519b6d1330d0f4b23b7b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - add new example [Usage GraphiQL 5 with Vite, React Router and `ssr: true`](https://github.com/graphql/graphiql/tree/main/examples/example-graphiql-vite-react-router) ### Patch Changes - Updated dependencies [[`3a0a755`](https://github.com/graphql/graphiql/commit/3a0a75569c6b318f5dc27d62000bcc9b0536c6fd), [`fd3f9e6`](https://github.com/graphql/graphiql/commit/fd3f9e6a91be728a69a136ad8680f6e3c7241198), [`416e3a0`](https://github.com/graphql/graphiql/commit/416e3a05e9473eb2abd444da61ecfb8614020d14), [`3d41e11`](https://github.com/graphql/graphiql/commit/3d41e113fbf53930fd1b519b6d1330d0f4b23b7b)]: - @graphiql/react@0.36.0 ## 0.3.0 ### Minor Changes - [#3990](https://github.com/graphql/graphiql/pull/3990) [`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - allow multiple independent instances of GraphiQL on the same page - store `onClickReference` in query editor in React `ref` - remove `onClickReference` from variable editor - fix shortcut text per OS for run query in execute query button's tooltip and in default query - allow override all default GraphiQL plugins - adjust operation argument color to be purple from GraphiQL v2 on dark/light theme - [#4009](https://github.com/graphql/graphiql/pull/4009) [`4936492`](https://github.com/graphql/graphiql/commit/49364924d0da05a86f7c6c3139d44aed0e474531) Thanks [@dimaMachina](https://github.com/dimaMachina)! - separate store actions from state, add `useGraphiQLActions` state - [#4025](https://github.com/graphql/graphiql/pull/4025) [`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - set "importsNotUsedAsValues": "error" in tsconfig - [#3234](https://github.com/graphql/graphiql/pull/3234) [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Migration from Codemirror to [Monaco Editor](https://github.com/microsoft/monaco-editor) Replacing `codemirror-graphql` with [`monaco-graphql`](https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql) Support for comments in **Variables** and **Headers** editors - [#4026](https://github.com/graphql/graphiql/pull/4026) [`7fb5ac3`](https://github.com/graphql/graphiql/commit/7fb5ac38b8ec27f0234adc06aacf42e71f6a259b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - deprecate `useExplorerContext`, `useHistoryContext`, `usePrettifyEditors`, `useCopyQuery`, `useMergeQuery`, `useExecutionContext`, `usePluginContext`, `useSchemaContext`, `useStorageContext` hooks - fix response editor overflow on `` - export `GraphiQLProps` type - allow `children: ReactNode` for `` - change `ToolbarMenu` component: - The `label` and `className` props were removed - The `button` prop should now be a button element - document `useGraphiQL` and `useGraphiQLActions` hooks in `@graphiql/react` README.md - rename `useThemeStore` to `useTheme` - [#3950](https://github.com/graphql/graphiql/pull/3950) [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - remove `useQueryEditor`, `useVariableEditor`, `useHeaderEditor`, `useResponseEditor` hooks - remove `UseHeaderEditorArgs`, `UseQueryEditorArgs`, `UseResponseEditorArgs`, `UseVariableEditorArgs` exports - rename components - `StorageContextProvider` => `StorageStore` - `EditorContextProvider` => `EditorStore` - `SchemaContextProvider` => `SchemaStore` - `ExecutionContextProvider` => `ExecutionStore` - `HistoryContextProvider` => `HistoryStore` - `ExplorerContextProvider` => `ExplorerStore` ### Patch Changes - [#3949](https://github.com/graphql/graphiql/pull/3949) [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - replace `onCopyQuery` hook with `copyQuery` function - replace `onMergeQuery` hook with `mergeQuery` function - replace `onPrettifyEditors` hook with `prettifyEditors` function - remove `fetcher` prop from `SchemaContextProvider` and `schemaStore` and add `fetcher` to `executionStore` - add `onCopyQuery` and `onPrettifyQuery` props to `EditorContextProvider` - remove exports (use `GraphiQLProvider`) - `EditorContextProvider` - `ExecutionContextProvider` - `PluginContextProvider` - `SchemaContextProvider` - `StorageContextProvider` - `ExecutionContextType` - `PluginContextType` - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - prefer `getComputedStyle` over `window.getComputedStyle` - [#4006](https://github.com/graphql/graphiql/pull/4006) [`7792dc9`](https://github.com/graphql/graphiql/commit/7792dc98814abcd6dc5f5cd94ae84c308a260dcf) Thanks [@dimaMachina](https://github.com/dimaMachina)! - push field type on stack too before field - [#4007](https://github.com/graphql/graphiql/pull/4007) [`f9780bd`](https://github.com/graphql/graphiql/commit/f9780bd44f67acad0a9bb10f57eb6059db60e1ec) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Use an additional `Alt` key for focus doc explorer search input instead of `Cmd/Ctrl+K` because monaco-editor has a built-in shortcut for `Cmd/Ctrl+K` - [#4004](https://github.com/graphql/graphiql/pull/4004) [`16fdd6a`](https://github.com/graphql/graphiql/commit/16fdd6a16684c9f250ee53ea2dfbb24435cee6a9) Thanks [@dimaMachina](https://github.com/dimaMachina)! - show spinner in doc explorer based on `isIntrospecting` value, and not based on `isFetching` - Updated dependencies [[`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92), [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e), [`866a8f3`](https://github.com/graphql/graphiql/commit/866a8f39a27d213315ccc55ec06353bb3280b270), [`4936492`](https://github.com/graphql/graphiql/commit/49364924d0da05a86f7c6c3139d44aed0e474531), [`3c0ad34`](https://github.com/graphql/graphiql/commit/3c0ad34a8f2f9d0f912db9597f608d7405c2bd83), [`1e3ec84`](https://github.com/graphql/graphiql/commit/1e3ec8455706e62e6cae306df58d3343ec6b612d), [`0c8e390`](https://github.com/graphql/graphiql/commit/0c8e3906cf58055f898cb173b2e912a494ae8439), [`0a08642`](https://github.com/graphql/graphiql/commit/0a0864268da4f340e30a1e9b8191d34e33ffbfa7), [`cff3da5`](https://github.com/graphql/graphiql/commit/cff3da541184d36d1c2e5c919dd4231e9905ccbb), [`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b), [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91), [`30bc3f9`](https://github.com/graphql/graphiql/commit/30bc3f9cae4dbb11649a0952dad092e192ad653c), [`4b39f11`](https://github.com/graphql/graphiql/commit/4b39f1118d008c2fac6e2df9c94a3f3271c4eeb9), [`7fb5ac3`](https://github.com/graphql/graphiql/commit/7fb5ac38b8ec27f0234adc06aacf42e71f6a259b), [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb)]: - @graphiql/react@0.35.0 ## 0.3.0-rc.4 ### Minor Changes - [#4025](https://github.com/graphql/graphiql/pull/4025) [`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - set "importsNotUsedAsValues": "error" in tsconfig - [#4026](https://github.com/graphql/graphiql/pull/4026) [`7fb5ac3`](https://github.com/graphql/graphiql/commit/7fb5ac38b8ec27f0234adc06aacf42e71f6a259b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - deprecate `useExplorerContext`, `useHistoryContext`, `usePrettifyEditors`, `useCopyQuery`, `useMergeQuery`, `useExecutionContext`, `usePluginContext`, `useSchemaContext`, `useStorageContext` hooks - fix response editor overflow on `` - export `GraphiQLProps` type - allow `children: ReactNode` for `` - change `ToolbarMenu` component: - The `label` and `className` props were removed - The `button` prop should now be a button element - document `useGraphiQL` and `useGraphiQLActions` hooks in `@graphiql/react` README.md - rename `useThemeStore` to `useTheme` ### Patch Changes - Updated dependencies [[`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b), [`7fb5ac3`](https://github.com/graphql/graphiql/commit/7fb5ac38b8ec27f0234adc06aacf42e71f6a259b)]: - @graphiql/react@0.35.0-rc.8 ## 0.3.0-rc.3 ### Minor Changes - [#4009](https://github.com/graphql/graphiql/pull/4009) [`4936492`](https://github.com/graphql/graphiql/commit/49364924d0da05a86f7c6c3139d44aed0e474531) Thanks [@dimaMachina](https://github.com/dimaMachina)! - separate store actions from state, add `useGraphiQLActions` state ### Patch Changes - Updated dependencies [[`4936492`](https://github.com/graphql/graphiql/commit/49364924d0da05a86f7c6c3139d44aed0e474531)]: - @graphiql/react@0.35.0-rc.3 ## 0.3.0-rc.2 ### Patch Changes - [#4006](https://github.com/graphql/graphiql/pull/4006) [`7792dc9`](https://github.com/graphql/graphiql/commit/7792dc98814abcd6dc5f5cd94ae84c308a260dcf) Thanks [@dimaMachina](https://github.com/dimaMachina)! - push field type on stack too before field - [#4007](https://github.com/graphql/graphiql/pull/4007) [`f9780bd`](https://github.com/graphql/graphiql/commit/f9780bd44f67acad0a9bb10f57eb6059db60e1ec) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Use an additional `Alt` key for focus doc explorer search input instead of `Cmd/Ctrl+K` because monaco-editor has a built-in shortcut for `Cmd/Ctrl+K` - [#4004](https://github.com/graphql/graphiql/pull/4004) [`16fdd6a`](https://github.com/graphql/graphiql/commit/16fdd6a16684c9f250ee53ea2dfbb24435cee6a9) Thanks [@dimaMachina](https://github.com/dimaMachina)! - show spinner in doc explorer based on `isIntrospecting` value, and not based on `isFetching` - Updated dependencies [[`866a8f3`](https://github.com/graphql/graphiql/commit/866a8f39a27d213315ccc55ec06353bb3280b270), [`1e3ec84`](https://github.com/graphql/graphiql/commit/1e3ec8455706e62e6cae306df58d3343ec6b612d), [`0c8e390`](https://github.com/graphql/graphiql/commit/0c8e3906cf58055f898cb173b2e912a494ae8439)]: - @graphiql/react@0.35.0-rc.2 ## 0.3.0-rc.1 ### Minor Changes - [#3990](https://github.com/graphql/graphiql/pull/3990) [`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - allow multiple independent instances of GraphiQL on the same page - store `onClickReference` in query editor in React `ref` - remove `onClickReference` from variable editor - fix shortcut text per OS for run query in execute query button's tooltip and in default query - allow override all default GraphiQL plugins - adjust operation argument color to be purple from GraphiQL v2 on dark/light theme ### Patch Changes - Updated dependencies [[`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92)]: - @graphiql/react@0.35.0-rc.1 ## 0.3.0-rc.0 ### Minor Changes - [#3234](https://github.com/graphql/graphiql/pull/3234) [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Migration from Codemirror to [Monaco Editor](https://github.com/microsoft/monaco-editor) Replacing `codemirror-graphql` with [`monaco-graphql`](https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql) Support for comments in **Variables** and **Headers** editors - [#3950](https://github.com/graphql/graphiql/pull/3950) [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - remove `useQueryEditor`, `useVariableEditor`, `useHeaderEditor`, `useResponseEditor` hooks - remove `UseHeaderEditorArgs`, `UseQueryEditorArgs`, `UseResponseEditorArgs`, `UseVariableEditorArgs` exports - rename components - `StorageContextProvider` => `StorageStore` - `EditorContextProvider` => `EditorStore` - `SchemaContextProvider` => `SchemaStore` - `ExecutionContextProvider` => `ExecutionStore` - `HistoryContextProvider` => `HistoryStore` - `ExplorerContextProvider` => `ExplorerStore` ### Patch Changes - [#3949](https://github.com/graphql/graphiql/pull/3949) [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - replace `onCopyQuery` hook with `copyQuery` function - replace `onMergeQuery` hook with `mergeQuery` function - replace `onPrettifyEditors` hook with `prettifyEditors` function - remove `fetcher` prop from `SchemaContextProvider` and `schemaStore` and add `fetcher` to `executionStore` - add `onCopyQuery` and `onPrettifyQuery` props to `EditorContextProvider` - remove exports (use `GraphiQLProvider`) - `EditorContextProvider` - `ExecutionContextProvider` - `PluginContextProvider` - `SchemaContextProvider` - `StorageContextProvider` - `ExecutionContextType` - `PluginContextType` - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - prefer `getComputedStyle` over `window.getComputedStyle` - Updated dependencies [[`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e), [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91), [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb)]: - @graphiql/react@0.35.0-rc.0 ## 0.2.2 ### Patch Changes - [#3970](https://github.com/graphql/graphiql/pull/3970) [`7054591`](https://github.com/graphql/graphiql/commit/70545912d1b3bb9e0c45e766a5c89896a9c4dfb7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - revert https://github.com/graphql/graphiql/pull/3946 to have support multiple embedded graphiql instances on the same page - Updated dependencies [[`7054591`](https://github.com/graphql/graphiql/commit/70545912d1b3bb9e0c45e766a5c89896a9c4dfb7)]: - @graphiql/react@0.34.1 ## 0.2.1 ### Patch Changes - [#3946](https://github.com/graphql/graphiql/pull/3946) [`71755b7`](https://github.com/graphql/graphiql/commit/71755b7f412f8f3dd9f5194d3f1e0168b9ad07af) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - replace `useAutoCompleteLeafs` hook with `getAutoCompleteLeafs` function - Updated dependencies [[`71755b7`](https://github.com/graphql/graphiql/commit/71755b7f412f8f3dd9f5194d3f1e0168b9ad07af), [`6d631e2`](https://github.com/graphql/graphiql/commit/6d631e2e558d038476fe235b1506bc52ecf68781)]: - @graphiql/react@0.34.0 ## 0.2.0 ### Minor Changes - [#3947](https://github.com/graphql/graphiql/pull/3947) [`fa78481`](https://github.com/graphql/graphiql/commit/fa784819ce020346052901019079fb5b44af6ef0) Thanks [@dimaMachina](https://github.com/dimaMachina)! - refactor `useStorage`, `useDocExplorer` and `useHistory` hooks ### Patch Changes - [#3945](https://github.com/graphql/graphiql/pull/3945) [`117627b`](https://github.com/graphql/graphiql/commit/117627b451607198dd7b9dc19e76da8a71d14b71) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand, replace `usePluginContext` with `usePluginStore` hook - [#3943](https://github.com/graphql/graphiql/pull/3943) [`7275472`](https://github.com/graphql/graphiql/commit/727547236bbd4fc721069ceae63eb8a6acffa57e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand, replace `useSchemaContext` with `useSchemaStore` hook - Updated dependencies [[`117627b`](https://github.com/graphql/graphiql/commit/117627b451607198dd7b9dc19e76da8a71d14b71), [`fa78481`](https://github.com/graphql/graphiql/commit/fa784819ce020346052901019079fb5b44af6ef0), [`7275472`](https://github.com/graphql/graphiql/commit/727547236bbd4fc721069ceae63eb8a6acffa57e), [`00c8605`](https://github.com/graphql/graphiql/commit/00c8605e1f3068e6547a5a9e969571a86a57f921)]: - @graphiql/react@0.33.0 ## 0.1.0 ### Minor Changes - [#3940](https://github.com/graphql/graphiql/pull/3940) [`5a66864`](https://github.com/graphql/graphiql/commit/5a668647e1cbca9e846bfa617f97fbae21c821bd) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/plugin-doc-explorer): migrate React context to zustand, replace `useExplorerContext` with `useDocExplorer` and `useDocExplorerActions` hooks ## 0.0.2 ### Patch Changes - [#3939](https://github.com/graphql/graphiql/pull/3939) [`69ad489`](https://github.com/graphql/graphiql/commit/69ad489678d0096432d5c4b1749d87343f4ed1f7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - prefer `React.FC` type when declaring React components - Updated dependencies [[`2bfbb06`](https://github.com/graphql/graphiql/commit/2bfbb06e416cabc46951a137b61a12a571f0c937), [`69ad489`](https://github.com/graphql/graphiql/commit/69ad489678d0096432d5c4b1749d87343f4ed1f7), [`2500288`](https://github.com/graphql/graphiql/commit/250028863f6eefe4167ff9f9c23168ccf0a85b7b)]: - @graphiql/react@0.32.2 ## 0.0.1 ### Patch Changes - [#3916](https://github.com/graphql/graphiql/pull/3916) [`98d13a3`](https://github.com/graphql/graphiql/commit/98d13a3e515eb70aaf5a5ba669c680d5959fef67) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - remove the following exports from `@graphiql/react` and move them in `@graphiql/plugin-doc-explorer` package: - Argument - DefaultValue - DeprecationReason - Directive - DocExplorer - ExplorerContext - ExplorerContextProvider - ExplorerSection - FieldDocumentation - FieldLink - SchemaDocumentation - Search - TypeDocumentation - TypeLink - useExplorerContext - DOC_EXPLORER_PLUGIN - ExplorerContextType - ExplorerFieldDef - ExplorerNavStack - ExplorerNavStackItem - add new `referencePlugin` prop on `PluginContextProviderProps` component for plugin which is used to display the reference documentation when selecting a type. - Updated dependencies [[`98d13a3`](https://github.com/graphql/graphiql/commit/98d13a3e515eb70aaf5a5ba669c680d5959fef67)]: - @graphiql/react@0.32.0 ================================================ FILE: packages/graphiql-plugin-doc-explorer/README.md ================================================ # `@graphiql/plugin-doc-explorer` ## API - `useDocExplorer`: Handles the state for the doc explorer - `useDocExplorerActions`: Actions related to the doc explorer ================================================ FILE: packages/graphiql-plugin-doc-explorer/package.json ================================================ { "name": "@graphiql/plugin-doc-explorer", "version": "0.4.1", "sideEffects": false, "repository": { "type": "git", "url": "https://github.com/graphql/graphiql", "directory": "packages/graphiql-plugin-doc-explorer" }, "homepage": "https://github.com/graphql/graphiql/tree/master/packages/graphiql-plugin-doc-explorer#readme", "bugs": { "url": "https://github.com/graphql/graphiql/issues?q=issue+label:@graphiql/plugin-doc-explorer" }, "license": "MIT", "exports": { "./package.json": "./package.json", "./style.css": "./dist/style.css", ".": "./dist/index.js" }, "types": "dist/index.d.ts", "keywords": [ "react", "graphql", "graphiql", "plugin", "documentation", "explorer" ], "files": [ "dist" ], "scripts": { "types:check": "tsc --noEmit", "dev": "vite build --watch --emptyOutDir=false", "build": "vite build", "test": "vitest" }, "peerDependencies": { "@graphiql/react": "^0.37.0", "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", "react": "^18 || ^19", "react-compiler-runtime": "19.1.0-rc.1", "react-dom": "^18 || ^19" }, "dependencies": { "@headlessui/react": "^2.2", "zustand": "^5" }, "devDependencies": { "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.3.0", "@vitejs/plugin-react": "^4.4.1", "babel-plugin-react-compiler": "19.1.0-rc.1", "graphql": "^16.9.0", "react": "^19.1.0", "react-dom": "^19.1.0", "vite": "^6.3.4", "vite-plugin-dts": "^4.5.3" } } ================================================ FILE: packages/graphiql-plugin-doc-explorer/setup-files.ts ================================================ 'use no memo'; import '@testing-library/jest-dom'; // to make it works like Jest (auto-mocking) vi.mock('zustand'); vi.mock('monaco-editor'); ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/__tests__/doc-explorer.spec.tsx ================================================ import type { Mock } from 'vitest'; import { useGraphiQL as $useGraphiQL } from '@graphiql/react'; import { render } from '@testing-library/react'; import { GraphQLInt, GraphQLObjectType, GraphQLSchema } from 'graphql'; import { FC, useEffect } from 'react'; import { DocExplorerStore, useDocExplorer, useDocExplorerActions, } from '../../context'; import { DocExplorer } from '../doc-explorer'; const useGraphiQL = $useGraphiQL as Mock; vi.mock('@graphiql/react', async () => { const originalModule = await vi.importActual('@graphiql/react'); return { ...originalModule, useGraphiQL: vi.fn(), }; }); function makeSchema(fieldName = 'field') { return new GraphQLSchema({ description: 'GraphQL Schema for testing', query: new GraphQLObjectType({ name: 'Query', fields: { [fieldName]: { type: GraphQLInt, args: { arg: { type: GraphQLInt, }, }, }, }, }), }); } const defaultSchemaContext = { introspect() {}, schema: makeSchema(), validationErrors: [], }; const withErrorSchemaContext = { ...defaultSchemaContext, fetchError: 'Error fetching schema', schema: new GraphQLSchema({ description: 'GraphQL Schema for testing' }), }; const DocExplorerWithContext: FC = () => { return ( ); }; describe('DocExplorer', () => { beforeEach(() => { vi.resetModules(); }); it('renders spinner when the schema is loading', () => { useGraphiQL.mockImplementation(cb => cb({ ...defaultSchemaContext, isIntrospecting: true }), ); const { container } = render(); const spinner = container.querySelectorAll('.graphiql-spinner'); expect(spinner).toHaveLength(1); }); it('renders with null schema', () => { useGraphiQL.mockImplementation(cb => cb({ ...defaultSchemaContext, schema: null }), ); const { container } = render(); const error = container.querySelectorAll('.graphiql-doc-explorer-error'); expect(error).toHaveLength(1); expect(error[0]).toHaveTextContent('No GraphQL schema available'); }); it('renders with schema', () => { useGraphiQL.mockImplementation(cb => cb(defaultSchemaContext)); const { container } = render(); const error = container.querySelectorAll('.graphiql-doc-explorer-error'); expect(error).toHaveLength(0); expect( container.querySelector('.graphiql-markdown-description'), ).toHaveTextContent('GraphQL Schema for testing'); }); it('renders correctly with schema error', () => { useGraphiQL.mockImplementation(cb => cb(withErrorSchemaContext)); const { rerender, container } = render(); const error = container.querySelector('.graphiql-doc-explorer-error'); expect(error).toHaveTextContent('Error fetching schema'); useGraphiQL.mockImplementation(cb => cb(defaultSchemaContext)); rerender(); const errors = container.querySelectorAll('.graphiql-doc-explorer-error'); expect(errors).toHaveLength(0); }); it('maintains nav stack when possible', () => { const initialSchema = makeSchema(); const Query = initialSchema.getType('Query'); const { field } = (Query as GraphQLObjectType).getFields(); // A hacky component to set the initial explorer nav stack const SetInitialStack: React.FC = () => { const explorerNavStack = useDocExplorer(); const { push } = useDocExplorerActions(); useEffect(() => { if (explorerNavStack.length === 1) { push({ name: 'Query', def: Query }); push({ name: 'field', def: field }); } }, [explorerNavStack.length, push]); return null; }; // Initial render, set initial state useGraphiQL.mockImplementation(cb => cb({ ...defaultSchemaContext, schema: initialSchema }), ); const { container, rerender } = render( , ); // First proper render of doc explorer rerender( , ); const title = container.querySelector('.graphiql-doc-explorer-title')!; expect(title.textContent).toEqual('field'); // Second render of doc explorer, this time with a new schema, with _same_ field name useGraphiQL.mockImplementation(cb => cb({ ...defaultSchemaContext, schema: makeSchema(), // <<< New, but equivalent, schema }), ); rerender( , ); const title2 = container.querySelector('.graphiql-doc-explorer-title')!; // Because `Query.field` still exists in the new schema, we can still render it expect(title2.textContent).toEqual('field'); }); it('trims nav stack when necessary', () => { const initialSchema = makeSchema(); const Query = initialSchema.getType('Query'); const { field } = (Query as GraphQLObjectType).getFields(); // A hacky component to set the initial explorer nav stack // eslint-disable-next-line sonarjs/no-identical-functions -- todo: could be refactored const SetInitialStack: React.FC = () => { const explorerNavStack = useDocExplorer(); const { push } = useDocExplorerActions(); useEffect(() => { if (explorerNavStack.length === 1) { push({ name: 'Query', def: Query }); push({ name: 'field', def: field }); } }, [explorerNavStack.length, push]); return null; }; // Initial render, set initial state useGraphiQL.mockImplementation(cb => cb({ ...defaultSchemaContext, schema: initialSchema }), ); const { container, rerender } = render( , ); // First proper render of doc explorer rerender( , ); const title = container.querySelector('.graphiql-doc-explorer-title')!; expect(title.textContent).toEqual('field'); // Second render of doc explorer, this time with a new schema, with a different field name useGraphiQL.mockImplementation(cb => cb({ ...defaultSchemaContext, schema: makeSchema('field2'), // <<< New schema with a new field name }), ); rerender( , ); const title2 = container.querySelector('.graphiql-doc-explorer-title')!; // Because `Query.field` doesn't exist anymore, the top-most item we can render is `Query` expect(title2.textContent).toEqual('Query'); }); }); ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/__tests__/field-documentation.spec.tsx ================================================ import { FC, useEffect } from 'react'; import { fireEvent, render } from '@testing-library/react'; import { GraphQLString, GraphQLObjectType, Kind } from 'graphql'; import { DocExplorerFieldDef, docExplorerStore } from '../../context'; import { FieldDocumentation } from '../field-documentation'; const exampleObject = new GraphQLObjectType({ name: 'Query', fields: { string: { type: GraphQLString, }, stringWithArgs: { type: GraphQLString, description: 'Example String field with arguments', args: { stringArg: { type: GraphQLString, }, deprecatedStringArg: { type: GraphQLString, deprecationReason: 'no longer used', }, }, }, stringWithDirective: { type: GraphQLString, astNode: { kind: Kind.FIELD_DEFINITION, name: { kind: Kind.NAME, value: 'stringWithDirective', }, type: { kind: Kind.NAMED_TYPE, name: { kind: Kind.NAME, value: 'GraphQLString', }, }, directives: [ { kind: Kind.DIRECTIVE, name: { kind: Kind.NAME, value: 'development', }, }, ], }, }, }, }); const FieldDocumentationWithContext: FC<{ field: DocExplorerFieldDef; }> = ({ field }) => { useEffect(() => { docExplorerStore.setState({ explorerNavStack: [ { name: field.name, def: field, }, ], }); }, [field]); return ; }; describe('FieldDocumentation', () => { it('should render a simple string field', () => { const { container } = render( , ); expect( container.querySelector('.graphiql-markdown-description'), ).not.toBeInTheDocument(); expect( container.querySelector('.graphiql-doc-explorer-type-name'), ).toHaveTextContent('String'); expect( container.querySelector('.graphiql-doc-explorer-argument'), ).not.toBeInTheDocument(); }); it('should re-render on field change', () => { const { container, rerender } = render( , ); expect( container.querySelector('.graphiql-markdown-description'), ).not.toBeInTheDocument(); expect( container.querySelector('.graphiql-doc-explorer-type-name'), ).toHaveTextContent('String'); expect( container.querySelector('.graphiql-doc-explorer-argument'), ).not.toBeInTheDocument(); rerender( , ); expect( container.querySelector('.graphiql-doc-explorer-type-name'), ).toHaveTextContent('String'); expect( container.querySelector('.graphiql-markdown-description'), ).toHaveTextContent('Example String field with arguments'); }); it('should render a string field with arguments', () => { const { container, getByText } = render( , ); expect( container.querySelector('.graphiql-doc-explorer-type-name'), ).toHaveTextContent('String'); expect( container.querySelector('.graphiql-markdown-description'), ).toHaveTextContent('Example String field with arguments'); expect( container.querySelectorAll('.graphiql-doc-explorer-argument'), ).toHaveLength(1); expect( container.querySelector('.graphiql-doc-explorer-argument'), ).toHaveTextContent('stringArg: String'); // by default, the deprecation docs should be hidden expect( container.querySelectorAll('.graphiql-markdown-deprecation'), ).toHaveLength(0); // make sure deprecation is present fireEvent.click(getByText('Show Deprecated Arguments')); const deprecationDocs = container.querySelectorAll( '.graphiql-markdown-deprecation', ); expect(deprecationDocs).toHaveLength(1); expect(deprecationDocs[0]).toHaveTextContent('no longer used'); }); it('should render a string field with directives', () => { const { container } = render( , ); expect( container.querySelector('.graphiql-doc-explorer-type-name'), ).toHaveTextContent('String'); expect( container.querySelector('.graphiql-doc-explorer-directive'), ).toHaveTextContent('@development'); }); }); ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/__tests__/fixtures.ts ================================================ import { GraphQLBoolean, GraphQLEnumType, GraphQLInterfaceType, GraphQLObjectType, GraphQLSchema, GraphQLString, GraphQLUnionType, } from 'graphql'; const ExampleInterface = new GraphQLInterfaceType({ name: 'exampleInterface', fields: { name: { type: GraphQLString }, }, }); export const ExampleEnum = new GraphQLEnumType({ name: 'exampleEnum', values: { value1: { value: 'Value 1' }, value2: { value: 'Value 2' }, value3: { value: 'Value 3', deprecationReason: 'Only two are needed' }, }, }); const ExampleUnionType1 = new GraphQLObjectType({ name: 'Union_Type_1', interfaces: [ExampleInterface], fields: { name: { type: GraphQLString }, enum: { type: ExampleEnum }, }, }); const ExampleUnionType2 = new GraphQLObjectType({ name: 'Union_Type_2', interfaces: [ExampleInterface], fields: { name: { type: GraphQLString }, string: { type: GraphQLString }, }, }); export const ExampleUnion = new GraphQLUnionType({ name: 'exampleUnion', types: [ExampleUnionType1, ExampleUnionType2], }); export const ExampleQuery = new GraphQLObjectType({ name: 'Query', description: 'Query description\n Second line', fields: { string: { type: GraphQLString }, union: { type: ExampleUnion }, fieldWithArgs: { type: GraphQLString, args: { stringArg: { type: GraphQLString }, }, }, deprecatedField: { type: GraphQLBoolean, deprecationReason: 'example deprecation reason', }, }, }); export const ExampleSchema = new GraphQLSchema({ query: ExampleQuery, description: 'GraphQL Schema for testing', }); ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/__tests__/test-utils.ts ================================================ 'use no memo'; import type { GraphQLNamedType, GraphQLType } from 'graphql'; export function unwrapType(type: GraphQLType): GraphQLNamedType { return 'ofType' in type ? unwrapType(type.ofType) : type; } ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/__tests__/type-documentation.spec.tsx ================================================ import { FC, useEffect } from 'react'; import { fireEvent, render } from '@testing-library/react'; import type { GraphQLNamedType } from 'graphql'; import { ExampleSchema, ExampleEnum, ExampleUnion, ExampleQuery, } from './fixtures'; import { docExplorerStore } from '../../context'; import { TypeDocumentation } from '../type-documentation'; import { unwrapType } from './test-utils'; import type { SlicesWithActions } from '@graphiql/react'; vi.mock('@graphiql/react', async () => { const originalModule = await vi.importActual('@graphiql/react'); const useGraphiQL: (typeof originalModule)['useGraphiQL'] = cb => cb({ schema: ExampleSchema } as SlicesWithActions); return { ...originalModule, useGraphiQL, }; }); const TypeDocumentationWithContext: FC<{ type: GraphQLNamedType }> = ({ type, }) => { useEffect(() => { docExplorerStore.setState({ explorerNavStack: [ { name: unwrapType(type).name, def: type, }, ], }); }, [type]); return ; }; describe('TypeDocumentation', () => { it('renders a top-level query object type', () => { const { container } = render( , ); const description = container.querySelectorAll( '.graphiql-markdown-description', ); expect(description).toHaveLength(1); expect(description[0]).toHaveTextContent('Query description\nSecond line', { normalizeWhitespace: false, }); const cats = container.querySelectorAll('.graphiql-doc-explorer-item'); expect(cats[0]).toHaveTextContent('string: String'); expect(cats[1]).toHaveTextContent('union: exampleUnion'); expect(cats[2]).toHaveTextContent( 'fieldWithArgs(stringArg: String): String', ); }); it('renders deprecated fields when you click to see them', () => { const { container, getByText } = render( , ); let cats = container.querySelectorAll('.graphiql-doc-explorer-item'); expect(cats).toHaveLength(3); fireEvent.click(getByText('Show Deprecated Fields')); cats = container.querySelectorAll('.graphiql-doc-explorer-item'); expect(cats).toHaveLength(4); expect( container.querySelectorAll('.graphiql-doc-explorer-field-name')[3], ).toHaveTextContent('deprecatedField'); expect( container.querySelector('.graphiql-markdown-deprecation'), ).toHaveTextContent('example deprecation reason'); }); it('renders a Union type', () => { const { container } = render( , ); const title = container.querySelector( '.graphiql-doc-explorer-section-title', )!; title.childNodes[0]!.remove(); expect(title).toHaveTextContent('Possible Types'); }); it('renders an Enum type', () => { const { container } = render( , ); const title = container.querySelector( '.graphiql-doc-explorer-section-title', )!; title.childNodes[0]!.remove(); expect(title).toHaveTextContent('Enum Values'); const enums = container.querySelectorAll( '.graphiql-doc-explorer-enum-value', ); expect(enums[0]).toHaveTextContent('value1'); expect(enums[1]).toHaveTextContent('value2'); }); it('shows deprecated enum values on click', () => { const { getByText, container } = render( , ); const showBtn = getByText('Show Deprecated Values'); expect(showBtn).toBeInTheDocument(); const title = container.querySelector( '.graphiql-doc-explorer-section-title', )!; title.childNodes[0]!.remove(); expect(title).toHaveTextContent('Enum Values'); let enums = container.querySelectorAll('.graphiql-doc-explorer-enum-value'); expect(enums).toHaveLength(2); // click button to show deprecated enum values fireEvent.click(showBtn); expect(showBtn).not.toBeInTheDocument(); const deprecatedTitle = container.querySelectorAll( '.graphiql-doc-explorer-section-title', )[1]!; deprecatedTitle.childNodes[0]!.remove(); expect(deprecatedTitle).toHaveTextContent('Deprecated Enum Values'); enums = container.querySelectorAll('.graphiql-doc-explorer-enum-value'); expect(enums).toHaveLength(3); expect(enums[2]).toHaveTextContent('value3'); expect( container.querySelector('.graphiql-markdown-deprecation'), ).toHaveTextContent('Only two are needed'); }); }); ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/__tests__/type-link.spec.tsx ================================================ import { FC, useEffect } from 'react'; import { fireEvent, render } from '@testing-library/react'; import { GraphQLNonNull, GraphQLList, GraphQLString } from 'graphql'; import { docExplorerStore, useDocExplorer } from '../../context'; import { TypeLink } from '../type-link'; import { unwrapType } from './test-utils'; const nonNullType = new GraphQLNonNull(GraphQLString); const listType = new GraphQLList(GraphQLString); const TypeLinkConsumer: FC = () => { const explorerNavStack = useDocExplorer(); return ( {JSON.stringify(explorerNavStack[explorerNavStack.length + 1])} ); }; const TypeLinkWithContext: typeof TypeLink = ({ type }) => { useEffect(() => { docExplorerStore.setState({ explorerNavStack: [ { name: unwrapType(type).name, def: unwrapType(type), }, ], }); }, [type]); return ( <> {/* Print the top of the current nav stack for test assertions */} ); }; describe('TypeLink', () => { it('should render a string', () => { const { container } = render(); expect(container).toHaveTextContent('String'); expect(container.querySelectorAll('a')).toHaveLength(1); }); it('should render a non-null type', () => { const { container } = render(); expect(container).toHaveTextContent('String!'); expect(container.querySelectorAll('span')).toHaveLength(1); }); it('should render a list type', () => { const { container } = render(); expect(container).toHaveTextContent('[String]'); expect(container.querySelectorAll('span')).toHaveLength(1); }); it('should push to the nav stack on click', () => { const { container, getByTestId } = render( , ); fireEvent.click(container.querySelector('a')!); expect(getByTestId('nav-stack')).toHaveTextContent(''); }); it('should re-render on type change', () => { const { container, rerender } = render( , ); expect(container).toHaveTextContent('[String]'); rerender(); expect(container).toHaveTextContent('String'); }); }); ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/argument.css ================================================ .graphiql-doc-explorer-argument { & > * + * { margin-top: var(--px-12); } } .graphiql-doc-explorer-argument-name { color: hsl(var(--color-secondary)); } .graphiql-doc-explorer-argument-deprecation { background-color: hsla(var(--color-warning), var(--alpha-background-light)); border: 1px solid hsl(var(--color-warning)); border-radius: var(--border-radius-4); color: hsl(var(--color-warning)); padding: var(--px-8); } .graphiql-doc-explorer-argument-deprecation-label { font-size: var(--font-size-hint); font-weight: var(--font-weight-medium); } ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/argument.tsx ================================================ import type { FC } from 'react'; import type { GraphQLArgument } from 'graphql'; import { MarkdownContent } from '@graphiql/react'; import { DefaultValue } from './default-value'; import { TypeLink } from './type-link'; import './argument.css'; type ArgumentProps = { /** * The argument that should be rendered. */ arg: GraphQLArgument; /** * Toggle if the default value for the argument is shown (if there is one) * @default false */ showDefaultValue?: boolean; /** * Toggle whether to render the whole argument including description and * deprecation reason (`false`) or to just render the argument name, type, * and default value in a single line (`true`). * @default false */ inline?: boolean; }; export const Argument: FC = ({ arg, showDefaultValue, inline, }) => { const definition = ( {arg.name} {': '} {showDefaultValue !== false && } ); if (inline) { return definition; } return (
{definition} {arg.description ? ( {arg.description} ) : null} {arg.deprecationReason ? (
Deprecated
{arg.deprecationReason}
) : null}
); }; ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/default-value.css ================================================ .graphiql-doc-explorer-default-value { color: hsl(var(--color-success)); } ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/default-value.tsx ================================================ import type { FC } from 'react'; import { astFromValue, print, ValueNode } from 'graphql'; import type { DocExplorerFieldDef } from '../context'; import './default-value.css'; const printDefault = (ast?: ValueNode | null): string => { if (!ast) { return ''; } return print(ast); }; type DefaultValueProps = { /** * The field or argument for which to render the default value. */ field: DocExplorerFieldDef; }; export const DefaultValue: FC = ({ field }) => { if (!('defaultValue' in field) || field.defaultValue === undefined) { return null; } const ast = astFromValue(field.defaultValue, field.type); if (!ast) { return null; } return ( <> {' = '} {printDefault(ast)} ); }; ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/deprecation-reason.css ================================================ .graphiql-doc-explorer-deprecation { background-color: hsla(var(--color-warning), var(--alpha-background-light)); border: 1px solid hsl(var(--color-warning)); border-radius: var(--px-4); color: hsl(var(--color-warning)); padding: var(--px-8); } .graphiql-doc-explorer-deprecation-label { font-size: var(--font-size-hint); font-weight: var(--font-weight-medium); } ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/deprecation-reason.tsx ================================================ import type { FC } from 'react'; import { MarkdownContent } from '@graphiql/react'; import './deprecation-reason.css'; type DeprecationReasonProps = { /** * The deprecation reason as Markdown string. */ children?: string | null; preview?: boolean; }; export const DeprecationReason: FC = props => { return props.children ? (
Deprecated
{props.children}
) : null; }; ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/directive.css ================================================ .graphiql-doc-explorer-directive { color: hsl(var(--color-secondary)); } ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/directive.tsx ================================================ import type { FC } from 'react'; import type { DirectiveNode } from 'graphql'; import './directive.css'; type DirectiveProps = { /** * The directive that should be rendered. */ directive: DirectiveNode; }; export const Directive: FC = ({ directive }) => { return ( @{directive.name.value} ); }; ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/doc-explorer.css ================================================ /* The header of the doc explorer */ .graphiql-doc-explorer-header { display: flex; justify-content: space-between; position: relative; &:focus-within { & .graphiql-doc-explorer-title { /* Hide the header when focussing the search input */ visibility: hidden; } & .graphiql-doc-explorer-back:not(:focus) { /** * Make the back link invisible when focussing the search input. Hiding * it in any other way makes it impossible to focus the link by pressing * Shift-Tab while the input is focussed. */ color: transparent; } } } .graphiql-doc-explorer-header-content { display: flex; flex-direction: column; min-width: 0; } /* The search input in the header of the doc explorer */ .graphiql-doc-explorer-search { position: absolute; right: 0; top: 0; &:focus-within { left: 0; } &:not(:focus-within) [role='combobox'] { height: 24px; width: 6.5ch; } & [role='combobox']:focus { width: 100%; } } /* The back-button in the doc explorer */ a.graphiql-doc-explorer-back { align-items: center; color: hsla(var(--color-neutral), var(--alpha-secondary)); display: flex; text-decoration: none; &:hover { text-decoration: underline; } &:focus { outline: hsla(var(--color-neutral), var(--alpha-secondary)) auto 1px; & + .graphiql-doc-explorer-title { /* Don't hide the header when focussing the back link */ visibility: unset; } } & > svg { height: var(--px-8); margin-right: var(--px-8); width: var(--px-8); } } /* The title of the currently active page in the doc explorer */ .graphiql-doc-explorer-title { font-weight: var(--font-weight-medium); font-size: var(--font-size-h2); overflow-x: hidden; text-overflow: ellipsis; white-space: nowrap; &:not(:first-child) { font-size: var(--font-size-h3); margin-top: var(--px-8); } } /* The contents of the currently active page in the doc explorer */ .graphiql-doc-explorer-content > * { color: hsla(var(--color-neutral), var(--alpha-secondary)); margin-top: var(--px-20); } /* Error message */ .graphiql-doc-explorer-error { background-color: hsla(var(--color-error), var(--alpha-background-heavy)); border: 1px solid hsl(var(--color-error)); border-radius: var(--border-radius-8); color: hsl(var(--color-error)); padding: var(--px-8) var(--px-12); } ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/doc-explorer.tsx ================================================ import { isType } from 'graphql'; import type { FC, ReactNode } from 'react'; import { ChevronLeftIcon, Spinner, useGraphiQL, pick } from '@graphiql/react'; import { useDocExplorer, useDocExplorerActions } from '../context'; import { FieldDocumentation } from './field-documentation'; import { SchemaDocumentation } from './schema-documentation'; import { Search } from './search'; import { TypeDocumentation } from './type-documentation'; import './doc-explorer.css'; export const DocExplorer: FC = () => { const { fetchError, isIntrospecting, schema, validationErrors } = useGraphiQL( pick('fetchError', 'isIntrospecting', 'schema', 'validationErrors'), ); const explorerNavStack = useDocExplorer(); const { pop } = useDocExplorerActions(); const navItem = explorerNavStack.at(-1)!; let content: ReactNode = null; if (fetchError) { content = (
Error fetching schema
); } else if (validationErrors[0]) { content = (
Schema is invalid: {validationErrors[0].message}
); } else if (isIntrospecting) { // Schema is undefined when it is being loaded via introspection. content = ; } else if (!schema) { // Schema is null when it explicitly does not exist, typically due to // an error during introspection. content = (
No GraphQL schema available
); } else if (explorerNavStack.length === 1) { content = ; } else if (isType(navItem.def)) { content = ; } else if (navItem.def) { content = ; } let prevName; if (explorerNavStack.length > 1) { prevName = explorerNavStack.at(-2)!.name; } return (
{content}
); }; ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/field-documentation.tsx ================================================ import type { GraphQLArgument } from 'graphql'; import { FC, useState } from 'react'; import { Button, MarkdownContent } from '@graphiql/react'; import type { DocExplorerFieldDef } from '../context'; import { Argument } from './argument'; import { DeprecationReason } from './deprecation-reason'; import { Directive } from './directive'; import { ExplorerSection } from './section'; import { TypeLink } from './type-link'; type FieldDocumentationProps = { /** * The field or argument that should be rendered. */ field: DocExplorerFieldDef; }; export const FieldDocumentation: FC = ({ field }) => { return ( <> {field.description ? ( {field.description} ) : null} {field.deprecationReason} ); }; const Arguments: FC<{ field: DocExplorerFieldDef }> = ({ field }) => { const [showDeprecated, setShowDeprecated] = useState(false); const handleShowDeprecated = () => { setShowDeprecated(true); }; if (!('args' in field)) { return null; } const args: GraphQLArgument[] = []; const deprecatedArgs: GraphQLArgument[] = []; for (const argument of field.args) { if (argument.deprecationReason) { deprecatedArgs.push(argument); } else { args.push(argument); } } return ( <> {args.length > 0 ? ( {args.map(arg => ( ))} ) : null} {deprecatedArgs.length > 0 ? ( showDeprecated || args.length === 0 ? ( {deprecatedArgs.map(arg => ( ))} ) : ( ) ) : null} ); }; const Directives: FC<{ field: DocExplorerFieldDef }> = ({ field }) => { const directives = field.astNode?.directives; if (!directives?.length) { return null; } return ( {directives.map(directive => (
))}
); }; ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/field-link.css ================================================ a.graphiql-doc-explorer-field-name { color: hsl(var(--color-info)); text-decoration: none; &:hover { text-decoration: underline; } &:focus { outline: hsl(var(--color-info)) auto 1px; } } ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/field-link.tsx ================================================ import type { FC } from 'react'; import { DocExplorerFieldDef, useDocExplorerActions } from '../context'; import './field-link.css'; type FieldLinkProps = { /** * The field or argument that should be linked to. */ field: DocExplorerFieldDef; }; export const FieldLink: FC = ({ field }) => { const { push } = useDocExplorerActions(); return ( { event.preventDefault(); push({ name: field.name, def: field }); }} href="#" > {field.name} ); }; ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/index.ts ================================================ export { Argument } from './argument'; export { DefaultValue } from './default-value'; export { DeprecationReason } from './deprecation-reason'; export { Directive } from './directive'; export { DocExplorer } from './doc-explorer'; export { FieldDocumentation } from './field-documentation'; export { FieldLink } from './field-link'; export { SchemaDocumentation } from './schema-documentation'; export { Search } from './search'; export { ExplorerSection } from './section'; export { TypeDocumentation } from './type-documentation'; export { TypeLink } from './type-link'; ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/schema-documentation.css ================================================ .graphiql-doc-explorer-root-type { color: hsl(var(--color-info)); } ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/schema-documentation.tsx ================================================ import type { FC } from 'react'; import type { GraphQLSchema } from 'graphql'; import { MarkdownContent } from '@graphiql/react'; import { ExplorerSection } from './section'; import { TypeLink } from './type-link'; import './schema-documentation.css'; type SchemaDocumentationProps = { /** * The schema that should be rendered. */ schema: GraphQLSchema; }; export const SchemaDocumentation: FC = ({ schema, }) => { const queryType = schema.getQueryType(); const mutationType = schema.getMutationType(); const subscriptionType = schema.getSubscriptionType(); const typeMap = schema.getTypeMap(); const ignoreTypesInAllSchema = [ queryType?.name, mutationType?.name, subscriptionType?.name, ]; return ( <> {schema.description || 'A GraphQL schema provides a root type for each kind of operation.'} {queryType ? (
query {': '}
) : null} {mutationType && (
mutation {': '}
)} {subscriptionType && (
subscription {': '}
)}
{Object.values(typeMap).map(type => { if ( ignoreTypesInAllSchema.includes(type.name) || type.name.startsWith('__') ) { return null; } return (
); })}
); }; ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/search.css ================================================ .graphiql-doc-explorer-search { color: hsla(var(--color-neutral), var(--alpha-secondary)); &:not([data-state='idle']) { border: var(--popover-border); border-radius: var(--border-radius-4); box-shadow: var(--popover-box-shadow); color: hsl(var(--color-neutral)); & .graphiql-doc-explorer-search-input { background: hsl(var(--color-base)); } } } .graphiql-doc-explorer-search-input { align-items: center; background-color: hsla(var(--color-neutral), var(--alpha-background-light)); border-radius: var(--border-radius-4); display: flex; padding: var(--px-8) var(--px-12); } .graphiql-doc-explorer-search [role='combobox'] { border: none; background-color: transparent; margin-left: var(--px-4); width: 100%; &:focus { outline: none; } } .graphiql-doc-explorer-search [role='listbox'] { background-color: hsl(var(--color-base)); border: none; border-bottom-left-radius: var(--border-radius-4); border-bottom-right-radius: var(--border-radius-4); border-top: 1px solid hsla(var(--color-neutral), var(--alpha-background-heavy)); max-height: 400px; overflow-y: auto; margin: 0; font-size: var(--font-size-body); padding: var(--px-4); /** * This makes sure that the logic for auto-scrolling the search results when * using keyboard navigation works properly (we use `offsetTop` there). */ position: relative; } .graphiql-doc-explorer-search [role='option'] { border-radius: var(--border-radius-4); color: hsla(var(--color-neutral), var(--alpha-secondary)); overflow-x: hidden; padding: var(--px-8) var(--px-12); text-overflow: ellipsis; white-space: nowrap; cursor: pointer; &[data-headlessui-state='active'] { background-color: hsla(var(--color-neutral), var(--alpha-background-light)); } &:hover { background-color: hsla( var(--color-neutral), var(--alpha-background-medium) ); } &[data-headlessui-state='active']:hover { background-color: hsla(var(--color-neutral), var(--alpha-background-heavy)); } & + & { margin-top: var(--px-4); } } .graphiql-doc-explorer-search-type { color: hsl(var(--color-info)); } .graphiql-doc-explorer-search-field { color: hsl(var(--color-warning)); } .graphiql-doc-explorer-search-argument { color: hsl(var(--color-secondary)); } .graphiql-doc-explorer-search-divider { color: hsla(var(--color-neutral), var(--alpha-secondary)); font-size: var(--font-size-hint); font-weight: var(--font-weight-medium); margin-top: var(--px-8); padding: var(--px-8) var(--px-12); } .graphiql-doc-explorer-search-empty { color: hsla(var(--color-neutral), var(--alpha-secondary)); padding: var(--px-8) var(--px-12); } ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/search.tsx ================================================ import { GraphQLArgument, GraphQLField, GraphQLInputField, GraphQLNamedType, isInputObjectType, isInterfaceType, isObjectType, } from 'graphql'; import { FC, useEffect, useRef, useState } from 'react'; import { Combobox, ComboboxInput, ComboboxOptions, ComboboxOption, } from '@headlessui/react'; import { formatShortcutForOS, useGraphiQL, MagnifyingGlassIcon, debounce, KEY_MAP, } from '@graphiql/react'; import { useDocExplorer, useDocExplorerActions } from '../context'; import { renderType } from './utils'; import './search.css'; export const Search: FC = () => { const explorerNavStack = useDocExplorer(); const { push } = useDocExplorerActions(); const inputRef = useRef(null!); const getSearchResults = useSearchResults(); const [searchValue, setSearchValue] = useState(''); const [results, setResults] = useState(() => getSearchResults(searchValue)); const debouncedGetSearchResults = debounce(200, (search: string) => { setResults(getSearchResults(search)); }); // Workaround to fix React compiler error: // Ref values (the `current` property) may not be accessed during render. const [ref] = useState(inputRef); const isFocused = ref.current === document.activeElement; useEffect(() => { debouncedGetSearchResults(searchValue); }, [debouncedGetSearchResults, searchValue]); const navItem = explorerNavStack.at(-1)!; const onSelect = (def: TypeMatch | FieldMatch | null) => { // `null` when we remove search value if (!def) { return; } push( 'field' in def ? { name: def.field.name, def: def.field } : { name: def.type.name, def: def.type }, ); }; const shouldSearchBoxAppear = explorerNavStack.length === 1 || isObjectType(navItem.def) || isInterfaceType(navItem.def) || isInputObjectType(navItem.def); if (!shouldSearchBoxAppear) { return null; } return (
{ inputRef.current.focus(); }} > setSearchValue(event.target.value)} placeholder={formatShortcutForOS( formatShortcutForOS(KEY_MAP.searchInDocs.key).replaceAll('-', ' '), )} ref={inputRef} value={searchValue} data-cy="doc-explorer-input" />
{isFocused && ( {results.within.length + results.types.length + results.fields.length === 0 ? (
No results found
) : ( results.within.map((result, i) => ( )) )} {results.within.length > 0 && results.types.length + results.fields.length > 0 ? (
Other results
) : null} {results.types.map((result, i) => ( ))} {results.fields.map((result, i) => ( . ))}
)}
); }; type TypeMatch = { type: GraphQLNamedType }; type FieldMatch = { type: GraphQLNamedType; field: GraphQLField | GraphQLInputField; argument?: GraphQLArgument; }; export function useSearchResults() { const explorerNavStack = useDocExplorer(); const schema = useGraphiQL(state => state.schema); const navItem = explorerNavStack.at(-1)!; return (searchValue: string) => { const matches: { within: FieldMatch[]; types: TypeMatch[]; fields: FieldMatch[]; } = { within: [], types: [], fields: [], }; if (!schema) { return matches; } const withinType = navItem.def; const typeMap = schema.getTypeMap(); let typeNames = Object.keys(typeMap); // Move the within type name to be the first searched. if (withinType) { typeNames = typeNames.filter(n => n !== withinType.name); typeNames.unshift(withinType.name); } for (const typeName of typeNames) { if ( matches.within.length + matches.types.length + matches.fields.length >= 100 ) { break; } const type = typeMap[typeName]!; if (withinType !== type && isMatch(typeName, searchValue)) { matches.types.push({ type }); } if ( !isObjectType(type) && !isInterfaceType(type) && !isInputObjectType(type) ) { continue; } const fields = type.getFields(); for (const fieldName in fields) { const field = fields[fieldName]!; let matchingArgs: GraphQLArgument[] | undefined; if (!isMatch(fieldName, searchValue)) { if ('args' in field) { matchingArgs = field.args.filter(arg => isMatch(arg.name, searchValue), ); if (matchingArgs.length === 0) { continue; } } else { continue; } } matches[withinType === type ? 'within' : 'fields'].push( ...(matchingArgs ? matchingArgs.map(argument => ({ type, field, argument })) : [{ type, field }]), ); } } return matches; }; } function isMatch(sourceText: string, searchValue: string): boolean { try { const escaped = searchValue.replaceAll(/[^_0-9A-Za-z]/g, ch => '\\' + ch); return new RegExp(escaped, 'i').test(sourceText); } catch { return sourceText.toLowerCase().includes(searchValue.toLowerCase()); } } const Type: FC<{ type: GraphQLNamedType }> = ({ type }) => { return {type.name}; }; type FieldProps = { field: GraphQLField | GraphQLInputField; argument?: GraphQLArgument; }; const Field: FC = ({ field, argument }) => { return ( <> {field.name} {argument ? ( <> ( {argument.name} :{' '} {renderType(argument.type, namedType => ( ))} ) ) : null} ); }; ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/section.css ================================================ .graphiql-doc-explorer-section-title { align-items: center; display: flex; font-size: var(--font-size-hint); font-weight: var(--font-weight-medium); line-height: 1; & > svg { height: var(--px-16); margin-right: var(--px-8); width: var(--px-16); } } .graphiql-doc-explorer-section-content { margin-left: var(--px-8); margin-top: var(--px-16); & > * + * { margin-top: var(--px-16); } } ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/section.tsx ================================================ import type { FC, ReactNode } from 'react'; import { ArgumentIcon, DeprecatedArgumentIcon, DeprecatedEnumValueIcon, DeprecatedFieldIcon, DirectiveIcon, EnumValueIcon, FieldIcon, ImplementsIcon, RootTypeIcon, TypeIcon, } from '@graphiql/react'; import './section.css'; type ExplorerSectionProps = { children: ReactNode; /** * The title of the section, which will also determine the icon rendered next * to the headline. */ title: | 'Root Types' | 'Fields' | 'Deprecated Fields' | 'Type' | 'Arguments' | 'Deprecated Arguments' | 'Implements' | 'Implementations' | 'Possible Types' | 'Enum Values' | 'Deprecated Enum Values' | 'Directives' | 'All Schema Types'; }; export const ExplorerSection: FC = ({ title, children, }) => { const Icon = TYPE_TO_ICON[title]; return (
{title}
{children}
); }; const TYPE_TO_ICON: Record = { Arguments: ArgumentIcon, 'Deprecated Arguments': DeprecatedArgumentIcon, 'Deprecated Enum Values': DeprecatedEnumValueIcon, 'Deprecated Fields': DeprecatedFieldIcon, Directives: DirectiveIcon, 'Enum Values': EnumValueIcon, Fields: FieldIcon, Implements: ImplementsIcon, Implementations: TypeIcon, 'Possible Types': TypeIcon, 'Root Types': RootTypeIcon, Type: TypeIcon, 'All Schema Types': TypeIcon, }; ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/type-documentation.css ================================================ .graphiql-doc-explorer-item > :not(:first-child) { margin-top: var(--px-12); } .graphiql-doc-explorer-argument-multiple { margin-left: var(--px-8); } .graphiql-doc-explorer-enum-value { color: hsl(var(--color-info)); } ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/type-documentation.tsx ================================================ import { FC, useState } from 'react'; import { GraphQLEnumValue, GraphQLNamedType, isAbstractType, isEnumType, isInputObjectType, isInterfaceType, isNamedType, isObjectType, } from 'graphql'; import { useGraphiQL, Button, MarkdownContent } from '@graphiql/react'; import type { DocExplorerFieldDef } from '../context'; import { Argument } from './argument'; import { DefaultValue } from './default-value'; import { DeprecationReason } from './deprecation-reason'; import { FieldLink } from './field-link'; import { ExplorerSection } from './section'; import { TypeLink } from './type-link'; import './type-documentation.css'; type TypeDocumentationProps = { /** * The type that should be rendered. */ type: GraphQLNamedType; }; export const TypeDocumentation: FC = ({ type }) => { return isNamedType(type) ? ( <> {type.description ? ( {type.description} ) : null} ) : null; }; const ImplementsInterfaces: FC<{ type: GraphQLNamedType }> = ({ type }) => { if (!isObjectType(type)) { return null; } const interfaces = type.getInterfaces(); return interfaces.length > 0 ? ( {type.getInterfaces().map(implementedInterface => (
))}
) : null; }; const Fields: FC<{ type: GraphQLNamedType }> = ({ type }) => { const [showDeprecated, setShowDeprecated] = useState(false); const handleShowDeprecated = () => { setShowDeprecated(true); }; if ( !isObjectType(type) && !isInterfaceType(type) && !isInputObjectType(type) ) { return null; } const fieldMap = type.getFields(); const fields: DocExplorerFieldDef[] = []; const deprecatedFields: DocExplorerFieldDef[] = []; // TODO: maybe can be refactored to Object.values(fieldMap) ? for (const field of Object.keys(fieldMap).map(name => fieldMap[name]!)) { if (field.deprecationReason) { deprecatedFields.push(field); } else { fields.push(field); } } return ( <> {fields.length > 0 ? ( {fields.map(field => ( ))} ) : null} {deprecatedFields.length > 0 ? ( showDeprecated || fields.length === 0 ? ( {deprecatedFields.map(field => ( ))} ) : ( ) ) : null} ); }; const Field: FC<{ field: DocExplorerFieldDef }> = ({ field }) => { const args = 'args' in field ? field.args.filter(arg => !arg.deprecationReason) : []; return (
{args.length > 0 ? ( <> ( {args.map(arg => args.length === 1 ? ( ) : (
), )}
) ) : null} {': '}
{field.description ? ( {field.description} ) : null} {field.deprecationReason}
); }; const EnumValues: FC<{ type: GraphQLNamedType }> = ({ type }) => { const [showDeprecated, setShowDeprecated] = useState(false); const handleShowDeprecated = () => { setShowDeprecated(true); }; if (!isEnumType(type)) { return null; } const values: GraphQLEnumValue[] = []; const deprecatedValues: GraphQLEnumValue[] = []; for (const value of type.getValues()) { if (value.deprecationReason) { deprecatedValues.push(value); } else { values.push(value); } } return ( <> {values.length > 0 && ( {values.map(value => ( ))} )} {deprecatedValues.length > 0 && (showDeprecated || !values.length ? ( {deprecatedValues.map(value => ( ))} ) : ( ))} ); }; const EnumValue: FC<{ value: GraphQLEnumValue }> = ({ value }) => { return (
{value.name}
{value.description && ( {value.description} )} {value.deprecationReason && ( {value.deprecationReason} )}
); }; const PossibleTypes: FC<{ type: GraphQLNamedType }> = ({ type }) => { const schema = useGraphiQL(state => state.schema); if (!schema || !isAbstractType(type)) { return null; } return ( {schema.getPossibleTypes(type).map(possibleType => (
))}
); }; ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/type-link.css ================================================ a.graphiql-doc-explorer-type-name { color: hsl(var(--color-warning)); text-decoration: none; &:hover { text-decoration: underline; } &:focus { outline: hsl(var(--color-warning)) auto 1px; } } ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/type-link.tsx ================================================ import type { FC } from 'react'; import type { GraphQLType } from 'graphql'; import { useDocExplorerActions } from '../context'; import { renderType } from './utils'; import './type-link.css'; type TypeLinkProps = { /** * The type that should be linked to. */ type: GraphQLType; }; export const TypeLink: FC = ({ type }) => { const { push } = useDocExplorerActions(); return renderType(type, def => ( { event.preventDefault(); push({ name: def.name, def }); }} href="#" > {def.name} )); }; ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/components/utils.tsx ================================================ 'use no memo'; import { GraphQLNamedType, GraphQLType, isListType, isNonNullType, } from 'graphql'; import type { JSX } from 'react'; export function renderType( type: GraphQLType, renderNamedType: (namedType: GraphQLNamedType) => JSX.Element, ): JSX.Element { if (isNonNullType(type)) { return <>{renderType(type.ofType, renderNamedType)}!; } if (isListType(type)) { return <>[{renderType(type.ofType, renderNamedType)}]; } return renderNamedType(type); } ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/context.tsx ================================================ import type { GraphQLArgument, GraphQLField, GraphQLInputField, GraphQLNamedType, GraphQLSchema, } from 'graphql'; import { isEnumType, isInputObjectType, isInterfaceType, isNamedType, isObjectType, isScalarType, isUnionType, } from 'graphql'; import { FC, ReactElement, ReactNode, useEffect } from 'react'; import { SchemaReference, useGraphiQL, pick, createBoundedUseStore, GraphiQLPlugin, DocsFilledIcon, DocsIcon, isMacOs, } from '@graphiql/react'; import { createStore } from 'zustand'; import { getSchemaReference } from './schema-reference'; import { DocExplorer } from './components'; export const DOC_EXPLORER_PLUGIN: GraphiQLPlugin = { title: 'Documentation Explorer', icon: function Icon() { const visiblePlugin = useGraphiQL(state => state.visiblePlugin); return visiblePlugin === DOC_EXPLORER_PLUGIN ? ( ) : ( ); }, content: DocExplorer, }; export type DocExplorerFieldDef = | GraphQLField | GraphQLInputField | GraphQLArgument; export type DocExplorerNavStackItem = { /** * The name of the item. */ name: string; /** * The definition object of the item, this can be a named type, a field, an * input field or an argument. */ def?: GraphQLNamedType | DocExplorerFieldDef; }; // There's always at least one item in the nav stack export type DocExplorerNavStack = [ DocExplorerNavStackItem, ...DocExplorerNavStackItem[], ]; export type DocExplorerStoreType = { /** * A stack of navigation items. The last item in the list is the current one. * This list always contains at least one item. */ explorerNavStack: DocExplorerNavStack; actions: { /** * Push an item to the navigation stack. * @param item The item that should be pushed to the stack. */ push(item: DocExplorerNavStackItem): void; /** * Pop the last item from the navigation stack. */ pop(): void; /** * Reset the navigation stack to its initial state, this will remove all but * the initial stack item. */ reset(): void; resolveSchemaReferenceToNavItem( schemaReference: SchemaReference | null, ): void; /** * Replace the nav stack with an updated version using the new schema. */ rebuildNavStackWithSchema(schema: GraphQLSchema): void; }; }; const INITIAL_NAV_STACK: DocExplorerNavStack = [{ name: 'Docs' }]; export const docExplorerStore = createStore( (set, get) => ({ explorerNavStack: INITIAL_NAV_STACK, actions: { push(item) { set(state => { const curr = state.explorerNavStack; const lastItem = curr.at(-1)!; const explorerNavStack: DocExplorerNavStack = // Avoid pushing duplicate items lastItem.def === item.def ? curr : [...curr, item]; return { explorerNavStack }; }); }, pop() { set(state => { const curr = state.explorerNavStack; const explorerNavStack = curr.length > 1 ? (curr.slice(0, -1) as DocExplorerNavStack) : curr; return { explorerNavStack }; }); }, reset() { set(state => { const curr = state.explorerNavStack; const explorerNavStack = curr.length === 1 ? curr : INITIAL_NAV_STACK; return { explorerNavStack }; }); }, resolveSchemaReferenceToNavItem(schemaReference) { if (!schemaReference) { return; } const { kind, typeInfo } = schemaReference; const ref = getSchemaReference(kind, typeInfo); if (!ref) { return; } const { push } = get().actions; switch (ref.kind) { case 'Type': { push({ name: ref.type.name, def: ref.type, }); break; } case 'Field': { // Show a field type on stack if (ref.type) { push({ name: ref.type.name, def: ref.type, }); } push({ name: ref.field.name, def: ref.field, }); break; } case 'Argument': { if (ref.field) { push({ name: ref.field.name, def: ref.field, }); } break; } case 'EnumValue': { if (ref.type) { push({ name: ref.type.name, def: ref.type, }); } break; } } }, rebuildNavStackWithSchema(schema: GraphQLSchema) { set(state => { const oldNavStack = state.explorerNavStack; if (oldNavStack.length === 1) { return state; } // Spread is needed const newNavStack: DocExplorerNavStack = [...INITIAL_NAV_STACK]; let lastEntity: | GraphQLNamedType | GraphQLField | null = null; for (const item of oldNavStack) { if (item === INITIAL_NAV_STACK[0]) { // No need to copy the initial item continue; } if (item.def) { // If item.def isn't a named type, it must be a field, inputField, or argument if (isNamedType(item.def)) { // The type needs to be replaced with the new schema type of the same name const newType = schema.getType(item.def.name); if (newType) { newNavStack.push({ name: item.name, def: newType, }); lastEntity = newType; } else { // This type no longer exists; the stack cannot be built beyond here break; } } else if (lastEntity === null) { // We can't have a sub-entity if we have no entity; stop rebuilding the nav stack break; } else if ( isObjectType(lastEntity) || isInputObjectType(lastEntity) ) { // item.def must be a Field / input field; replace with the new field of the same name const field = lastEntity.getFields()[item.name]; if (field) { newNavStack.push({ name: item.name, def: field, }); } else { // This field no longer exists; the stack cannot be built beyond here break; } } else if ( isScalarType(lastEntity) || isEnumType(lastEntity) || isInterfaceType(lastEntity) || isUnionType(lastEntity) ) { // These don't (currently) have non-type sub-entries; something has gone wrong. // Handle gracefully by discontinuing rebuilding the stack. break; } else { // lastEntity must be a field (because it's not a named type) const field: GraphQLField = lastEntity; // Thus item.def must be an argument, so find the same named argument in the new schema if (field.args.some(a => a.name === item.name)) { newNavStack.push({ name: item.name, def: field, }); } else { // This argument no longer exists; the stack cannot be built beyond here break; } } } else { lastEntity = null; newNavStack.push(item); } } return { explorerNavStack: newNavStack }; }); }, }, }), ); export const DocExplorerStore: FC<{ children: ReactNode; }> = ({ children }) => { const { schema, validationErrors, schemaReference } = useGraphiQL( pick('schema', 'validationErrors', 'schemaReference'), ); useEffect(() => { const { resolveSchemaReferenceToNavItem } = docExplorerStore.getState().actions; resolveSchemaReferenceToNavItem(schemaReference); }, [schemaReference]); useEffect(() => { const { reset, rebuildNavStackWithSchema } = docExplorerStore.getState().actions; // Whenever the schema changes, we must revalidate/replace the nav stack. if (schema == null || validationErrors.length > 0) { reset(); } else { rebuildNavStackWithSchema(schema); } }, [schema, validationErrors]); useEffect(() => { function handleKeyDown(event: KeyboardEvent) { const shouldFocusInput = // Use an additional `Alt` key instead of `Cmd/Ctrl+K` because monaco-editor has a built-in // shortcut for `Cmd/Ctrl+K` event.altKey && event[isMacOs ? 'metaKey' : 'ctrlKey'] && // Using `event.code` because `event.key` will trigger different character // in English `˚` and in French `È` event.code === 'KeyK'; if (!shouldFocusInput) { return; } const button = document.querySelector( '.graphiql-sidebar button[aria-label="Show Documentation Explorer"]', ); button?.click(); // Execute on next tick when doc explorer is opened and input exists in DOM requestAnimationFrame(() => { const el = document.querySelector( '.graphiql-doc-explorer-search-input', ); el?.click(); }); } window.addEventListener('keydown', handleKeyDown); return () => { window.removeEventListener('keydown', handleKeyDown); }; }, []); return children as ReactElement; }; const useDocExplorerStore = createBoundedUseStore(docExplorerStore); export const useDocExplorer = () => useDocExplorerStore(state => state.explorerNavStack); /** * Actions are functions used to update values in your store. They are static and never change. * @see https://tkdodo.eu/blog/working-with-zustand#separate-actions-from-state */ export const useDocExplorerActions = () => useDocExplorerStore(state => state.actions); ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/deprecated.ts ================================================ import { useDocExplorer, useDocExplorerActions } from './context'; /** * @deprecated Use `useDocExplorerActions` and `useDocExplorer` hooks instead. */ export function useExplorerContext() { const actions = useDocExplorerActions(); const explorerNavStack = useDocExplorer(); return { ...actions, explorerNavStack, }; } ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/index.ts ================================================ export * from './components'; export { DocExplorerStore, useDocExplorer, useDocExplorerActions, DOC_EXPLORER_PLUGIN, } from './context'; export type { DocExplorerFieldDef, DocExplorerNavStack, DocExplorerNavStackItem, } from './context'; export * from './deprecated'; ================================================ FILE: packages/graphiql-plugin-doc-explorer/src/schema-reference.ts ================================================ import { getNamedType } from 'graphql'; import type { GraphQLEnumType, GraphQLNamedType, GraphQLField, GraphQLArgument, GraphQLDirective, GraphQLSchema, GraphQLEnumValue, GraphQLInputFieldMap, GraphQLInputType, GraphQLType, } from 'graphql'; import type { Maybe } from 'graphql/jsutils/Maybe'; /** * Copied from packages/codemirror-graphql/src/jump.ts */ export function getSchemaReference(kind: string, typeInfo: any) { if ( (kind === 'Field' && typeInfo.fieldDef) || (kind === 'AliasedField' && typeInfo.fieldDef) ) { return getFieldReference(typeInfo); } if (kind === 'Directive' && typeInfo.directiveDef) { return getDirectiveReference(typeInfo); } if (kind === 'Argument' && typeInfo.argDef) { return getArgumentReference(typeInfo); } if (kind === 'EnumValue' && typeInfo.enumValue) { return getEnumValueReference(typeInfo); } if (kind === 'NamedType' && typeInfo.type) { return getTypeReference(typeInfo); } } function getArgumentReference(typeInfo: any): ArgumentReference { return typeInfo.directiveDef ? { kind: 'Argument', schema: typeInfo.schema, argument: typeInfo.argDef, directive: typeInfo.directiveDef, } : { kind: 'Argument', schema: typeInfo.schema, argument: typeInfo.argDef, field: typeInfo.fieldDef, type: isMetaField(typeInfo.fieldDef) ? null : typeInfo.parentType, }; } function getDirectiveReference(typeInfo: any): DirectiveReference { return { kind: 'Directive', schema: typeInfo.schema, directive: typeInfo.directiveDef, }; } function getFieldReference(typeInfo: any): FieldReference { return { kind: 'Field', schema: typeInfo.schema, field: typeInfo.fieldDef, type: isMetaField(typeInfo.fieldDef) ? null : typeInfo.parentType, }; } // Note: for reusability, getTypeReference can produce a reference to any type, // though it defaults to the current type. function getTypeReference( typeInfo: any, type?: Maybe, ): TypeReference { return { kind: 'Type', schema: typeInfo.schema, type: type || typeInfo.type, }; } function getEnumValueReference(typeInfo: TypeInfo): EnumValueReference { return { kind: 'EnumValue', value: typeInfo.enumValue || undefined, type: typeInfo.inputType ? (getNamedType(typeInfo.inputType) as GraphQLEnumType) : undefined, }; } function isMetaField(fieldDef: GraphQLField) { return fieldDef.name.slice(0, 2) === '__'; } type ArgumentReference = { kind: 'Argument'; argument: GraphQLArgument; field?: GraphQLField; type?: GraphQLNamedType; directive?: GraphQLDirective; schema?: GraphQLSchema; }; type DirectiveReference = { kind: 'Directive'; directive: GraphQLDirective; schema?: GraphQLSchema; }; type EnumValueReference = { kind: 'EnumValue'; value?: GraphQLEnumValue; type?: GraphQLEnumType; schema?: GraphQLSchema; }; type FieldReference = { kind: 'Field'; field: GraphQLField; type: Maybe; schema?: GraphQLSchema; }; type TypeReference = { kind: 'Type'; type: GraphQLNamedType; schema?: GraphQLSchema; }; interface TypeInfo { schema: GraphQLSchema; type?: Maybe; parentType?: Maybe; inputType?: Maybe; directiveDef?: Maybe; fieldDef?: Maybe>; argDef?: Maybe; argDefs?: Maybe; enumValue?: Maybe; objectFieldDefs?: Maybe; } ================================================ FILE: packages/graphiql-plugin-doc-explorer/tsconfig.json ================================================ { "extends": "../graphiql-react/tsconfig.json" } ================================================ FILE: packages/graphiql-plugin-doc-explorer/vite.config.mts ================================================ import { defineConfig, PluginOption } from 'vite'; import react from '@vitejs/plugin-react'; import type { PluginOptions as ReactCompilerConfig } from 'babel-plugin-react-compiler'; import packageJSON from './package.json' assert { type: 'json' }; import dts from 'vite-plugin-dts'; import { reactCompilerConfig as $reactCompilerConfig } from '../graphiql-react/vite.config.mjs'; export const reactCompilerConfig: Partial = { ...$reactCompilerConfig, sources(filename) { if (filename.includes('__tests__')) { return false; } return filename.includes('/graphiql-plugin-doc-explorer/src/'); }, }; export const plugins: PluginOption[] = [ react({ babel: { plugins: [['babel-plugin-react-compiler', reactCompilerConfig]], }, }), dts({ include: ['src/**'], exclude: ['**/*.spec.{ts,tsx}', '**/__tests__/'], }), ]; export default defineConfig({ plugins, css: { transformer: 'lightningcss', }, build: { minify: false, sourcemap: true, lib: { entry: 'src/index.ts', fileName(_format, entryName) { const filePath = entryName.replace(/\.svg$/, ''); return `${filePath}.js`; }, formats: ['es'], cssFileName: 'style', }, rollupOptions: { external: [ 'react/jsx-runtime', // Exclude peer dependencies and dependencies from bundle ...Object.keys(packageJSON.peerDependencies), ...Object.keys(packageJSON.dependencies), ], output: { preserveModules: true, }, }, }, }); ================================================ FILE: packages/graphiql-plugin-doc-explorer/vitest.config.mts ================================================ import path from 'node:path'; import { defineConfig } from 'vitest/config'; import { plugins } from './vite.config.mjs'; export default defineConfig({ plugins, test: { globals: true, environment: 'jsdom', setupFiles: ['./setup-files.ts'], alias: [ { // Fixes Error: Failed to resolve entry for package "monaco-editor". The package may have incorrect main/module/exports specified in its package.json. find: /^monaco-editor$/, replacement: path.resolve( '../../node_modules/monaco-editor/esm/vs/editor/editor.api', ), }, ], }, }); ================================================ FILE: packages/graphiql-plugin-explorer/CHANGELOG.md ================================================ # @graphiql/plugin-explorer ## 5.1.1 ### Patch Changes - Updated dependencies [[`6e5d5fc`](https://github.com/graphql/graphiql/commit/6e5d5fce9a7eb5770f40300fc153e0b9b10edfbf), [`293beed`](https://github.com/graphql/graphiql/commit/293beed772baa2be834cad5f19e1aee0628e15cc)]: - @graphiql/react@0.37.0 ## 5.1.0 ### Minor Changes - [#4077](https://github.com/graphql/graphiql/pull/4077) [`3d41e11`](https://github.com/graphql/graphiql/commit/3d41e113fbf53930fd1b519b6d1330d0f4b23b7b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - add new example [Usage GraphiQL 5 with Vite, React Router and `ssr: true`](https://github.com/graphql/graphiql/tree/main/examples/example-graphiql-vite-react-router) ### Patch Changes - Updated dependencies [[`3a0a755`](https://github.com/graphql/graphiql/commit/3a0a75569c6b318f5dc27d62000bcc9b0536c6fd), [`fd3f9e6`](https://github.com/graphql/graphiql/commit/fd3f9e6a91be728a69a136ad8680f6e3c7241198), [`416e3a0`](https://github.com/graphql/graphiql/commit/416e3a05e9473eb2abd444da61ecfb8614020d14), [`3d41e11`](https://github.com/graphql/graphiql/commit/3d41e113fbf53930fd1b519b6d1330d0f4b23b7b)]: - @graphiql/react@0.36.0 ## 5.0.0 ### Major Changes - [#3990](https://github.com/graphql/graphiql/pull/3990) [`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - allow multiple independent instances of GraphiQL on the same page - store `onClickReference` in query editor in React `ref` - remove `onClickReference` from variable editor - fix shortcut text per OS for run query in execute query button's tooltip and in default query - allow override all default GraphiQL plugins - adjust operation argument color to be purple from GraphiQL v2 on dark/light theme - [#4009](https://github.com/graphql/graphiql/pull/4009) [`4936492`](https://github.com/graphql/graphiql/commit/49364924d0da05a86f7c6c3139d44aed0e474531) Thanks [@dimaMachina](https://github.com/dimaMachina)! - separate store actions from state, add `useGraphiQLActions` state - [#4002](https://github.com/graphql/graphiql/pull/4002) [`2d9faec`](https://github.com/graphql/graphiql/commit/2d9faec57830b38aa175929c47a55c959c327535) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove UMD builds ### Patch Changes - [#3949](https://github.com/graphql/graphiql/pull/3949) [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - replace `onCopyQuery` hook with `copyQuery` function - replace `onMergeQuery` hook with `mergeQuery` function - replace `onPrettifyEditors` hook with `prettifyEditors` function - remove `fetcher` prop from `SchemaContextProvider` and `schemaStore` and add `fetcher` to `executionStore` - add `onCopyQuery` and `onPrettifyQuery` props to `EditorContextProvider` - remove exports (use `GraphiQLProvider`) - `EditorContextProvider` - `ExecutionContextProvider` - `PluginContextProvider` - `SchemaContextProvider` - `StorageContextProvider` - `ExecutionContextType` - `PluginContextType` - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - prefer `getComputedStyle` over `window.getComputedStyle` - [#3234](https://github.com/graphql/graphiql/pull/3234) [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Migration from Codemirror to [Monaco Editor](https://github.com/microsoft/monaco-editor) Replacing `codemirror-graphql` with [`monaco-graphql`](https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql) Support for comments in **Variables** and **Headers** editors ## 5.0.0-rc.3 ### Major Changes - [#4009](https://github.com/graphql/graphiql/pull/4009) [`4936492`](https://github.com/graphql/graphiql/commit/49364924d0da05a86f7c6c3139d44aed0e474531) Thanks [@dimaMachina](https://github.com/dimaMachina)! - separate store actions from state, add `useGraphiQLActions` state ## 5.0.0-rc.2 ### Major Changes - [#4002](https://github.com/graphql/graphiql/pull/4002) [`2d9faec`](https://github.com/graphql/graphiql/commit/2d9faec57830b38aa175929c47a55c959c327535) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove UMD builds ## 5.0.0-rc.1 ### Major Changes - [#3990](https://github.com/graphql/graphiql/pull/3990) [`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - allow multiple independent instances of GraphiQL on the same page - store `onClickReference` in query editor in React `ref` - remove `onClickReference` from variable editor - fix shortcut text per OS for run query in execute query button's tooltip and in default query - allow override all default GraphiQL plugins - adjust operation argument color to be purple from GraphiQL v2 on dark/light theme ## 4.0.7-rc.0 ### Patch Changes - [#3949](https://github.com/graphql/graphiql/pull/3949) [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - replace `onCopyQuery` hook with `copyQuery` function - replace `onMergeQuery` hook with `mergeQuery` function - replace `onPrettifyEditors` hook with `prettifyEditors` function - remove `fetcher` prop from `SchemaContextProvider` and `schemaStore` and add `fetcher` to `executionStore` - add `onCopyQuery` and `onPrettifyQuery` props to `EditorContextProvider` - remove exports (use `GraphiQLProvider`) - `EditorContextProvider` - `ExecutionContextProvider` - `PluginContextProvider` - `SchemaContextProvider` - `StorageContextProvider` - `ExecutionContextType` - `PluginContextType` - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - prefer `getComputedStyle` over `window.getComputedStyle` - [#3234](https://github.com/graphql/graphiql/pull/3234) [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Migration from Codemirror to [Monaco Editor](https://github.com/microsoft/monaco-editor) Replacing `codemirror-graphql` with [`monaco-graphql`](https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql) Support for comments in **Variables** and **Headers** editors - Updated dependencies [[`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e), [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91), [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb)]: - @graphiql/react@0.35.0-rc.0 ## 4.0.6 ### Patch Changes - [#3970](https://github.com/graphql/graphiql/pull/3970) [`7054591`](https://github.com/graphql/graphiql/commit/70545912d1b3bb9e0c45e766a5c89896a9c4dfb7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - revert https://github.com/graphql/graphiql/pull/3946 to have support multiple embedded graphiql instances on the same page ## 4.0.5 ### Patch Changes - [#3946](https://github.com/graphql/graphiql/pull/3946) [`71755b7`](https://github.com/graphql/graphiql/commit/71755b7f412f8f3dd9f5194d3f1e0168b9ad07af) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - replace `useAutoCompleteLeafs` hook with `getAutoCompleteLeafs` function - Updated dependencies [[`71755b7`](https://github.com/graphql/graphiql/commit/71755b7f412f8f3dd9f5194d3f1e0168b9ad07af), [`6d631e2`](https://github.com/graphql/graphiql/commit/6d631e2e558d038476fe235b1506bc52ecf68781)]: - @graphiql/react@0.34.0 ## 4.0.4 ### Patch Changes - [#3945](https://github.com/graphql/graphiql/pull/3945) [`117627b`](https://github.com/graphql/graphiql/commit/117627b451607198dd7b9dc19e76da8a71d14b71) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand, replace `usePluginContext` with `usePluginStore` hook - [#3947](https://github.com/graphql/graphiql/pull/3947) [`fa78481`](https://github.com/graphql/graphiql/commit/fa784819ce020346052901019079fb5b44af6ef0) Thanks [@dimaMachina](https://github.com/dimaMachina)! - refactor `useStorage`, `useDocExplorer` and `useHistory` hooks - [#3943](https://github.com/graphql/graphiql/pull/3943) [`7275472`](https://github.com/graphql/graphiql/commit/727547236bbd4fc721069ceae63eb8a6acffa57e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand, replace `useSchemaContext` with `useSchemaStore` hook - Updated dependencies [[`117627b`](https://github.com/graphql/graphiql/commit/117627b451607198dd7b9dc19e76da8a71d14b71), [`fa78481`](https://github.com/graphql/graphiql/commit/fa784819ce020346052901019079fb5b44af6ef0), [`7275472`](https://github.com/graphql/graphiql/commit/727547236bbd4fc721069ceae63eb8a6acffa57e), [`00c8605`](https://github.com/graphql/graphiql/commit/00c8605e1f3068e6547a5a9e969571a86a57f921)]: - @graphiql/react@0.33.0 ## 4.0.3 ### Patch Changes - [#3939](https://github.com/graphql/graphiql/pull/3939) [`69ad489`](https://github.com/graphql/graphiql/commit/69ad489678d0096432d5c4b1749d87343f4ed1f7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - prefer `React.FC` type when declaring React components ## 4.0.2 ### Patch Changes - Updated dependencies [[`98d13a3`](https://github.com/graphql/graphiql/commit/98d13a3e515eb70aaf5a5ba669c680d5959fef67)]: - @graphiql/react@0.32.0 ## 4.0.1 ### Patch Changes - [#3915](https://github.com/graphql/graphiql/pull/3915) [`bc31cd9`](https://github.com/graphql/graphiql/commit/bc31cd99a92693238e7359456e3cc22ed0387df0) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix unpkg.com results to `Not found` when `main` field isn't specified in `package.json` - Updated dependencies [[`e7c436b`](https://github.com/graphql/graphiql/commit/e7c436b329a68981bdbd2b662be94875a546a1d6)]: - @graphiql/react@0.31.0 ## 4.0.0 ### Major Changes - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - drop commonjs build files - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - 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 - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - `style.css` import was changed ## Migration ```diff -import '@graphiql/plugin-explorer/dist/style.css'; +import '@graphiql/plugin-explorer/style.css'; ``` ### Minor Changes - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Update GraphiQL CDN example using ESM-based CDN esm.sh - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - generate types with `vite-plugin-dts` - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update `vite` and related dependencies ### Patch Changes - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - improve explorer styles - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix types incorrect types entry - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - use `vite build --watch` instead of `vite` for `dev` script because we don't need development server for them do not use `vite-plugin-dts` when generating umd build - Updated dependencies [[`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602), [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602)]: - @graphiql/react@0.30.0 ## 4.0.0-alpha.2 ### Patch Changes - [#3740](https://github.com/graphql/graphiql/pull/3740) [`3c12ce0`](https://github.com/graphql/graphiql/commit/3c12ce01eb3b2ec9a317a2fea2bb92602b748a8b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix types incorrect types entry ## 4.0.0-alpha.1 ### Patch Changes - [#3738](https://github.com/graphql/graphiql/pull/3738) [`eaa415c`](https://github.com/graphql/graphiql/commit/eaa415cce5c3baecea76068c02953884eec5ba2e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - improve explorer styles ## 4.0.0-alpha.0 ### Major Changes - [#3709](https://github.com/graphql/graphiql/pull/3709) [`9baf1f0`](https://github.com/graphql/graphiql/commit/9baf1f0fc9f32404fbb8bf57b3d1c2c2c8778ddb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - `style.css` import was changed ## Migration ```diff -import '@graphiql/plugin-explorer/dist/style.css'; +import '@graphiql/plugin-explorer/style.css'; ``` ### Minor Changes - [#3702](https://github.com/graphql/graphiql/pull/3702) [`00415d2`](https://github.com/graphql/graphiql/commit/00415d2940c4d76a4a9e683e9fa0504ba97dd627) Thanks [@dimaMachina](https://github.com/dimaMachina)! - generate types with `vite-plugin-dts` ### Patch Changes - [#3705](https://github.com/graphql/graphiql/pull/3705) [`8ff87d7`](https://github.com/graphql/graphiql/commit/8ff87d7b6b3d5d12b539612a39ca3abf7e631106) Thanks [@dimaMachina](https://github.com/dimaMachina)! - use `vite build --watch` instead of `vite` for `dev` script because we don't need development server for them do not use `vite-plugin-dts` when generating umd build - Updated dependencies [[`00415d2`](https://github.com/graphql/graphiql/commit/00415d2940c4d76a4a9e683e9fa0504ba97dd627), [`9baf1f0`](https://github.com/graphql/graphiql/commit/9baf1f0fc9f32404fbb8bf57b3d1c2c2c8778ddb), [`8ff87d7`](https://github.com/graphql/graphiql/commit/8ff87d7b6b3d5d12b539612a39ca3abf7e631106), [`82bc961`](https://github.com/graphql/graphiql/commit/82bc961a33c4e9da29dffb4a603035a4909f49ad), [`3c1a345`](https://github.com/graphql/graphiql/commit/3c1a345acd9bf07b45bc230009cb57c51c425673)]: - @graphiql/react@1.0.0-alpha.0 ## 3.2.6 ### Patch Changes - Updated dependencies [[`cb29e9f`](https://github.com/graphql/graphiql/commit/cb29e9fbe1362778bc327513fc884c4ec419775e), [`1adc40c`](https://github.com/graphql/graphiql/commit/1adc40cc56dbf79296bb857156e6adce1c44dcbe)]: - @graphiql/react@0.29.0 ## 3.2.5 ### Patch Changes - [#3837](https://github.com/graphql/graphiql/pull/3837) [`5e76a4f`](https://github.com/graphql/graphiql/commit/5e76a4f3c8b089a1de0c92c9b9c1edc2ae3f49d4) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix query builder updated only first selected field in query editor due recent enabled react-compiler ## 3.2.4 ### Patch Changes - Updated dependencies [[`3633d61`](https://github.com/graphql/graphiql/commit/3633d61c3c597adf60c0ec1bbf98cf6a1f49beed)]: - @graphiql/react@0.28.0 ## 3.2.3 ### Patch Changes - Updated dependencies [[`f86e2bc`](https://github.com/graphql/graphiql/commit/f86e2bce40826b3d07755f91b37a72051de00f9c)]: - @graphiql/react@0.27.0 ## 3.2.2 ### Patch Changes - Updated dependencies [[`959ed21`](https://github.com/graphql/graphiql/commit/959ed21815682fc439f64d78e23e603a8f313a6f), [`9aef83a`](https://github.com/graphql/graphiql/commit/9aef83a32aeb5f193a3ff0f191c95d09eb0d70b6)]: - @graphiql/react@0.26.0 ## 3.2.1 ### Patch Changes - Updated dependencies [[`7404e8e`](https://github.com/graphql/graphiql/commit/7404e8e6c62b06107f452142493297ec70f1649c)]: - @graphiql/react@0.25.0 ## 3.2.0 ### Minor Changes - [#3682](https://github.com/graphql/graphiql/pull/3682) [`6c9f0df`](https://github.com/graphql/graphiql/commit/6c9f0df83ea4afe7fa59f84d83d59fba73dc3931) Thanks [@yaacovCR](https://github.com/yaacovCR)! - Support v17 of `graphql-js` from `17.0.0-alpha.2` forward. Includes support for the latest incremental delivery response format. For further details, see https://github.com/graphql/defer-stream-wg/discussions/69. ### Patch Changes - Updated dependencies [[`6c9f0df`](https://github.com/graphql/graphiql/commit/6c9f0df83ea4afe7fa59f84d83d59fba73dc3931)]: - @graphiql/react@0.24.0 ## 3.1.1 ### Patch Changes - [#3657](https://github.com/graphql/graphiql/pull/3657) [`5bc7b84`](https://github.com/graphql/graphiql/commit/5bc7b84531b6404553787615d61a5cbcc96c1d6f) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update vite to v5 - [#3656](https://github.com/graphql/graphiql/pull/3656) [`93c7e9f`](https://github.com/graphql/graphiql/commit/93c7e9fd224cb4f1e9a86b3391efc1e0ef6e1e3f) Thanks [@dimaMachina](https://github.com/dimaMachina)! - set `build.minify: false` for cjs/esm builds since minified variable names change every build time - Updated dependencies [[`5bc7b84`](https://github.com/graphql/graphiql/commit/5bc7b84531b6404553787615d61a5cbcc96c1d6f), [`fdec377`](https://github.com/graphql/graphiql/commit/fdec377f28ac0d918a219b78dfa2d8f0996ff84d), [`93c7e9f`](https://github.com/graphql/graphiql/commit/93c7e9fd224cb4f1e9a86b3391efc1e0ef6e1e3f)]: - @graphiql/react@0.23.0 ## 3.1.0 ### Minor Changes - [#3633](https://github.com/graphql/graphiql/pull/3633) [`8849a15b`](https://github.com/graphql/graphiql/commit/8849a15b6e80fe1b34e8250e74a56b85ccdb6ac6) Thanks [@dimaMachina](https://github.com/dimaMachina)! - adjust `@graphiql/plugin-explorer` styles ### Patch Changes - Updated dependencies [[`adf0ba01`](https://github.com/graphql/graphiql/commit/adf0ba019902dcac2e49ccee69b79a6665c4766d)]: - @graphiql/react@0.22.4 ## 3.0.3 ### Patch Changes - Updated dependencies [[`335d830c`](https://github.com/graphql/graphiql/commit/335d830c2a4e551ef97fbeff8ed7c538ff5cd4af)]: - @graphiql/react@0.22.3 ## 3.0.2 ### Patch Changes - Updated dependencies [[`03ab3a6b`](https://github.com/graphql/graphiql/commit/03ab3a6b76378591ef79a828d80cc69b0b8f2842)]: - @graphiql/react@0.22.2 ## 3.0.1 ### Patch Changes - Updated dependencies [[`224b43f5`](https://github.com/graphql/graphiql/commit/224b43f5473456f264a82998d48a34a441537f54)]: - @graphiql/react@0.22.1 ## 3.0.0 ### Patch Changes - Updated dependencies [[`d48f4ef5`](https://github.com/graphql/graphiql/commit/d48f4ef56578dad7ec90f33458353791e463ef7b)]: - @graphiql/react@0.22.0 ## 2.0.0 ### Patch Changes - Updated dependencies [[`5d051054`](https://github.com/graphql/graphiql/commit/5d05105469c3f0cbeb5e294da1cf6ff2355e4eb5)]: - @graphiql/react@0.21.0 ## 1.0.4 ### Patch Changes - Updated dependencies []: - @graphiql/react@0.20.4 ## 1.0.3 ### Patch Changes - [#3526](https://github.com/graphql/graphiql/pull/3526) [`2b6ea316`](https://github.com/graphql/graphiql/commit/2b6ea3166c8d8e152f16d87c878aa8a66f1b3775) Thanks [@benjie](https://github.com/benjie)! - Fix bug whereby typing quickly into explorer sidebar would result in characters being dropped. - Updated dependencies [[`2b6ea316`](https://github.com/graphql/graphiql/commit/2b6ea3166c8d8e152f16d87c878aa8a66f1b3775)]: - @graphiql/react@0.20.3 ## 1.0.2 ### Patch Changes - Updated dependencies [[`e89c432d`](https://github.com/graphql/graphiql/commit/e89c432d8d2b91f087b683360f23e0686462bc02)]: - @graphiql/react@0.20.2 ## 1.0.1 ### Patch Changes - Updated dependencies [[`39bf31d1`](https://github.com/graphql/graphiql/commit/39bf31d15b1e7fb5f235ec9adc1ce8081536de4a)]: - @graphiql/react@0.20.1 ## 1.0.0 ### Patch Changes - Updated dependencies [[`f6afd22d`](https://github.com/graphql/graphiql/commit/f6afd22d3f5a20089759042f16fd865646a32038)]: - @graphiql/react@0.20.0 ## 0.3.5 ### Patch Changes - Updated dependencies []: - @graphiql/react@0.19.4 ## 0.3.4 ### Patch Changes - Updated dependencies [[`2348641c`](https://github.com/graphql/graphiql/commit/2348641c07748691c478ac5f67032b7e9081f9cb)]: - @graphiql/react@0.19.3 ## 0.3.3 ### Patch Changes - Updated dependencies [[`d67c13f6`](https://github.com/graphql/graphiql/commit/d67c13f6e1f478b171801afd0767b98312db04c9)]: - @graphiql/react@0.19.2 ## 0.3.2 ### Patch Changes - [#3341](https://github.com/graphql/graphiql/pull/3341) [`e4a36207`](https://github.com/graphql/graphiql/commit/e4a362071edf1db53f87f271c523ab2f3a5c4717) Thanks [@acao](https://github.com/acao)! - Fix code exporter plugin on early init, add hooks - Updated dependencies [[`17069e7a`](https://github.com/graphql/graphiql/commit/17069e7a0224dbce3f5523630a898e093f5c47c9), [`e4a36207`](https://github.com/graphql/graphiql/commit/e4a362071edf1db53f87f271c523ab2f3a5c4717)]: - @graphiql/react@0.19.1 ## 0.3.1 ### Patch Changes - [#3350](https://github.com/graphql/graphiql/pull/3350) [`119775ed`](https://github.com/graphql/graphiql/commit/119775ed191ce075532a6e85cbfeac2364c0ba40) Thanks [@acao](https://github.com/acao)! - handle null editor in explorer plugin [(PR)](https://github.com/graphql/graphiql/pull/3340) ## 0.3.0 ### Minor Changes - [#3330](https://github.com/graphql/graphiql/pull/3330) [`bed5fc86`](https://github.com/graphql/graphiql/commit/bed5fc86173eb0e770f966fa529ee035b97a1349) Thanks [@acao](https://github.com/acao)! - **BREAKING CHANGE**: fix lifecycle issue in plugin-explorer, change implementation pattern `value` and `setValue` is no longer an implementation detail, and are handled internally by plugins. the plugin signature has changed slightly as well. now, instead of something like this: ```jsx import { useExplorerPlugin } from '@graphiql/plugin-explorer'; import { snippets } from './snippets'; import { useExporterPlugin } from '@graphiql/plugin-code-exporter'; const App = () => { const [query, setQuery] = React.useState(''); const explorerPlugin = useExplorerPlugin({ query, onEdit: setQuery, }); const codeExporterPlugin = useExporterPlugin({ query, snippets, }); const plugins = React.useMemo( () => [explorerPlugin, codeExporterPlugin], [explorerPlugin, codeExporterPlugin], ); return ( ); }; ``` you can just do this: ```jsx import { explorerPlugin } from '@graphiql/plugin-explorer'; import { snippets } from './snippets'; import { codeExporterPlugin } from '@graphiql/plugin-code-exporter'; import { createGraphiQLFetcher } from '@graphiql/toolkit'; // only invoke these inside the component lifecycle // if there are dynamic values, and then use useMemo() (see below) const explorer = explorerPlugin(); const exporter = codeExporterPlugin({ snippets }); const fetcher = createGraphiQLFetcher({ url: '/graphql' }); const App = () => { return ; }; ``` or this, for more complex state-driven needs: ```jsx import { useMemo } from 'react'; import { explorerPlugin } from '@graphiql/plugin-explorer'; import { snippets } from './snippets'; import { codeExporterPlugin } from '@graphiql/plugin-code-exporter'; const explorer = explorerPlugin(); const fetcher = createGraphiQLFetcher({ url: '/graphql' }); const App = () => { const { snippets } = useMyUserSuppliedState(); const exporter = useMemo( () => codeExporterPlugin({ snippets }), [snippets], ); return ; }; ``` ## 0.2.0 ### Minor Changes - [#3293](https://github.com/graphql/graphiql/pull/3293) [`1b8f3fe9`](https://github.com/graphql/graphiql/commit/1b8f3fe9c41697855378ec13a76f1a908fda778a) Thanks [@B2o5T](https://github.com/B2o5T)! - BREAKING CHANGE: umd build was renamed to `index.umd.js` ### Patch Changes - [#3319](https://github.com/graphql/graphiql/pull/3319) [`2f51b1a5`](https://github.com/graphql/graphiql/commit/2f51b1a5f25ac515af89b708c009796c57a611fb) Thanks [@LekoArts](https://github.com/LekoArts)! - Use named `Explorer` import from `graphiql-explorer` to fix an issue where the bundler didn't correctly choose either the `default` or `Explorer` import. This change should ensure that `@graphiql/plugin-explorer` works correctly without `graphiql-explorer` being bundled. ## 0.1.22 ### Patch Changes - [#3292](https://github.com/graphql/graphiql/pull/3292) [`f86e4172`](https://github.com/graphql/graphiql/commit/f86e41721d4d990535253b579c810bc5e291b40b) Thanks [@B2o5T](https://github.com/B2o5T)! - fix umd build names `graphiql-plugin-code-exporter.umd.js` and `graphiql-plugin-explorer.umd.js` ## 0.1.21 ### Patch Changes - [#3229](https://github.com/graphql/graphiql/pull/3229) [`0a65e720`](https://github.com/graphql/graphiql/commit/0a65e7207b6bc4174896f6acca8a40f45d2fb1b8) Thanks [@B2o5T](https://github.com/B2o5T)! - exclude peer dependencies and dependencies from bundle - [#3251](https://github.com/graphql/graphiql/pull/3251) [`f8d8509b`](https://github.com/graphql/graphiql/commit/f8d8509b432803eaeb2e53b6b6d4321535e11c1d) Thanks [@B2o5T](https://github.com/B2o5T)! - always bundle `package.json#dependencies` for UMD build for `@graphiql/plugin-code-exporter` and `@graphiql/plugin-explorer` - [#3236](https://github.com/graphql/graphiql/pull/3236) [`64da8c30`](https://github.com/graphql/graphiql/commit/64da8c3074628bb411eb1c28aa4738843f60910c) Thanks [@B2o5T](https://github.com/B2o5T)! - update vite - [#3252](https://github.com/graphql/graphiql/pull/3252) [`c915a4ee`](https://github.com/graphql/graphiql/commit/c915a4eead4ae39cb5c9fa615b5b55945da06c01) Thanks [@B2o5T](https://github.com/B2o5T)! - `@graphiql/react` should be in `peerDependencies` not in `dependencies` - Updated dependencies [[`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`bc9d243d`](https://github.com/graphql/graphiql/commit/bc9d243d40b95f95fc9d00d25aa0dd1733952626), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`67bf93a3`](https://github.com/graphql/graphiql/commit/67bf93a33e98c60ae3a686063a1c47037f88ef49)]: - @graphiql/react@0.18.0 ## 0.1.21-alpha.1 ### Patch Changes - [#3229](https://github.com/graphql/graphiql/pull/3229) [`0a65e720`](https://github.com/graphql/graphiql/commit/0a65e7207b6bc4174896f6acca8a40f45d2fb1b8) Thanks [@B2o5T](https://github.com/B2o5T)! - exclude peer dependencies and dependencies from bundle - Updated dependencies [[`bc9d243d`](https://github.com/graphql/graphiql/commit/bc9d243d40b95f95fc9d00d25aa0dd1733952626), [`67bf93a3`](https://github.com/graphql/graphiql/commit/67bf93a33e98c60ae3a686063a1c47037f88ef49)]: - @graphiql/react@0.18.0-alpha.1 ## 0.1.21-alpha.0 ### Patch Changes - Updated dependencies [[`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696), [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696)]: - @graphiql/react@0.18.0-alpha.0 ## 0.1.20 ### Patch Changes - [#3124](https://github.com/graphql/graphiql/pull/3124) [`c645932c`](https://github.com/graphql/graphiql/commit/c645932c7973e11ad917e1d1d897fd409f8c042f) Thanks [@B2o5T](https://github.com/B2o5T)! - avoid unnecessary renders by using useMemo or useCallback - Updated dependencies [[`911cf3e0`](https://github.com/graphql/graphiql/commit/911cf3e0b0fa13268245463c8db8299279e5c461), [`c645932c`](https://github.com/graphql/graphiql/commit/c645932c7973e11ad917e1d1d897fd409f8c042f), [`2ca4841b`](https://github.com/graphql/graphiql/commit/2ca4841baf74e87a3f067b3415f8da3347ee3898), [`7bf90929`](https://github.com/graphql/graphiql/commit/7bf90929f62ba812c0946e0424f9f843f7b6b0ff), [`431b7fe1`](https://github.com/graphql/graphiql/commit/431b7fe1efefa4867f0ea617adc436b1117052e8)]: - @graphiql/react@0.17.6 ## 0.1.19 ### Patch Changes - Updated dependencies [[`2b212941`](https://github.com/graphql/graphiql/commit/2b212941628498957d95ee89a7a5a0623f391b7a), [`9b333a04`](https://github.com/graphql/graphiql/commit/9b333a047d6b75db7681f484156d8772e9f91810)]: - @graphiql/react@0.17.5 ## 0.1.18 ### Patch Changes - Updated dependencies [[`707f3cbc`](https://github.com/graphql/graphiql/commit/707f3cbca3ac2ce186058e7d2b145cdf69bf7d9c)]: - @graphiql/react@0.17.4 ## 0.1.17 ### Patch Changes - Updated dependencies []: - @graphiql/react@0.17.3 ## 0.1.16 ### Patch Changes - Updated dependencies [[`2e477eb2`](https://github.com/graphql/graphiql/commit/2e477eb24672a242ae4a4f2dfaeaf41152ed7ee9), [`4879984e`](https://github.com/graphql/graphiql/commit/4879984ea1803a6e9f97d81c97e8ba27aacddae9), [`51007002`](https://github.com/graphql/graphiql/commit/510070028b7d8e98f2ba25f396519976aea5fa4b)]: - @graphiql/react@0.17.2 ## 0.1.15 ### Patch Changes - [#3017](https://github.com/graphql/graphiql/pull/3017) [`4a2284f5`](https://github.com/graphql/graphiql/commit/4a2284f54809f91d03ba51b9eb4e3ba7b8b7e773) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Avoid bundling code from `react/jsx-runtime` so that the package can be used with Preact - [#3063](https://github.com/graphql/graphiql/pull/3063) [`5792aaa5`](https://github.com/graphql/graphiql/commit/5792aaa5b26b68dc396f7bfb5dc3defd9331b831) Thanks [@B2o5T](https://github.com/B2o5T)! - avoid `useMemo` with empty array `[]` since React can't guarantee stable reference, + lint restrict syntax for future mistakes - Updated dependencies [[`2d5c60ec`](https://github.com/graphql/graphiql/commit/2d5c60ecf717abafde2bddd32b2772261d3eec8b), [`b9c13328`](https://github.com/graphql/graphiql/commit/b9c13328f3d28c0026ee0f0ecc7213065c9b016d), [`4a2284f5`](https://github.com/graphql/graphiql/commit/4a2284f54809f91d03ba51b9eb4e3ba7b8b7e773), [`881a2024`](https://github.com/graphql/graphiql/commit/881a202497d5a58eb5260a5aa54c0c88930d69a0), [`7cf4908a`](https://github.com/graphql/graphiql/commit/7cf4908a5d4bd58af315047f4dec5236e8c701fc)]: - @graphiql/react@0.17.1 ## 0.1.14 ### Patch Changes - Updated dependencies [[`bdc966cb`](https://github.com/graphql/graphiql/commit/bdc966cba6134a72ff7fe40f76543c77ba15d4a4), [`65f5176a`](https://github.com/graphql/graphiql/commit/65f5176a408cfbbc514ca60e2e4bd2ea133a8b0b)]: - @graphiql/react@0.17.0 ## 0.1.13 ### Patch Changes - Updated dependencies [[`f7addb20`](https://github.com/graphql/graphiql/commit/f7addb20c4a558fbfb4112c8ff095bbc8f9d9147), [`cec3fb2a`](https://github.com/graphql/graphiql/commit/cec3fb2a493c4a0c40df7dfad04e1a95ed35e786), [`11e6ad11`](https://github.com/graphql/graphiql/commit/11e6ad11e745c671eb320731697887bb8d7177b7), [`c70d9165`](https://github.com/graphql/graphiql/commit/c70d9165cc1ef8eb1cd0d6b506ced98c626597f9), [`d502a33b`](https://github.com/graphql/graphiql/commit/d502a33b4332f1025e947c02d7cfdc5799365c8d), [`0669767e`](https://github.com/graphql/graphiql/commit/0669767e1e2196a78cbefe3679a52bcbb341e913), [`f263f778`](https://github.com/graphql/graphiql/commit/f263f778cb95b9f413bd09ca56a43f5b9c2f6215), [`ccba2f33`](https://github.com/graphql/graphiql/commit/ccba2f33b67a03f492222f7afde1354cfd033b42), [`4ff2794c`](https://github.com/graphql/graphiql/commit/4ff2794c8b6032168e27252096cb276ce712878e)]: - @graphiql/react@0.16.0 ## 0.1.12 ### Patch Changes - Updated dependencies [[`16174a05`](https://github.com/graphql/graphiql/commit/16174a053ed89fb9554d096395ab7bf69c8f6911), [`f6cae4ea`](https://github.com/graphql/graphiql/commit/f6cae4eaa0258ea7fcde97ba6368830955f0abf4), [`3340fd74`](https://github.com/graphql/graphiql/commit/3340fd745e181ba8f1f5a6ed002a04d253a78d4a), [`0851d5f9`](https://github.com/graphql/graphiql/commit/0851d5f9ecf709597d0a698609d88f99c4395665), [`83364b28`](https://github.com/graphql/graphiql/commit/83364b28020b5946ed58908d6d977f1de766e75d), [`3a7d0007`](https://github.com/graphql/graphiql/commit/3a7d00071922e2005777c92daf6ad0c1ce3e2816)]: - @graphiql/react@0.15.0 ## 0.1.11 ### Patch Changes - Updated dependencies [[`29630c22`](https://github.com/graphql/graphiql/commit/29630c2219bca8b825ab0897840864364a9de2e8), [`8f926489`](https://github.com/graphql/graphiql/commit/8f9264896e9971951853463a283a90ba3d1310ef), [`2ba2f620`](https://github.com/graphql/graphiql/commit/2ba2f620b6e7de3ae6b5ea641f33e600f7f44e08)]: - @graphiql/react@0.14.0 ## 0.1.10 ### Patch Changes - Updated dependencies []: - @graphiql/react@0.13.7 ## 0.1.9 ### Patch Changes - Updated dependencies []: - @graphiql/react@0.13.6 ## 0.1.8 ### Patch Changes - Updated dependencies [[`682ad06e`](https://github.com/graphql/graphiql/commit/682ad06e58ded2f82fa973e8e6613dd654417fe2)]: - @graphiql/react@0.13.5 ## 0.1.7 ### Patch Changes - Updated dependencies [[`4e2f7ff9`](https://github.com/graphql/graphiql/commit/4e2f7ff99c578ceae54a1ae17c02088bd91b89c3)]: - @graphiql/react@0.13.4 ## 0.1.6 ### Patch Changes - Updated dependencies [[`42700076`](https://github.com/graphql/graphiql/commit/4270007671ce52f6c2250739916083611748b657), [`36839800`](https://github.com/graphql/graphiql/commit/36839800de128b05d11c262036c8240390c72a14), [`905f2e5e`](https://github.com/graphql/graphiql/commit/905f2e5ea3f0b304d27ea583e250ed4baff5016e)]: - @graphiql/react@0.13.3 ## 0.1.5 ### Patch Changes - Updated dependencies [[`39b4668d`](https://github.com/graphql/graphiql/commit/39b4668d43176526d37ecf07d8c86901d53e0d80)]: - @graphiql/react@0.13.2 ## 0.1.4 ### Patch Changes - Updated dependencies []: - @graphiql/react@0.13.1 ## 0.1.3 ### Patch Changes - [#2735](https://github.com/graphql/graphiql/pull/2735) [`ca067d88`](https://github.com/graphql/graphiql/commit/ca067d88148c5d221d196790a997ad599038fad1) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Use the new CSS variables for color alpha values defined in `@graphiql/react` in style definitions * [#2757](https://github.com/graphql/graphiql/pull/2757) [`32a70065`](https://github.com/graphql/graphiql/commit/32a70065434eaa7733e28cda0ea0e7d51952e62a) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Use different colors for field names and argument names * Updated dependencies [[`ca067d88`](https://github.com/graphql/graphiql/commit/ca067d88148c5d221d196790a997ad599038fad1), [`32a70065`](https://github.com/graphql/graphiql/commit/32a70065434eaa7733e28cda0ea0e7d51952e62a)]: - @graphiql/react@0.13.0 ## 0.1.2 ### Patch Changes - [#2750](https://github.com/graphql/graphiql/pull/2750) [`cdc44aab`](https://github.com/graphql/graphiql/commit/cdc44aabdc549f5a0359b8f69506cc0c31661d16) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Remove `type` field from `package.json` to support both ES Modules and CommonJS - Updated dependencies []: - @graphiql/react@0.12.1 ## 0.1.1 ### Patch Changes - [#2745](https://github.com/graphql/graphiql/pull/2745) [`92a17490`](https://github.com/graphql/graphiql/commit/92a17490c3842b4f83ed1065b73a803f73d02a17) Thanks [@acao](https://github.com/acao)! - Specify MIT license for `@graphiql/plugin-explorer` `package.json` * [#2731](https://github.com/graphql/graphiql/pull/2731) [`3e8f0d1f`](https://github.com/graphql/graphiql/commit/3e8f0d1fe4da5cdea94240119bbad587720ca324) Thanks [@hasparus](https://github.com/hasparus)! - Expose typings for graphiql-explorer - [#2738](https://github.com/graphql/graphiql/pull/2738) [`33bef178`](https://github.com/graphql/graphiql/commit/33bef17832edb29f5b26f4ed1cf33fd0d7fbbed1) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix peer dependency versions * [#2747](https://github.com/graphql/graphiql/pull/2747) [`52d0003f`](https://github.com/graphql/graphiql/commit/52d0003fd0c405da65b7b23dcfed9f3aacbad067) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Make `@graphiql/react` a real dependency instead of a peer dependency * Updated dependencies [[`98e14155`](https://github.com/graphql/graphiql/commit/98e14155c650ee7c5ac639e594eb47f0052b7fa9), [`7dfea94a`](https://github.com/graphql/graphiql/commit/7dfea94afc0cfe79b5080f10d840bfdce53f02d7), [`3aa1f39f`](https://github.com/graphql/graphiql/commit/3aa1f39f6df559b54f703937ed510c8ba1f21058), [`0219eef3`](https://github.com/graphql/graphiql/commit/0219eef39146495749aca2487112db52fa3bb8fd)]: - @graphiql/react@0.12.0 ## 0.1.0 ### Minor Changes - [#2724](https://github.com/graphql/graphiql/pull/2724) [`dd5db3b2`](https://github.com/graphql/graphiql/commit/dd5db3b2ee08b240ba7b77a9b7ff621115bd25f3) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add a package that exports a plugin to use the GraphiQL Explorer from OneGraph ================================================ FILE: packages/graphiql-plugin-explorer/README.md ================================================ # GraphiQL Explorer Plugin This package provides a plugin that integrates the [`GraphiQL Explorer`](https://github.com/OneGraph/graphiql-explorer) into the GraphiQL UI. ## Installation Use your preferred package manager to install the plugin: ```sh npm install @graphiql/plugin-explorer ``` Make sure to also install the required peer dependencies: ```sh npm install react react-dom graphql ``` ## Usage ```jsx import { GraphiQL } from 'graphiql'; import { createGraphiQLFetcher } from '@graphiql/toolkit'; import { explorerPlugin } from '@graphiql/plugin-explorer'; import 'graphiql/style.css'; import '@graphiql/plugin-explorer/style.css'; const fetcher = createGraphiQLFetcher({ url: 'https://swapi-graphql.netlify.app/.netlify/functions/index', }); // Pass the explorer props here if you want const explorer = explorerPlugin(); function GraphiQLWithExplorer() { return ; } ``` ## CDN bundles You can also use this plugin via an ESM-based CDN like [esm.sh](https://esm.sh). See the [CDN example](./example/index.html) for a working demo. ================================================ FILE: packages/graphiql-plugin-explorer/package.json ================================================ { "name": "@graphiql/plugin-explorer", "version": "5.1.1", "sideEffects": false, "repository": { "type": "git", "url": "https://github.com/graphql/graphiql", "directory": "packages/graphiql-plugin-explorer" }, "main": "dist/index.js", "types": "dist/index.d.ts", "license": "MIT", "keywords": [ "react", "graphql", "graphiql", "plugin", "explorer" ], "files": [ "dist" ], "exports": { "./package.json": "./package.json", "./style.css": "./dist/style.css", ".": "./dist/index.js" }, "scripts": { "types:check": "tsc --noEmit", "dev": "vite build --watch --emptyOutDir=false", "build": "vite build", "postbuild": "cp src/graphiql-explorer.d.ts dist/graphiql-explorer.d.ts" }, "dependencies": { "graphiql-explorer": "^0.9.0" }, "peerDependencies": { "@graphiql/react": "^0.37.0", "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0-alpha.2", "react": "^18 || ^19", "react-dom": "^18 || ^19" }, "devDependencies": { "@graphiql/react": "^0.37.0", "@vitejs/plugin-react": "^4.4.1", "graphql": "^16.9.0", "react": "^19.1.0", "react-dom": "^19.1.0", "typescript": "^4.6.3", "vite": "^6.3.4", "vite-plugin-dts": "^4.0.1", "vite-plugin-svgr": "^4.3.0" } } ================================================ FILE: packages/graphiql-plugin-explorer/src/graphiql-explorer.d.ts ================================================ declare module 'graphiql-explorer' { import { FragmentDefinitionNode, GraphQLArgument, GraphQLField, GraphQLInputField, GraphQLLeafType, GraphQLObjectType, GraphQLSchema, ValueNode, } from 'graphql'; import { ComponentType, ReactNode, CSSProperties } from 'react'; export type GraphiQLExplorerProps = { query: string; width?: number; title?: string; schema?: GraphQLSchema | null; onEdit?(newQuery: string): void; getDefaultFieldNames?(type: GraphQLObjectType): string[]; getDefaultScalarArgValue?( parentField: GraphQLField, arg: GraphQLArgument | GraphQLInputField, underlyingArgType: GraphQLLeafType, ): ValueNode; makeDefaultArg?( parentField: GraphQLField, arg: GraphQLArgument | GraphQLInputField, ): boolean; onToggleExplorer?(): void; explorerIsOpen?: boolean; onRunOperation?(name: string | null): void; colors?: { keyword: string; def: string; property: string; qualifier: string; attribute: string; number: string; string: string; builtin: string; string2: string; variable: string; atom: string; }; arrowOpen?: ReactNode; arrowClosed?: ReactNode; checkboxChecked?: ReactNode; checkboxUnchecked?: ReactNode; styles?: { explorerActionsStyle?: CSSProperties; buttonStyle?: CSSProperties; actionButtonStyle?: CSSProperties; }; showAttribution?: boolean; hideActions?: boolean; externalFragments?: FragmentDefinitionNode[]; }; const GraphiQLExplorer: ComponentType & { defaultValue: (arg: GraphQLLeafType) => ValueNode; }; export { GraphiQLExplorer as Explorer }; export default GraphiQLExplorer; } ================================================ FILE: packages/graphiql-plugin-explorer/src/index.css ================================================ .docExplorerWrap { height: unset !important; min-width: unset !important; width: unset !important; } .docExplorerWrap svg { display: unset; } .doc-explorer-title { font-size: var(--font-size-h2); font-weight: var(--font-weight-medium); } .doc-explorer-rhs { display: none; } .graphiql-explorer-root { font-family: var(--font-family-mono) !important; font-size: var(--font-size-body) !important; padding: 0 !important; } .graphiql-explorer-root > div > div { border-color: hsla( var(--color-neutral), var(--alpha-background-heavy) ) !important; padding-top: var(--px-16); } .graphiql-explorer-root > div { overflow: auto !important; /* override overflow: scroll */ } .graphiql-explorer-root input { background: unset; } .graphiql-explorer-root select { background: hsl(var(--color-base)) !important; border: 1px solid hsla(var(--color-neutral), var(--alpha-secondary)); border-radius: var(--border-radius-4); color: hsl(var(--color-neutral)) !important; margin: 0 var(--px-8); padding: var(--px-4) var(--px-6); } .toolbar-button { all: unset; cursor: pointer; line-height: 0 !important; margin-left: var(--px-6); color: hsl(var(--color-primary)); font-size: var(--font-size-h3) !important; } .graphiql-explorer-slug .toolbar-button, .graphiql-explorer-graphql-arguments .toolbar-button { font-size: inherit !important; } .graphiql-explorer-graphql-arguments input { line-height: 0; min-width: 2rem; } .graphiql-explorer-actions { border-color: hsla( var(--color-neutral), var(--alpha-background-heavy) ) !important; } ================================================ FILE: packages/graphiql-plugin-explorer/src/index.tsx ================================================ import { CSSProperties, FC, useCallback } from 'react'; import { GraphiQLPlugin, useGraphiQL, useGraphiQLActions, useOperationsEditorState, useOptimisticState, } from '@graphiql/react'; import { Explorer as GraphiQLExplorer, GraphiQLExplorerProps, } from 'graphiql-explorer'; import ArrowIcon from './icons/arrow.svg?react'; import FolderPlusIcon from './icons/folder-plus.svg?react'; import CheckboxUncheckedIcon from './icons/checkbox-unchecked.svg?react'; import CheckboxCheckedIcon from './icons/checkbox-checked.svg?react'; 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: Record = { buttonStyle: { cursor: 'pointer', fontSize: '2em', lineHeight: 0, }, explorerActionsStyle: { paddingTop: 'var(--px-16)', }, actionButtonStyle: {}, }; export type GraphiQLExplorerPluginProps = Omit< GraphiQLExplorerProps, 'onEdit' | 'query' >; const ExplorerPlugin: FC = props => { const { setOperationName, run } = useGraphiQLActions(); const schema = useGraphiQL(state => state.schema); // handle running the current operation from the plugin const handleRunOperation = useCallback( (operationName: string | null) => { if (operationName) { // set the plugin-defined operation name before executing setOperationName(operationName); } run(); }, [run, setOperationName], ); // load the current editor tab state into the explorer const [operationsString, handleEditOperations] = useOptimisticState( useOperationsEditorState(), ); return ( ); }; export function explorerPlugin( props?: GraphiQLExplorerPluginProps, ): GraphiQLPlugin { return { title: 'GraphiQL Explorer', icon: FolderPlusIcon, content: () => , }; } ================================================ FILE: packages/graphiql-plugin-explorer/src/vite-env.d.ts ================================================ /// /// ================================================ FILE: packages/graphiql-plugin-explorer/tsconfig.json ================================================ { "extends": "../graphiql-react/tsconfig.json" } ================================================ FILE: packages/graphiql-plugin-explorer/vite.config.mts ================================================ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import svgr from 'vite-plugin-svgr'; import dts from 'vite-plugin-dts'; import packageJSON from './package.json'; export default defineConfig({ plugins: [ react(), svgr({ svgrOptions: { titleProp: true, }, }), dts({ include: ['src/**'] }), ], css: { transformer: 'lightningcss', }, build: { minify: false, lib: { entry: 'src/index.tsx', fileName: (_format, filePath) => `${filePath}.js`, formats: ['es'], cssFileName: 'style', }, rollupOptions: { external: [ 'react/jsx-runtime', // Exclude peer dependencies and dependencies from bundle ...Object.keys({ ...packageJSON.peerDependencies, ...packageJSON.dependencies, }), ], }, }, }); ================================================ FILE: packages/graphiql-plugin-history/CHANGELOG.md ================================================ # @graphiql/plugin-history ## 0.4.1 ### Patch Changes - Updated dependencies [[`6e5d5fc`](https://github.com/graphql/graphiql/commit/6e5d5fce9a7eb5770f40300fc153e0b9b10edfbf), [`293beed`](https://github.com/graphql/graphiql/commit/293beed772baa2be834cad5f19e1aee0628e15cc)]: - @graphiql/react@0.37.0 ## 0.4.0 ### Minor Changes - [#4074](https://github.com/graphql/graphiql/pull/4074) [`fd3f9e6`](https://github.com/graphql/graphiql/commit/fd3f9e6a91be728a69a136ad8680f6e3c7241198) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Ensure `storage` and `theme` store values aren't shared between GraphiQL instances. Deprecate `useTheme` and `useStorage` hooks in favour of values from `useGraphiQL` and `useGraphiQLActions` hooks feat(`@graphiql/plugin-history`/`@graphiql/plugin-doc-explorer`): move `@graphiql/react` to `peerDependencies` - [#4077](https://github.com/graphql/graphiql/pull/4077) [`3d41e11`](https://github.com/graphql/graphiql/commit/3d41e113fbf53930fd1b519b6d1330d0f4b23b7b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - add new example [Usage GraphiQL 5 with Vite, React Router and `ssr: true`](https://github.com/graphql/graphiql/tree/main/examples/example-graphiql-vite-react-router) ### Patch Changes - Updated dependencies [[`3a0a755`](https://github.com/graphql/graphiql/commit/3a0a75569c6b318f5dc27d62000bcc9b0536c6fd), [`fd3f9e6`](https://github.com/graphql/graphiql/commit/fd3f9e6a91be728a69a136ad8680f6e3c7241198), [`416e3a0`](https://github.com/graphql/graphiql/commit/416e3a05e9473eb2abd444da61ecfb8614020d14), [`3d41e11`](https://github.com/graphql/graphiql/commit/3d41e113fbf53930fd1b519b6d1330d0f4b23b7b)]: - @graphiql/react@0.36.0 ## 0.3.0 ### Minor Changes - [#3990](https://github.com/graphql/graphiql/pull/3990) [`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - allow multiple independent instances of GraphiQL on the same page - store `onClickReference` in query editor in React `ref` - remove `onClickReference` from variable editor - fix shortcut text per OS for run query in execute query button's tooltip and in default query - allow override all default GraphiQL plugins - adjust operation argument color to be purple from GraphiQL v2 on dark/light theme - [#4025](https://github.com/graphql/graphiql/pull/4025) [`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - set "importsNotUsedAsValues": "error" in tsconfig - [#4011](https://github.com/graphql/graphiql/pull/4011) [`30bc3f9`](https://github.com/graphql/graphiql/commit/30bc3f9cae4dbb11649a0952dad092e192ad653c) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix execute query shortcut in query editor, run it even there are no operations in query editor fix plugin store, save last opened plugin in storage - [#4026](https://github.com/graphql/graphiql/pull/4026) [`7fb5ac3`](https://github.com/graphql/graphiql/commit/7fb5ac38b8ec27f0234adc06aacf42e71f6a259b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - deprecate `useExplorerContext`, `useHistoryContext`, `usePrettifyEditors`, `useCopyQuery`, `useMergeQuery`, `useExecutionContext`, `usePluginContext`, `useSchemaContext`, `useStorageContext` hooks - fix response editor overflow on `` - export `GraphiQLProps` type - allow `children: ReactNode` for `` - change `ToolbarMenu` component: - The `label` and `className` props were removed - The `button` prop should now be a button element - document `useGraphiQL` and `useGraphiQLActions` hooks in `@graphiql/react` README.md - rename `useThemeStore` to `useTheme` - [#3950](https://github.com/graphql/graphiql/pull/3950) [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - remove `useQueryEditor`, `useVariableEditor`, `useHeaderEditor`, `useResponseEditor` hooks - remove `UseHeaderEditorArgs`, `UseQueryEditorArgs`, `UseResponseEditorArgs`, `UseVariableEditorArgs` exports - rename components - `StorageContextProvider` => `StorageStore` - `EditorContextProvider` => `EditorStore` - `SchemaContextProvider` => `SchemaStore` - `ExecutionContextProvider` => `ExecutionStore` - `HistoryContextProvider` => `HistoryStore` - `ExplorerContextProvider` => `ExplorerStore` ### Patch Changes - [#3949](https://github.com/graphql/graphiql/pull/3949) [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - replace `onCopyQuery` hook with `copyQuery` function - replace `onMergeQuery` hook with `mergeQuery` function - replace `onPrettifyEditors` hook with `prettifyEditors` function - remove `fetcher` prop from `SchemaContextProvider` and `schemaStore` and add `fetcher` to `executionStore` - add `onCopyQuery` and `onPrettifyQuery` props to `EditorContextProvider` - remove exports (use `GraphiQLProvider`) - `EditorContextProvider` - `ExecutionContextProvider` - `PluginContextProvider` - `SchemaContextProvider` - `StorageContextProvider` - `ExecutionContextType` - `PluginContextType` - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - prefer `getComputedStyle` over `window.getComputedStyle` - [#3234](https://github.com/graphql/graphiql/pull/3234) [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Migration from Codemirror to [Monaco Editor](https://github.com/microsoft/monaco-editor) Replacing `codemirror-graphql` with [`monaco-graphql`](https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql) Support for comments in **Variables** and **Headers** editors - Updated dependencies [[`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92), [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e), [`866a8f3`](https://github.com/graphql/graphiql/commit/866a8f39a27d213315ccc55ec06353bb3280b270), [`4936492`](https://github.com/graphql/graphiql/commit/49364924d0da05a86f7c6c3139d44aed0e474531), [`3c0ad34`](https://github.com/graphql/graphiql/commit/3c0ad34a8f2f9d0f912db9597f608d7405c2bd83), [`1e3ec84`](https://github.com/graphql/graphiql/commit/1e3ec8455706e62e6cae306df58d3343ec6b612d), [`0c8e390`](https://github.com/graphql/graphiql/commit/0c8e3906cf58055f898cb173b2e912a494ae8439), [`0a08642`](https://github.com/graphql/graphiql/commit/0a0864268da4f340e30a1e9b8191d34e33ffbfa7), [`cff3da5`](https://github.com/graphql/graphiql/commit/cff3da541184d36d1c2e5c919dd4231e9905ccbb), [`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b), [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91), [`30bc3f9`](https://github.com/graphql/graphiql/commit/30bc3f9cae4dbb11649a0952dad092e192ad653c), [`4b39f11`](https://github.com/graphql/graphiql/commit/4b39f1118d008c2fac6e2df9c94a3f3271c4eeb9), [`7fb5ac3`](https://github.com/graphql/graphiql/commit/7fb5ac38b8ec27f0234adc06aacf42e71f6a259b), [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb)]: - @graphiql/react@0.35.0 ## 0.3.0-rc.3 ### Minor Changes - [#4025](https://github.com/graphql/graphiql/pull/4025) [`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - set "importsNotUsedAsValues": "error" in tsconfig - [#4026](https://github.com/graphql/graphiql/pull/4026) [`7fb5ac3`](https://github.com/graphql/graphiql/commit/7fb5ac38b8ec27f0234adc06aacf42e71f6a259b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - deprecate `useExplorerContext`, `useHistoryContext`, `usePrettifyEditors`, `useCopyQuery`, `useMergeQuery`, `useExecutionContext`, `usePluginContext`, `useSchemaContext`, `useStorageContext` hooks - fix response editor overflow on `` - export `GraphiQLProps` type - allow `children: ReactNode` for `` - change `ToolbarMenu` component: - The `label` and `className` props were removed - The `button` prop should now be a button element - document `useGraphiQL` and `useGraphiQLActions` hooks in `@graphiql/react` README.md - rename `useThemeStore` to `useTheme` ### Patch Changes - Updated dependencies [[`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b), [`7fb5ac3`](https://github.com/graphql/graphiql/commit/7fb5ac38b8ec27f0234adc06aacf42e71f6a259b)]: - @graphiql/react@0.35.0-rc.8 ## 0.3.0-rc.2 ### Minor Changes - [#4011](https://github.com/graphql/graphiql/pull/4011) [`30bc3f9`](https://github.com/graphql/graphiql/commit/30bc3f9cae4dbb11649a0952dad092e192ad653c) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix execute query shortcut in query editor, run it even there are no operations in query editor fix plugin store, save last opened plugin in storage ### Patch Changes - Updated dependencies [[`30bc3f9`](https://github.com/graphql/graphiql/commit/30bc3f9cae4dbb11649a0952dad092e192ad653c)]: - @graphiql/react@0.35.0-rc.4 ## 0.3.0-rc.1 ### Minor Changes - [#3990](https://github.com/graphql/graphiql/pull/3990) [`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - allow multiple independent instances of GraphiQL on the same page - store `onClickReference` in query editor in React `ref` - remove `onClickReference` from variable editor - fix shortcut text per OS for run query in execute query button's tooltip and in default query - allow override all default GraphiQL plugins - adjust operation argument color to be purple from GraphiQL v2 on dark/light theme ### Patch Changes - Updated dependencies [[`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92)]: - @graphiql/react@0.35.0-rc.1 ## 0.3.0-rc.0 ### Minor Changes - [#3950](https://github.com/graphql/graphiql/pull/3950) [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - remove `useQueryEditor`, `useVariableEditor`, `useHeaderEditor`, `useResponseEditor` hooks - remove `UseHeaderEditorArgs`, `UseQueryEditorArgs`, `UseResponseEditorArgs`, `UseVariableEditorArgs` exports - rename components - `StorageContextProvider` => `StorageStore` - `EditorContextProvider` => `EditorStore` - `SchemaContextProvider` => `SchemaStore` - `ExecutionContextProvider` => `ExecutionStore` - `HistoryContextProvider` => `HistoryStore` - `ExplorerContextProvider` => `ExplorerStore` ### Patch Changes - [#3949](https://github.com/graphql/graphiql/pull/3949) [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - replace `onCopyQuery` hook with `copyQuery` function - replace `onMergeQuery` hook with `mergeQuery` function - replace `onPrettifyEditors` hook with `prettifyEditors` function - remove `fetcher` prop from `SchemaContextProvider` and `schemaStore` and add `fetcher` to `executionStore` - add `onCopyQuery` and `onPrettifyQuery` props to `EditorContextProvider` - remove exports (use `GraphiQLProvider`) - `EditorContextProvider` - `ExecutionContextProvider` - `PluginContextProvider` - `SchemaContextProvider` - `StorageContextProvider` - `ExecutionContextType` - `PluginContextType` - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - prefer `getComputedStyle` over `window.getComputedStyle` - [#3234](https://github.com/graphql/graphiql/pull/3234) [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Migration from Codemirror to [Monaco Editor](https://github.com/microsoft/monaco-editor) Replacing `codemirror-graphql` with [`monaco-graphql`](https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql) Support for comments in **Variables** and **Headers** editors - Updated dependencies [[`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e), [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91), [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb)]: - @graphiql/react@0.35.0-rc.0 ## 0.2.2 ### Patch Changes - [#3970](https://github.com/graphql/graphiql/pull/3970) [`7054591`](https://github.com/graphql/graphiql/commit/70545912d1b3bb9e0c45e766a5c89896a9c4dfb7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - revert https://github.com/graphql/graphiql/pull/3946 to have support multiple embedded graphiql instances on the same page - Updated dependencies [[`7054591`](https://github.com/graphql/graphiql/commit/70545912d1b3bb9e0c45e766a5c89896a9c4dfb7)]: - @graphiql/toolkit@0.11.3 - @graphiql/react@0.34.1 ## 0.2.1 ### Patch Changes - [#3946](https://github.com/graphql/graphiql/pull/3946) [`71755b7`](https://github.com/graphql/graphiql/commit/71755b7f412f8f3dd9f5194d3f1e0168b9ad07af) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - replace `useAutoCompleteLeafs` hook with `getAutoCompleteLeafs` function - Updated dependencies [[`71755b7`](https://github.com/graphql/graphiql/commit/71755b7f412f8f3dd9f5194d3f1e0168b9ad07af), [`6d631e2`](https://github.com/graphql/graphiql/commit/6d631e2e558d038476fe235b1506bc52ecf68781)]: - @graphiql/react@0.34.0 ## 0.2.0 ### Minor Changes - [#3947](https://github.com/graphql/graphiql/pull/3947) [`fa78481`](https://github.com/graphql/graphiql/commit/fa784819ce020346052901019079fb5b44af6ef0) Thanks [@dimaMachina](https://github.com/dimaMachina)! - refactor `useStorage`, `useDocExplorer` and `useHistory` hooks ### Patch Changes - [#3945](https://github.com/graphql/graphiql/pull/3945) [`117627b`](https://github.com/graphql/graphiql/commit/117627b451607198dd7b9dc19e76da8a71d14b71) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand, replace `usePluginContext` with `usePluginStore` hook - [#3942](https://github.com/graphql/graphiql/pull/3942) [`00c8605`](https://github.com/graphql/graphiql/commit/00c8605e1f3068e6547a5a9e969571a86a57f921) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand, replace `useStorageContext` with `useStorage` hook - Updated dependencies [[`117627b`](https://github.com/graphql/graphiql/commit/117627b451607198dd7b9dc19e76da8a71d14b71), [`fa78481`](https://github.com/graphql/graphiql/commit/fa784819ce020346052901019079fb5b44af6ef0), [`7275472`](https://github.com/graphql/graphiql/commit/727547236bbd4fc721069ceae63eb8a6acffa57e), [`00c8605`](https://github.com/graphql/graphiql/commit/00c8605e1f3068e6547a5a9e969571a86a57f921)]: - @graphiql/react@0.33.0 ## 0.1.0 ### Minor Changes - [#3935](https://github.com/graphql/graphiql/pull/3935) [`5985e13`](https://github.com/graphql/graphiql/commit/5985e135fcc38a0ce90bf5a5d2cc344ec6b36aab) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/plugin-history): migrate React context to zustand, replace `useHistoryContext` with `useHistory`, `useHistoryActions` hooks ### Patch Changes - [#3939](https://github.com/graphql/graphiql/pull/3939) [`69ad489`](https://github.com/graphql/graphiql/commit/69ad489678d0096432d5c4b1749d87343f4ed1f7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - prefer `React.FC` type when declaring React components - Updated dependencies [[`2bfbb06`](https://github.com/graphql/graphiql/commit/2bfbb06e416cabc46951a137b61a12a571f0c937), [`69ad489`](https://github.com/graphql/graphiql/commit/69ad489678d0096432d5c4b1749d87343f4ed1f7), [`2500288`](https://github.com/graphql/graphiql/commit/250028863f6eefe4167ff9f9c23168ccf0a85b7b)]: - @graphiql/react@0.32.2 ## 0.0.2 ### Patch Changes - Updated dependencies [[`98d13a3`](https://github.com/graphql/graphiql/commit/98d13a3e515eb70aaf5a5ba669c680d5959fef67)]: - @graphiql/react@0.32.0 ## 0.0.1 ### Patch Changes - [#3911](https://github.com/graphql/graphiql/pull/3911) [`e7c436b`](https://github.com/graphql/graphiql/commit/e7c436b329a68981bdbd2b662be94875a546a1d6) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - export `cn` from `@graphiql/react` - remove following exports from `@graphiql/react` and move them in `@graphiql/plugin-history` package: - `History` - `HistoryContext` - `HistoryContextType` - `HistoryContextProvider` - `useHistoryContext` - `HISTORY_PLUGIN` - remove types from `@graphiql/react` (use `ComponentProps` instead): - `HistoryContextProviderProps` - `ExecutionContextProviderProps` - `EditorContextProviderProps` - `ExplorerContextProviderProps` - `PluginContextProviderProps` - `SchemaContextProviderProps` - `StorageContextProviderProps` - `GraphiQLProviderProps` - Updated dependencies [[`e7c436b`](https://github.com/graphql/graphiql/commit/e7c436b329a68981bdbd2b662be94875a546a1d6)]: - @graphiql/react@0.31.0 ================================================ FILE: packages/graphiql-plugin-history/README.md ================================================ # `@graphiql/plugin-history` ## API - `useHistory`: Persists executed requests in storage - `useHistoryActions`: Actions related to the history ================================================ FILE: packages/graphiql-plugin-history/package.json ================================================ { "name": "@graphiql/plugin-history", "version": "0.4.1", "sideEffects": false, "repository": { "type": "git", "url": "https://github.com/graphql/graphiql", "directory": "packages/graphiql-plugin-history" }, "homepage": "https://github.com/graphql/graphiql/tree/master/packages/graphiql-plugin-history#readme", "bugs": { "url": "https://github.com/graphql/graphiql/issues?q=issue+label:@graphiql/plugin-history" }, "license": "MIT", "exports": { "./package.json": "./package.json", "./style.css": "./dist/style.css", ".": "./dist/index.js" }, "types": "dist/index.d.ts", "keywords": [ "react", "graphql", "graphiql", "plugin", "history" ], "files": [ "dist" ], "scripts": { "types:check": "tsc --noEmit", "dev": "vite build --watch --emptyOutDir=false", "build": "vite build", "test": "vitest" }, "peerDependencies": { "@graphiql/react": "^0.37.0", "react": "^18 || ^19", "react-compiler-runtime": "19.1.0-rc.1", "react-dom": "^18 || ^19" }, "dependencies": { "@graphiql/toolkit": "^0.11.3", "zustand": "^5" }, "devDependencies": { "@testing-library/react": "^16.1.0", "@vitejs/plugin-react": "^4.4.1", "babel-plugin-react-compiler": "19.1.0-rc.1", "react": "^19.1.0", "react-dom": "^19.1.0", "vite": "^6.3.4", "vite-plugin-dts": "^4.5.3" } } ================================================ FILE: packages/graphiql-plugin-history/setup-files.ts ================================================ 'use no memo'; import '@testing-library/jest-dom'; // to make it works like Jest (auto-mocking) vi.mock('zustand'); vi.mock('monaco-editor'); ================================================ FILE: packages/graphiql-plugin-history/src/__tests__/components.spec.tsx ================================================ import type { Mock } from 'vitest'; import { fireEvent, render } from '@testing-library/react'; import type { ComponentProps } from 'react'; import { formatQuery, HistoryItem } from '../components'; import { HistoryStore } from '../context'; import { Tooltip, GraphiQLProvider, useGraphiQL } from '@graphiql/react'; vi.mock('@graphiql/react', async () => { const originalModule = await vi.importActual('@graphiql/react'); const mockedSetQueryEditor = vi.fn(); const mockedSetVariableEditor = vi.fn(); const mockedSetHeaderEditor = vi.fn(); return { ...originalModule, useGraphiQL() { return { queryEditor: { setValue: mockedSetQueryEditor }, variableEditor: { setValue: mockedSetVariableEditor }, headerEditor: { setValue: mockedSetHeaderEditor }, tabs: [], storage: { get() {}, }, }; }, }; }); const mockQuery = /* GraphQL */ ` query Test($string: String) { test { hasArgs(string: $string) } } `; const mockVariables = JSON.stringify({ string: 'string' }); const mockHeaders = JSON.stringify({ foo: 'bar' }); const mockOperationName = 'Test'; type QueryHistoryItemProps = ComponentProps; const QueryHistoryItemWithContext: typeof HistoryItem = props => { return ( ); }; const baseMockProps: QueryHistoryItemProps = { item: { query: mockQuery, variables: mockVariables, headers: mockHeaders, favorite: false, }, }; function getMockProps( customProps?: Partial, ): QueryHistoryItemProps { return { ...baseMockProps, ...customProps, item: { ...baseMockProps.item, ...customProps?.item }, }; } describe('QueryHistoryItem', () => { const { queryEditor, variableEditor, headerEditor } = useGraphiQL( state => state, ); const mockedSetQueryEditor = queryEditor!.setValue as Mock; const mockedSetVariableEditor = variableEditor!.setValue as Mock; const mockedSetHeaderEditor = headerEditor!.setValue as Mock; beforeEach(() => { mockedSetQueryEditor.mockClear(); mockedSetVariableEditor.mockClear(); mockedSetHeaderEditor.mockClear(); }); it('renders operationName if label is not provided', () => { const otherMockProps = { item: { operationName: mockOperationName } }; const props = getMockProps(otherMockProps); const { container } = render(); expect( container.querySelector('button.graphiql-history-item-label')! .textContent, ).toBe(mockOperationName); }); it('renders a string version of the query if label or operation name are not provided', () => { const { container } = render( , ); expect( container.querySelector('button.graphiql-history-item-label')! .textContent, ).toBe(formatQuery(mockQuery)); }); it('selects the item when history label button is clicked', () => { const otherMockProps = { item: { operationName: mockOperationName } }; const mockProps = getMockProps(otherMockProps); const { container } = render( , ); fireEvent.click( container.querySelector('button.graphiql-history-item-label')!, ); expect(mockedSetQueryEditor).toHaveBeenCalledTimes(1); expect(mockedSetQueryEditor).toHaveBeenCalledWith(mockProps.item.query); expect(mockedSetVariableEditor).toHaveBeenCalledTimes(1); expect(mockedSetVariableEditor).toHaveBeenCalledWith( mockProps.item.variables, ); expect(mockedSetHeaderEditor).toHaveBeenCalledTimes(1); expect(mockedSetHeaderEditor).toHaveBeenCalledWith(mockProps.item.headers); }); it('renders label input if the edit label button is clicked', () => { const { container, getByLabelText } = render( , ); fireEvent.click(getByLabelText('Edit label')); expect(container.querySelectorAll('li.editable').length).toBe(1); expect(container.querySelectorAll('input').length).toBe(1); expect( container.querySelectorAll('button.graphiql-history-item-label').length, ).toBe(0); }); }); ================================================ FILE: packages/graphiql-plugin-history/src/components.tsx ================================================ import type { QueryStoreItem } from '@graphiql/toolkit'; import { FC, MouseEventHandler, useEffect, useRef, useState } from 'react'; import { cn, CloseIcon, PenIcon, StarFilledIcon, StarIcon, TrashIcon, useGraphiQL, pick, Button, Tooltip, UnStyledButton, } from '@graphiql/react'; import { useHistory, useHistoryActions } from './context'; // Fix error from react-compiler // Support value blocks (conditional, logical, optional chaining, etc.) within a try/catch statement function handleDelete( items: QueryStoreItem[], deleteFromHistory: ReturnType['deleteFromHistory'], ) { for (const item of items) { deleteFromHistory(item, true); } } export const History: FC = () => { const all = useHistory(); const { deleteFromHistory } = useHistoryActions(); // Reverse items since we push them in so want the latest one at the top, and pass the // original index in case multiple items share the same label so we can edit the correct item let items = all .slice() .map((item, i) => ({ ...item, index: i })) .reverse(); const favorites = items.filter(item => item.favorite); if (favorites.length) { items = items.filter(item => !item.favorite); } const [clearStatus, setClearStatus] = useState<'success' | 'error' | null>( null, ); useEffect(() => { if (clearStatus) { // reset the button after a couple seconds setTimeout(() => { setClearStatus(null); }, 2000); } }, [clearStatus]); const handleClearStatus = () => { try { handleDelete(items, deleteFromHistory); setClearStatus('success'); } catch { setClearStatus('error'); } }; const hasFavorites = Boolean(favorites.length); const hasItems = Boolean(items.length); return (
History {(clearStatus || hasItems) && ( )}
{hasFavorites && (
    {favorites.map(item => ( ))}
)} {hasFavorites && hasItems && (
)} {hasItems && (
    {items.map(item => ( ))}
)}
); }; type QueryHistoryItemProps = { item: QueryStoreItem & { index?: number }; }; export const HistoryItem: FC = props => { const { editLabel, toggleFavorite, deleteFromHistory, setActive } = useHistoryActions(); const { headerEditor, queryEditor, variableEditor } = useGraphiQL( pick('headerEditor', 'queryEditor', 'variableEditor'), ); const inputRef = useRef(null); const buttonRef = useRef(null); const [isEditable, setIsEditable] = useState(false); useEffect(() => { if (isEditable) { inputRef.current?.focus(); } }, [isEditable]); const displayName = props.item.label || props.item.operationName || formatQuery(props.item.query); const handleSave = () => { setIsEditable(false); const { index, ...item } = props.item; editLabel({ ...item, label: inputRef.current?.value }, index); }; const handleClose = () => { setIsEditable(false); }; const handleEditLabel: MouseEventHandler = e => { e.stopPropagation(); setIsEditable(true); }; const handleHistoryItemClick: MouseEventHandler = () => { const { query, variables, headers } = props.item; queryEditor?.setValue(query ?? ''); variableEditor?.setValue(variables ?? ''); headerEditor?.setValue(headers ?? ''); setActive(props.item); }; const handleDeleteItemFromHistory: MouseEventHandler< HTMLButtonElement > = e => { e.stopPropagation(); deleteFromHistory(props.item); }; const handleToggleFavorite: MouseEventHandler = e => { e.stopPropagation(); toggleFavorite(props.item); }; return (
  • {isEditable ? ( <> { if (e.key === 'Esc') { setIsEditable(false); } else if (e.key === 'Enter') { setIsEditable(false); editLabel({ ...props.item, label: e.currentTarget.value }); } }} placeholder="Type a label" /> Save ) : ( <> {displayName} {props.item.favorite ? ( )}
  • ); }; export function formatQuery(query?: string) { return query ?.split('\n') .map(line => line.replace(/#(.*)/, '')) .join(' ') .replaceAll('{', ' { ') .replaceAll('}', ' } ') .replaceAll(/[\s]{2,}/g, ' '); } ================================================ FILE: packages/graphiql-plugin-history/src/context.ts ================================================ import { FC, ReactElement, ReactNode, useEffect } from 'react'; import { createStore } from 'zustand'; import { HistoryStore as ToolkitHistoryStore, QueryStoreItem, } from '@graphiql/toolkit'; import { useGraphiQL, pick, createBoundedUseStore } from '@graphiql/react'; const historyStore = createStore((set, get) => ({ historyStorage: null, actions: { addToHistory(operation) { const { historyStorage } = get(); historyStorage?.updateHistory(operation); set({}); // trigger rerender }, editLabel(operation, index) { const { historyStorage } = get(); historyStorage?.editLabel(operation, index); set({}); // trigger rerender }, toggleFavorite(operation) { const { historyStorage } = get(); historyStorage?.toggleFavorite(operation); set({}); // trigger rerender }, setActive: item => item, deleteFromHistory(item, clearFavorites) { const { historyStorage } = get(); historyStorage?.deleteHistory(item, clearFavorites); set({}); // trigger rerender }, }, })); type HistoryStoreType = { // Can be `null` if History plugin saved in `localStorage` as `visiblePlugin` historyStorage: ToolkitHistoryStore | null; actions: { /** * Add an operation to the history. * @param operation The operation that was executed, consisting of the query, * variables, headers, and operation name. */ addToHistory(operation: { query?: string; variables?: string; headers?: string; operationName?: string; }): void; /** * Change the custom label of an item from the history. * @param args An object containing the label (`undefined` if it should be * unset) and properties that identify the history item that the label should * be applied to. (This can result in the label being applied to multiple * history items.) * @param index Index to edit. Without it, will look for the first index matching the * operation, which may lead to misleading results if multiple items have the same label */ editLabel( args: { query?: string; variables?: string; headers?: string; operationName?: string; label?: string; favorite?: boolean; }, index?: number, ): void; /** * Toggle the favorite state of an item from the history. * @param args An object containing the favorite state (`undefined` if it * should be unset) and properties that identify the history item that the * label should be applied to. (This can result in the label being applied * to multiple history items.) */ toggleFavorite(args: { query?: string; variables?: string; headers?: string; operationName?: string; label?: string; favorite?: boolean; }): void; /** * Delete an operation from the history. * @param args The operation that was executed, consisting of the query, * variables, headers, and operation name. * @param clearFavorites This is only if you press the 'clear' button */ deleteFromHistory(args: QueryStoreItem, clearFavorites?: boolean): void; /** * If you need to know when an item in history is set as active to customize * your application. */ setActive(args: QueryStoreItem): void; }; }; type HistoryStoreProps = { children: ReactNode; /** * The maximum number of executed operations to store. * @default 20 */ maxHistoryLength?: number; }; /** * The functions send the entire operation so users can customize their own application and get * access to the operation plus any additional props they added for their needs (i.e., build their * own functions that may save to a backend instead of localStorage and might need an id property * added to the `QueryStoreItem`) */ export const HistoryStore: FC = ({ maxHistoryLength = 20, children, }) => { const { isFetching, tabs, activeTabIndex, storage } = useGraphiQL( pick('isFetching', 'tabs', 'activeTabIndex', 'storage'), ); const activeTab = tabs[activeTabIndex]!; const historyStorage = // eslint-disable-line react-hooks/exhaustive-deps -- false positive, code is optimized by React Compiler new ToolkitHistoryStore(storage, maxHistoryLength); useEffect(() => { historyStore.setState({ historyStorage }); }, [historyStorage]); useEffect(() => { if (!isFetching) { return; } const { addToHistory } = historyStore.getState().actions; addToHistory({ query: activeTab.query ?? undefined, variables: activeTab.variables ?? undefined, headers: activeTab.headers ?? undefined, operationName: activeTab.operationName ?? undefined, }); }, [isFetching, activeTab]); return children as ReactElement; }; const useHistoryStore = createBoundedUseStore(historyStore); const EMPTY_ARRAY: QueryStoreItem[] = []; export const useHistory = () => useHistoryStore(state => state.historyStorage?.queries ?? EMPTY_ARRAY); /** * Actions are functions used to update values in your store. They are static and never change. * @see https://tkdodo.eu/blog/working-with-zustand#separate-actions-from-state */ export const useHistoryActions = () => useHistoryStore(state => state.actions); ================================================ FILE: packages/graphiql-plugin-history/src/deprecated.ts ================================================ import { useHistory, useHistoryActions } from './context'; /** * @deprecated Use `useHistoryActions` and `useHistory` hooks instead. */ export function useHistoryContext() { const actions = useHistoryActions(); const items = useHistory(); return { ...actions, items }; } ================================================ FILE: packages/graphiql-plugin-history/src/index.ts ================================================ import { GraphiQLPlugin, HistoryIcon } from '@graphiql/react'; import './style.css'; import { History } from './components'; export const HISTORY_PLUGIN: GraphiQLPlugin = { title: 'History', icon: HistoryIcon, content: History, }; export { History }; export { HistoryStore, useHistory, useHistoryActions } from './context'; export * from './deprecated'; ================================================ FILE: packages/graphiql-plugin-history/src/style.css ================================================ .graphiql-history-header { font-size: var(--font-size-h2); font-weight: var(--font-weight-medium); display: flex; justify-content: space-between; align-items: center; } .graphiql-history-header button { font-size: var(--font-size-inline-code); padding: var(--px-6) var(--px-10); } .graphiql-history-items { margin: var(--px-16) 0 0; list-style: none; padding: 0; } .graphiql-history-item { border-radius: var(--border-radius-4); color: hsla(var(--color-neutral), var(--alpha-secondary)); display: flex; font-size: var(--font-size-inline-code); font-family: var(--font-family-mono); height: 34px; &:hover { color: hsl(var(--color-neutral)); background-color: hsla(var(--color-neutral), var(--alpha-background-light)); } &:not(:first-child) { margin-top: var(--px-4); } &.editable { background-color: hsla( var(--color-primary), var(--alpha-background-medium) ); & > input { background: transparent; border: none; flex: 1; margin: 0; outline: none; padding: 0 var(--px-10); width: 100%; &::placeholder { color: hsla(var(--color-neutral), var(--alpha-secondary)); } } & > button { color: hsl(var(--color-primary)); padding: 0 var(--px-10); &:active { background-color: hsla( var(--color-primary), var(--alpha-background-heavy) ); } &:focus { outline: hsl(var(--color-primary)) auto 1px; } & > svg { display: block; } } } } button.graphiql-history-item-label { flex: 1; padding: var(--px-8) var(--px-10); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } button.graphiql-history-item-action { align-items: center; color: hsla(var(--color-neutral), var(--alpha-secondary)); display: flex; padding: var(--px-8) var(--px-6); &:hover { color: hsl(var(--color-neutral)); } & > svg { height: 14px; width: 14px; } } .graphiql-history-item-spacer { height: var(--px-16); } ================================================ FILE: packages/graphiql-plugin-history/tsconfig.json ================================================ { "extends": "../graphiql-react/tsconfig.json" } ================================================ FILE: packages/graphiql-plugin-history/vite.config.mts ================================================ import { defineConfig, PluginOption } from 'vite'; import react from '@vitejs/plugin-react'; import type { PluginOptions as ReactCompilerConfig } from 'babel-plugin-react-compiler'; import packageJSON from './package.json' assert { type: 'json' }; import dts from 'vite-plugin-dts'; import { reactCompilerConfig as $reactCompilerConfig } from '../graphiql-react/vite.config.mjs'; export const reactCompilerConfig: Partial = { ...$reactCompilerConfig, sources(filename) { if (filename.includes('__tests__')) { return false; } return filename.includes('/graphiql-plugin-history/src/'); }, }; export const plugins: PluginOption[] = [ react({ babel: { plugins: [['babel-plugin-react-compiler', reactCompilerConfig]], }, }), dts({ include: ['src/**'], exclude: ['**/*.spec.{ts,tsx}', '**/__tests__/'], }), ]; export default defineConfig({ plugins, css: { transformer: 'lightningcss', }, build: { minify: false, sourcemap: true, lib: { entry: 'src/index.ts', fileName(_format, entryName) { const filePath = entryName.replace(/\.svg$/, ''); return `${filePath}.js`; }, formats: ['es'], cssFileName: 'style', }, rollupOptions: { external: [ 'react/jsx-runtime', // Exclude peer dependencies and dependencies from bundle ...Object.keys(packageJSON.peerDependencies), ...Object.keys(packageJSON.dependencies), ], output: { // Separate chunks for all modules preserveModules: true, }, }, }, }); ================================================ FILE: packages/graphiql-plugin-history/vitest.config.mts ================================================ import path from 'node:path'; import { defineConfig } from 'vitest/config'; import { plugins } from './vite.config.mjs'; export default defineConfig({ plugins, test: { globals: true, environment: 'jsdom', setupFiles: ['./setup-files.ts', '../graphiql/setup-window.ts'], alias: [ { // Fixes Error: Failed to resolve entry for package "monaco-editor". The package may have incorrect main/module/exports specified in its package.json. find: /^monaco-editor$/, replacement: path.resolve( '../../node_modules/monaco-editor/esm/vs/editor/editor.api', ), }, ], }, }); ================================================ FILE: packages/graphiql-react/CHANGELOG.md ================================================ # @graphiql/react ## 0.37.3 ### Patch Changes - [#4133](https://github.com/graphql/graphiql/pull/4133) [`1bc6568`](https://github.com/graphql/graphiql/commit/1bc6568da947394c216342ae75fb509fdbf03390) Thanks [@dimaMachina](https://github.com/dimaMachina)! - to fix esm.sh example we should pin `monaco-editor` peer dependency to versions `≥ 0.20.0 and < 0.53`, since `monaco-editor@^0.53.0` isn't supported yet with `monaco-graphql` - Updated dependencies [[`1bc6568`](https://github.com/graphql/graphiql/commit/1bc6568da947394c216342ae75fb509fdbf03390)]: - monaco-graphql@1.7.3 ## 0.37.2 ### Patch Changes - [#4124](https://github.com/graphql/graphiql/pull/4124) [`d77abe6`](https://github.com/graphql/graphiql/commit/d77abe647e700ef8949a16c3bccda648d5c6adae) Thanks [@dimaMachina](https://github.com/dimaMachina)! - pin `monaco-editor` to `0.52.2` ## 0.37.1 ### Patch Changes - [#4081](https://github.com/graphql/graphiql/pull/4081) [`4950dec`](https://github.com/graphql/graphiql/commit/4950decaddb816ef3e3d22d814d976d94405029e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat: add loader for initial loading of operation editor fix: adjust command palette `width`, `border` and remove `box-shadow` feat: add short cut `Cmd/Ctrl + ,` for opening GraphiQL settings dialog ## 0.37.0 ### Minor Changes - [#4078](https://github.com/graphql/graphiql/pull/4078) [`6e5d5fc`](https://github.com/graphql/graphiql/commit/6e5d5fce9a7eb5770f40300fc153e0b9b10edfbf) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix color in the F1 popup should be graphiql primary color and add deprecated exports for `useEditorStore`, `useExecutionStore`, `usePluginStore` and `useSchemaStore` ### Patch Changes - [#4079](https://github.com/graphql/graphiql/pull/4079) [`293beed`](https://github.com/graphql/graphiql/commit/293beed772baa2be834cad5f19e1aee0628e15cc) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove legacy codemirror CSS styles ## 0.36.0 ### Minor Changes - [#4071](https://github.com/graphql/graphiql/pull/4071) [`3a0a755`](https://github.com/graphql/graphiql/commit/3a0a75569c6b318f5dc27d62000bcc9b0536c6fd) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(graphql-language-service): export `getContextAtPosition` feat(graphiql): dynamically import `monaco-editor` and `monaco-graphql` When using GraphiQL in Next.js app, you no longer need to use `next/dynamic`: ```diff -import dynamic from 'next/dynamic' -const GraphiQL = dynamic(() => import('graphiql').then(mod => mod.GraphiQL), { - ssr: false -}) +import { GraphiQL } from 'graphiql' ``` - [#4074](https://github.com/graphql/graphiql/pull/4074) [`fd3f9e6`](https://github.com/graphql/graphiql/commit/fd3f9e6a91be728a69a136ad8680f6e3c7241198) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Ensure `storage` and `theme` store values aren't shared between GraphiQL instances. Deprecate `useTheme` and `useStorage` hooks in favour of values from `useGraphiQL` and `useGraphiQLActions` hooks feat(`@graphiql/plugin-history`/`@graphiql/plugin-doc-explorer`): move `@graphiql/react` to `peerDependencies` - [#4077](https://github.com/graphql/graphiql/pull/4077) [`3d41e11`](https://github.com/graphql/graphiql/commit/3d41e113fbf53930fd1b519b6d1330d0f4b23b7b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - add new example [Usage GraphiQL 5 with Vite, React Router and `ssr: true`](https://github.com/graphql/graphiql/tree/main/examples/example-graphiql-vite-react-router) ### Patch Changes - [#4076](https://github.com/graphql/graphiql/pull/4076) [`416e3a0`](https://github.com/graphql/graphiql/commit/416e3a05e9473eb2abd444da61ecfb8614020d14) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix broken `useOperationsEditorState` and `useEditorState` hook and add unit tests - Updated dependencies [[`3a0a755`](https://github.com/graphql/graphiql/commit/3a0a75569c6b318f5dc27d62000bcc9b0536c6fd)]: - monaco-graphql@1.7.2 - graphql-language-service@5.5.0 ## 0.35.6 ### Patch Changes - [#4069](https://github.com/graphql/graphiql/pull/4069) [`142f3f2`](https://github.com/graphql/graphiql/commit/142f3f2529c668aa1a6ba2f7269cf4b7e2fd3e61) Thanks [@dimaMachina](https://github.com/dimaMachina)! - reduce bundle size, import `prettier` dynamically to avoid bundling Prettier diff from vite example ```diff -dist/assets/index-BMgFrxsd.js 4,911.53 kB │ gzip: 1,339.77 kB +dist/assets/index-BlpzusGL.js 4,221.28 kB │ gzip: 1,145.58 kB ``` ## 0.35.5 ### Patch Changes - [#4063](https://github.com/graphql/graphiql/pull/4063) [`44b18e4`](https://github.com/graphql/graphiql/commit/44b18e4ed054d757568b5cfedc43614fd7ea3fc9) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix `useOperationsEditorState` wasn't returned updated return value ## 0.35.4 ### Patch Changes - [#4052](https://github.com/graphql/graphiql/pull/4052) [`9b54581`](https://github.com/graphql/graphiql/commit/9b54581e74a7e6c6354a810c2288869fb85f24eb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix multiple GraphiQL instances, suffix a unique id for operation, request headers, variables and response URI. E.g., the first GraphiQL instance will have: - `1-operation.graphql` - `1-request-headers.json` - `1-variables.json` - `1-response.json` The 2nd instance will have: - `2-operation.graphql` - `2-request-headers.json` - `2-variables.json` - `2-response.json` etc. - [#4049](https://github.com/graphql/graphiql/pull/4049) [`2c0586d`](https://github.com/graphql/graphiql/commit/2c0586d1f3db8fe8dc604032010cc9840d10b72d) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - use `allowTrailingComma` option in jsonc parser to make `tryParseJsonObject` sync - parse introspection headers with jsonc parser - use prettier format for operation editor since we already use prettier for jsonc editors - [#4050](https://github.com/graphql/graphiql/pull/4050) [`002f133`](https://github.com/graphql/graphiql/commit/002f1336db4bdafa01cff1964a1b56ba858699eb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix can't access property "jsonDefaults" ## 0.35.3 ### Patch Changes - [#4046](https://github.com/graphql/graphiql/pull/4046) [`8b56462`](https://github.com/graphql/graphiql/commit/8b564625b2470652db3c27dc70b0f85d5bbc3a0f) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Enable font ligatures in monaco-editors fix incorrect caret position on Windows ## 0.35.2 ### Patch Changes - [#4044](https://github.com/graphql/graphiql/pull/4044) [`68b347c`](https://github.com/graphql/graphiql/commit/68b347c78faa80cc00397fc1705dbf114c1f374b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix `Fixes Uncaught Error: can't access property "offsetNode", hitResult is null` on Mozilla ## 0.35.1 ### Patch Changes - [#4037](https://github.com/graphql/graphiql/pull/4037) [`e548574`](https://github.com/graphql/graphiql/commit/e548574101313349ffa11e6b5a36d1f68be3679c) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix execute button becomes unstyled if there are several queries present ## 0.35.0 ### Minor Changes - [#3990](https://github.com/graphql/graphiql/pull/3990) [`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - allow multiple independent instances of GraphiQL on the same page - store `onClickReference` in query editor in React `ref` - remove `onClickReference` from variable editor - fix shortcut text per OS for run query in execute query button's tooltip and in default query - allow override all default GraphiQL plugins - adjust operation argument color to be purple from GraphiQL v2 on dark/light theme - [#3949](https://github.com/graphql/graphiql/pull/3949) [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - replace `onCopyQuery` hook with `copyQuery` function - replace `onMergeQuery` hook with `mergeQuery` function - replace `onPrettifyEditors` hook with `prettifyEditors` function - remove `fetcher` prop from `SchemaContextProvider` and `schemaStore` and add `fetcher` to `executionStore` - add `onCopyQuery` and `onPrettifyQuery` props to `EditorContextProvider` - remove exports (use `GraphiQLProvider`) - `EditorContextProvider` - `ExecutionContextProvider` - `PluginContextProvider` - `SchemaContextProvider` - `StorageContextProvider` - `ExecutionContextType` - `PluginContextType` - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - prefer `getComputedStyle` over `window.getComputedStyle` - [#3999](https://github.com/graphql/graphiql/pull/3999) [`866a8f3`](https://github.com/graphql/graphiql/commit/866a8f39a27d213315ccc55ec06353bb3280b270) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update graphiql-cdn example to show how to load workers with esm.sh - [#4009](https://github.com/graphql/graphiql/pull/4009) [`4936492`](https://github.com/graphql/graphiql/commit/49364924d0da05a86f7c6c3139d44aed0e474531) Thanks [@dimaMachina](https://github.com/dimaMachina)! - separate store actions from state, add `useGraphiQLActions` state - [#4005](https://github.com/graphql/graphiql/pull/4005) [`1e3ec84`](https://github.com/graphql/graphiql/commit/1e3ec8455706e62e6cae306df58d3343ec6b612d) Thanks [@dimaMachina](https://github.com/dimaMachina)! - support `externalFragments` prop and remove `validationRules` prop - [#4003](https://github.com/graphql/graphiql/pull/4003) [`0c8e390`](https://github.com/graphql/graphiql/commit/0c8e3906cf58055f898cb173b2e912a494ae8439) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove `readOnly` prop document `keyMap` prop was removed in migration guide - [#3735](https://github.com/graphql/graphiql/pull/3735) [`0a08642`](https://github.com/graphql/graphiql/commit/0a0864268da4f340e30a1e9b8191d34e33ffbfa7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - Remove `query`, `variables`, `headers`, and `response` props from `` and `` - Add `initialQuery`, `initialVariables` and `initialHeaders` props - Fix `defaultQuery`, when is set will only be used for the first tab. When opening more tabs, the query editor will start out empty - remove `useSynchronizeValue` hook - [#4017](https://github.com/graphql/graphiql/pull/4017) [`cff3da5`](https://github.com/graphql/graphiql/commit/cff3da541184d36d1c2e5c919dd4231e9905ccbb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - extract graphiql sidebar to react component - [#4025](https://github.com/graphql/graphiql/pull/4025) [`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - set "importsNotUsedAsValues": "error" in tsconfig - [#3234](https://github.com/graphql/graphiql/pull/3234) [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Migration from Codemirror to [Monaco Editor](https://github.com/microsoft/monaco-editor) Replacing `codemirror-graphql` with [`monaco-graphql`](https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql) Support for comments in **Variables** and **Headers** editors - [#4011](https://github.com/graphql/graphiql/pull/4011) [`30bc3f9`](https://github.com/graphql/graphiql/commit/30bc3f9cae4dbb11649a0952dad092e192ad653c) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix execute query shortcut in query editor, run it even there are no operations in query editor fix plugin store, save last opened plugin in storage - [#4014](https://github.com/graphql/graphiql/pull/4014) [`4b39f11`](https://github.com/graphql/graphiql/commit/4b39f1118d008c2fac6e2df9c94a3f3271c4eeb9) Thanks [@dimaMachina](https://github.com/dimaMachina)! - extract storage key constants - [#4026](https://github.com/graphql/graphiql/pull/4026) [`7fb5ac3`](https://github.com/graphql/graphiql/commit/7fb5ac38b8ec27f0234adc06aacf42e71f6a259b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - deprecate `useExplorerContext`, `useHistoryContext`, `usePrettifyEditors`, `useCopyQuery`, `useMergeQuery`, `useExecutionContext`, `usePluginContext`, `useSchemaContext`, `useStorageContext` hooks - fix response editor overflow on `` - export `GraphiQLProps` type - allow `children: ReactNode` for `` - change `ToolbarMenu` component: - The `label` and `className` props were removed - The `button` prop should now be a button element - document `useGraphiQL` and `useGraphiQLActions` hooks in `@graphiql/react` README.md - rename `useThemeStore` to `useTheme` - [#3950](https://github.com/graphql/graphiql/pull/3950) [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - remove `useQueryEditor`, `useVariableEditor`, `useHeaderEditor`, `useResponseEditor` hooks - remove `UseHeaderEditorArgs`, `UseQueryEditorArgs`, `UseResponseEditorArgs`, `UseVariableEditorArgs` exports - rename components - `StorageContextProvider` => `StorageStore` - `EditorContextProvider` => `EditorStore` - `SchemaContextProvider` => `SchemaStore` - `ExecutionContextProvider` => `ExecutionStore` - `HistoryContextProvider` => `HistoryStore` - `ExplorerContextProvider` => `ExplorerStore` ### Patch Changes - [#4020](https://github.com/graphql/graphiql/pull/4020) [`3c0ad34`](https://github.com/graphql/graphiql/commit/3c0ad34a8f2f9d0f912db9597f608d7405c2bd83) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - run cypress tests in React strict mode - fix `defaultQuery` with empty string does not result in an empty default query - fix `useDidUpdate` in React strict mode - Updated dependencies [[`1e3ec84`](https://github.com/graphql/graphiql/commit/1e3ec8455706e62e6cae306df58d3343ec6b612d)]: - monaco-graphql@1.7.1 ## 0.35.0-rc.9 ### Minor Changes - [#3735](https://github.com/graphql/graphiql/pull/3735) [`0a08642`](https://github.com/graphql/graphiql/commit/0a0864268da4f340e30a1e9b8191d34e33ffbfa7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - Remove `query`, `variables`, `headers`, and `response` props from `` and `` - Add `initialQuery`, `initialVariables` and `initialHeaders` props - Fix `defaultQuery`, when is set will only be used for the first tab. When opening more tabs, the query editor will start out empty - remove `useSynchronizeValue` hook ## 0.35.0-rc.8 ### Minor Changes - [#4025](https://github.com/graphql/graphiql/pull/4025) [`6a50740`](https://github.com/graphql/graphiql/commit/6a507407c7c63bfc779ad383054ab3a8c003ef5b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - set "importsNotUsedAsValues": "error" in tsconfig - [#4026](https://github.com/graphql/graphiql/pull/4026) [`7fb5ac3`](https://github.com/graphql/graphiql/commit/7fb5ac38b8ec27f0234adc06aacf42e71f6a259b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - deprecate `useExplorerContext`, `useHistoryContext`, `usePrettifyEditors`, `useCopyQuery`, `useMergeQuery`, `useExecutionContext`, `usePluginContext`, `useSchemaContext`, `useStorageContext` hooks - fix response editor overflow on `` - export `GraphiQLProps` type - allow `children: ReactNode` for `` - change `ToolbarMenu` component: - The `label` and `className` props were removed - The `button` prop should now be a button element - document `useGraphiQL` and `useGraphiQLActions` hooks in `@graphiql/react` README.md - rename `useThemeStore` to `useTheme` ## 0.35.0-rc.7 ### Patch Changes - [#4020](https://github.com/graphql/graphiql/pull/4020) [`3c0ad34`](https://github.com/graphql/graphiql/commit/3c0ad34a8f2f9d0f912db9597f608d7405c2bd83) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - run cypress tests in React strict mode - fix `defaultQuery` with empty string does not result in an empty default query - fix `useDidUpdate` in React strict mode ## 0.35.0-rc.6 ### Minor Changes - [#4017](https://github.com/graphql/graphiql/pull/4017) [`cff3da5`](https://github.com/graphql/graphiql/commit/cff3da541184d36d1c2e5c919dd4231e9905ccbb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - extract graphiql sidebar to react component ## 0.35.0-rc.5 ### Minor Changes - [#4014](https://github.com/graphql/graphiql/pull/4014) [`4b39f11`](https://github.com/graphql/graphiql/commit/4b39f1118d008c2fac6e2df9c94a3f3271c4eeb9) Thanks [@dimaMachina](https://github.com/dimaMachina)! - extract storage key constants ## 0.35.0-rc.4 ### Minor Changes - [#4011](https://github.com/graphql/graphiql/pull/4011) [`30bc3f9`](https://github.com/graphql/graphiql/commit/30bc3f9cae4dbb11649a0952dad092e192ad653c) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix execute query shortcut in query editor, run it even there are no operations in query editor fix plugin store, save last opened plugin in storage ## 0.35.0-rc.3 ### Minor Changes - [#4009](https://github.com/graphql/graphiql/pull/4009) [`4936492`](https://github.com/graphql/graphiql/commit/49364924d0da05a86f7c6c3139d44aed0e474531) Thanks [@dimaMachina](https://github.com/dimaMachina)! - separate store actions from state, add `useGraphiQLActions` state ## 0.35.0-rc.2 ### Minor Changes - [#3999](https://github.com/graphql/graphiql/pull/3999) [`866a8f3`](https://github.com/graphql/graphiql/commit/866a8f39a27d213315ccc55ec06353bb3280b270) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update graphiql-cdn example to show how to load workers with esm.sh - [#4005](https://github.com/graphql/graphiql/pull/4005) [`1e3ec84`](https://github.com/graphql/graphiql/commit/1e3ec8455706e62e6cae306df58d3343ec6b612d) Thanks [@dimaMachina](https://github.com/dimaMachina)! - support `externalFragments` prop and remove `validationRules` prop - [#4003](https://github.com/graphql/graphiql/pull/4003) [`0c8e390`](https://github.com/graphql/graphiql/commit/0c8e3906cf58055f898cb173b2e912a494ae8439) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove `readOnly` prop document `keyMap` prop was removed in migration guide ### Patch Changes - Updated dependencies [[`1e3ec84`](https://github.com/graphql/graphiql/commit/1e3ec8455706e62e6cae306df58d3343ec6b612d)]: - monaco-graphql@1.7.1-rc.0 ## 0.35.0-rc.1 ### Minor Changes - [#3990](https://github.com/graphql/graphiql/pull/3990) [`27e7eb6`](https://github.com/graphql/graphiql/commit/27e7eb60247437d992c1fcdcc6870cb7892d4b92) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - allow multiple independent instances of GraphiQL on the same page - store `onClickReference` in query editor in React `ref` - remove `onClickReference` from variable editor - fix shortcut text per OS for run query in execute query button's tooltip and in default query - allow override all default GraphiQL plugins - adjust operation argument color to be purple from GraphiQL v2 on dark/light theme ## 0.35.0-rc.0 ### Minor Changes - [#3949](https://github.com/graphql/graphiql/pull/3949) [`0844dc1`](https://github.com/graphql/graphiql/commit/0844dc1ca89a5d8fce0dc23658cca6987ff8443e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - replace `onCopyQuery` hook with `copyQuery` function - replace `onMergeQuery` hook with `mergeQuery` function - replace `onPrettifyEditors` hook with `prettifyEditors` function - remove `fetcher` prop from `SchemaContextProvider` and `schemaStore` and add `fetcher` to `executionStore` - add `onCopyQuery` and `onPrettifyQuery` props to `EditorContextProvider` - remove exports (use `GraphiQLProvider`) - `EditorContextProvider` - `ExecutionContextProvider` - `PluginContextProvider` - `SchemaContextProvider` - `StorageContextProvider` - `ExecutionContextType` - `PluginContextType` - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - prefer `getComputedStyle` over `window.getComputedStyle` - [#3234](https://github.com/graphql/graphiql/pull/3234) [`86a96e5`](https://github.com/graphql/graphiql/commit/86a96e5f1779b5d0e84ad4179dbd6c5d4947fb91) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Migration from Codemirror to [Monaco Editor](https://github.com/microsoft/monaco-editor) Replacing `codemirror-graphql` with [`monaco-graphql`](https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql) Support for comments in **Variables** and **Headers** editors - [#3950](https://github.com/graphql/graphiql/pull/3950) [`2455907`](https://github.com/graphql/graphiql/commit/245590708cea52ff6f1bcce8664781f7e56029cb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - remove `useQueryEditor`, `useVariableEditor`, `useHeaderEditor`, `useResponseEditor` hooks - remove `UseHeaderEditorArgs`, `UseQueryEditorArgs`, `UseResponseEditorArgs`, `UseVariableEditorArgs` exports - rename components - `StorageContextProvider` => `StorageStore` - `EditorContextProvider` => `EditorStore` - `SchemaContextProvider` => `SchemaStore` - `ExecutionContextProvider` => `ExecutionStore` - `HistoryContextProvider` => `HistoryStore` - `ExplorerContextProvider` => `ExplorerStore` ## 0.34.1 ### Patch Changes - [#3970](https://github.com/graphql/graphiql/pull/3970) [`7054591`](https://github.com/graphql/graphiql/commit/70545912d1b3bb9e0c45e766a5c89896a9c4dfb7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - revert https://github.com/graphql/graphiql/pull/3946 to have support multiple embedded graphiql instances on the same page - Updated dependencies [[`7054591`](https://github.com/graphql/graphiql/commit/70545912d1b3bb9e0c45e766a5c89896a9c4dfb7)]: - @graphiql/toolkit@0.11.3 ## 0.34.0 ### Minor Changes - [#3946](https://github.com/graphql/graphiql/pull/3946) [`71755b7`](https://github.com/graphql/graphiql/commit/71755b7f412f8f3dd9f5194d3f1e0168b9ad07af) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand: - replace `useExecutionContext` with `useExecutionStore` hook - replace `useEditorContext` with `useEditorStore` hook - replace `useAutoCompleteLeafs` hook with `getAutoCompleteLeafs` function ### Patch Changes - [#3963](https://github.com/graphql/graphiql/pull/3963) [`6d631e2`](https://github.com/graphql/graphiql/commit/6d631e2e558d038476fe235b1506bc52ecf68781) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix headers are not set in the refetch of introspection query ## 0.33.0 ### Minor Changes - [#3945](https://github.com/graphql/graphiql/pull/3945) [`117627b`](https://github.com/graphql/graphiql/commit/117627b451607198dd7b9dc19e76da8a71d14b71) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand, replace `usePluginContext` with `usePluginStore` hook - [#3947](https://github.com/graphql/graphiql/pull/3947) [`fa78481`](https://github.com/graphql/graphiql/commit/fa784819ce020346052901019079fb5b44af6ef0) Thanks [@dimaMachina](https://github.com/dimaMachina)! - refactor `useStorage`, `useDocExplorer` and `useHistory` hooks - [#3943](https://github.com/graphql/graphiql/pull/3943) [`7275472`](https://github.com/graphql/graphiql/commit/727547236bbd4fc721069ceae63eb8a6acffa57e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand, replace `useSchemaContext` with `useSchemaStore` hook - [#3942](https://github.com/graphql/graphiql/pull/3942) [`00c8605`](https://github.com/graphql/graphiql/commit/00c8605e1f3068e6547a5a9e969571a86a57f921) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat(@graphiql/react): migrate React context to zustand, replace `useStorageContext` with `useStorage` hook ## 0.32.2 ### Patch Changes - [#3936](https://github.com/graphql/graphiql/pull/3936) [`2bfbb06`](https://github.com/graphql/graphiql/commit/2bfbb06e416cabc46951a137b61a12a571f0c937) Thanks [@dimaMachina](https://github.com/dimaMachina)! - add scroll-x to graphiql tabs area - [#3939](https://github.com/graphql/graphiql/pull/3939) [`69ad489`](https://github.com/graphql/graphiql/commit/69ad489678d0096432d5c4b1749d87343f4ed1f7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - prefer `React.FC` type when declaring React components - [#3937](https://github.com/graphql/graphiql/pull/3937) [`2500288`](https://github.com/graphql/graphiql/commit/250028863f6eefe4167ff9f9c23168ccf0a85b7b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove `Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format` warnings on SSR ## 0.32.1 ### Patch Changes - [#3929](https://github.com/graphql/graphiql/pull/3929) [`96dcbdf`](https://github.com/graphql/graphiql/commit/96dcbdfae25a10de668cdcb6826fd0cb857a361b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix: `ReferenceError: window is not defined` when using with SSR ## 0.32.0 ### Minor Changes - [#3916](https://github.com/graphql/graphiql/pull/3916) [`98d13a3`](https://github.com/graphql/graphiql/commit/98d13a3e515eb70aaf5a5ba669c680d5959fef67) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - remove the following exports from `@graphiql/react` and move them in `@graphiql/plugin-doc-explorer` package: - Argument - DefaultValue - DeprecationReason - Directive - DocExplorer - ExplorerContext - ExplorerContextProvider - ExplorerSection - FieldDocumentation - FieldLink - SchemaDocumentation - Search - TypeDocumentation - TypeLink - useExplorerContext - DOC_EXPLORER_PLUGIN - ExplorerContextType - ExplorerFieldDef - ExplorerNavStack - ExplorerNavStackItem - add new `referencePlugin` prop on `PluginContextProviderProps` component for plugin which is used to display the reference documentation when selecting a type. ## 0.31.0 ### Minor Changes - [#3911](https://github.com/graphql/graphiql/pull/3911) [`e7c436b`](https://github.com/graphql/graphiql/commit/e7c436b329a68981bdbd2b662be94875a546a1d6) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - export `cn` from `@graphiql/react` - remove following exports from `@graphiql/react` and move them in `@graphiql/plugin-history` package: - `History` - `HistoryContext` - `HistoryContextType` - `HistoryContextProvider` - `useHistoryContext` - `HISTORY_PLUGIN` - remove types from `@graphiql/react` (use `ComponentProps` instead): - `HistoryContextProviderProps` - `ExecutionContextProviderProps` - `EditorContextProviderProps` - `ExplorerContextProviderProps` - `PluginContextProviderProps` - `SchemaContextProviderProps` - `StorageContextProviderProps` - `GraphiQLProviderProps` ## 0.30.0 ### Minor Changes - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Add support for `onPrettifyQuery` callback to enable customised query formatting - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Update GraphiQL CDN example using ESM-based CDN esm.sh - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - drop commonjs build files - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - generate types with `vite-plugin-dts` - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - 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 - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - `style.css` import was changed ## Migration ```diff -import '@graphiql/react/dist/style.css'; +import '@graphiql/react/style.css'; ``` - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update `vite` and related dependencies - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove `createComponentGroup` utility in favour `Object.assign` - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - new looks of tabs - fix `disableTabs` when `Add tab` button is still shown ### Patch Changes - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Respect Markdown format: ignore single newline - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - use `vite build --watch` instead of `vite` for `dev` script because we don't need development server for them do not use `vite-plugin-dts` when generating umd build - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - replace `overflow-y: scroll` with `overflow-y: auto` - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - rollback `position: absolute` style for `.graphiql-logo` because tabs will behind logo - [#3904](https://github.com/graphql/graphiql/pull/3904) [`d1395f9`](https://github.com/graphql/graphiql/commit/d1395f987b3f9c70b69ec5ad7283c63594dd7602) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - prefer `location` over `window.location` - prefer `navigator` over `window.navigator` ## 1.0.0-alpha.4 ### Minor Changes - [#3733](https://github.com/graphql/graphiql/pull/3733) [`8dbddb5`](https://github.com/graphql/graphiql/commit/8dbddb50273720d76f895af6b783b04204c68e03) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Add support for `onPrettifyQuery` callback to enable customised query formatting ## 1.0.0-alpha.3 ### Patch Changes - [#3414](https://github.com/graphql/graphiql/pull/3414) [`f8b719f`](https://github.com/graphql/graphiql/commit/f8b719f215a79038d1b2a54ddfef461fd849a912) Thanks [@leonardehrenfried](https://github.com/leonardehrenfried)! - Respect Markdown format: ignore single newline - [#3730](https://github.com/graphql/graphiql/pull/3730) [`360a038`](https://github.com/graphql/graphiql/commit/360a0385d4ef0105beb8e76044a78f5cd43c9448) Thanks [@dimaMachina](https://github.com/dimaMachina)! - rollback `position: absolute` style for `.graphiql-logo` because tabs will behind logo ## 1.0.0-alpha.2 ### Patch Changes - [#3720](https://github.com/graphql/graphiql/pull/3720) [`79f3abf`](https://github.com/graphql/graphiql/commit/79f3abf9b697c448442e32eb5a21b7ff720bc242) Thanks [@dimaMachina](https://github.com/dimaMachina)! - replace `overflow-y: scroll` with `overflow-y: auto` ## 1.0.0-alpha.1 ### Minor Changes - [#3717](https://github.com/graphql/graphiql/pull/3717) [`bf0c4e7`](https://github.com/graphql/graphiql/commit/bf0c4e7236f4a68448063aa0c6a4ed439e869a9f) Thanks [@dimaMachina](https://github.com/dimaMachina)! - remove `createComponentGroup` utility in favour `Object.assign` ## 1.0.0-alpha.0 ### Major Changes - [#3709](https://github.com/graphql/graphiql/pull/3709) [`9baf1f0`](https://github.com/graphql/graphiql/commit/9baf1f0fc9f32404fbb8bf57b3d1c2c2c8778ddb) Thanks [@dimaMachina](https://github.com/dimaMachina)! - `style.css` import was changed ## Migration ```diff -import '@graphiql/react/dist/style.css'; +import '@graphiql/react/style.css'; ``` ### Minor Changes - [#3702](https://github.com/graphql/graphiql/pull/3702) [`00415d2`](https://github.com/graphql/graphiql/commit/00415d2940c4d76a4a9e683e9fa0504ba97dd627) Thanks [@dimaMachina](https://github.com/dimaMachina)! - generate types with `vite-plugin-dts` - [#3644](https://github.com/graphql/graphiql/pull/3644) [`3c1a345`](https://github.com/graphql/graphiql/commit/3c1a345acd9bf07b45bc230009cb57c51c425673) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - new looks of tabs - fix `disableTabs` when `Add tab` button is still shown ### Patch Changes - [#3705](https://github.com/graphql/graphiql/pull/3705) [`8ff87d7`](https://github.com/graphql/graphiql/commit/8ff87d7b6b3d5d12b539612a39ca3abf7e631106) Thanks [@dimaMachina](https://github.com/dimaMachina)! - use `vite build --watch` instead of `vite` for `dev` script because we don't need development server for them do not use `vite-plugin-dts` when generating umd build - [#3692](https://github.com/graphql/graphiql/pull/3692) [`82bc961`](https://github.com/graphql/graphiql/commit/82bc961a33c4e9da29dffb4a603035a4909f49ad) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - prefer `location` over `window.location` - prefer `navigator` over `window.navigator` ## 0.29.0 ### Minor Changes - [#3826](https://github.com/graphql/graphiql/pull/3826) [`cb29e9f`](https://github.com/graphql/graphiql/commit/cb29e9fbe1362778bc327513fc884c4ec419775e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - - remove react compiler custom patch - update `react-compiler-runtime` to use `19.1.0-rc.1` version ### Patch Changes - [#3896](https://github.com/graphql/graphiql/pull/3896) [`1adc40c`](https://github.com/graphql/graphiql/commit/1adc40cc56dbf79296bb857156e6adce1c44dcbe) Thanks [@dimaMachina](https://github.com/dimaMachina)! - bump eslint, eslint-plugins and fix new warnings - Updated dependencies [[`1adc40c`](https://github.com/graphql/graphiql/commit/1adc40cc56dbf79296bb857156e6adce1c44dcbe)]: - graphql-language-service@5.3.1 - codemirror-graphql@2.2.1 - @graphiql/toolkit@0.11.2 ## 0.28.2 ### Patch Changes - [#3843](https://github.com/graphql/graphiql/pull/3843) [`16b5698`](https://github.com/graphql/graphiql/commit/16b56982ce4de62c850380fe25698c3893551c5a) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix regression in documentation explorer search when clicking on results in dropdown ## 0.28.1 ### Patch Changes - [#3837](https://github.com/graphql/graphiql/pull/3837) [`5e76a4f`](https://github.com/graphql/graphiql/commit/5e76a4f3c8b089a1de0c92c9b9c1edc2ae3f49d4) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix query builder updated only first selected field in query editor due recent enabled react-compiler ## 0.28.0 ### Minor Changes - [#3821](https://github.com/graphql/graphiql/pull/3821) [`3633d61`](https://github.com/graphql/graphiql/commit/3633d61c3c597adf60c0ec1bbf98cf6a1f49beed) Thanks [@dimaMachina](https://github.com/dimaMachina)! - compile source code with react-compiler, remove `useMemo` and `useCallback` usages ## 0.27.1 ### Patch Changes - [#3824](https://github.com/graphql/graphiql/pull/3824) [`72f06bc`](https://github.com/graphql/graphiql/commit/72f06bc52a9bdc0cb146d65861ba7364717bbdf5) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Exclude `codemirror/...` and `codemirror-graphql/...` imports from bundle - Updated dependencies [[`7cdcabf`](https://github.com/graphql/graphiql/commit/7cdcabf9d401683e90c995476b187c6f8ea70f63)]: - codemirror-graphql@2.2.0 ## 0.27.0 ### Minor Changes - [#3806](https://github.com/graphql/graphiql/pull/3806) [`f86e2bc`](https://github.com/graphql/graphiql/commit/f86e2bce40826b3d07755f91b37a72051de00f9c) Thanks [@simmerer](https://github.com/simmerer)! - Fix: removed deprecated usage of Fn.prototype.caller ## 0.26.2 ### Patch Changes - [#3751](https://github.com/graphql/graphiql/pull/3751) [`b8538d8`](https://github.com/graphql/graphiql/commit/b8538d87421edb086b32d4eb2e30a3f7d9d9e893) Thanks [@dimaMachina](https://github.com/dimaMachina)! - replace deprecated `navigator.platform` with `navigator.userAgent` fix placeholder `⌘ K` in doc explorer search input for non mac devices, replace by `Ctrl K` - Updated dependencies [[`b8538d8`](https://github.com/graphql/graphiql/commit/b8538d87421edb086b32d4eb2e30a3f7d9d9e893)]: - codemirror-graphql@2.1.1 ## 0.26.1 ### Patch Changes - [#3743](https://github.com/graphql/graphiql/pull/3743) [`7275c19`](https://github.com/graphql/graphiql/commit/7275c19b174f06bd031f49b33912c1babf29ccb0) Thanks [@dimaMachina](https://github.com/dimaMachina)! - create instance of `new HistoryStore` and `new StorageAPI` only on mount, use function with `useState` - Updated dependencies [[`21c4409`](https://github.com/graphql/graphiql/commit/21c44096c0c0b23cea955a574d1110cb19ab6405), [`2ad4e75`](https://github.com/graphql/graphiql/commit/2ad4e7505385fefd252b9aa8ea2233cbaeca7f6a)]: - @graphiql/toolkit@0.11.0 ## 0.26.0 ### Minor Changes - [#3619](https://github.com/graphql/graphiql/pull/3619) [`9aef83a`](https://github.com/graphql/graphiql/commit/9aef83a32aeb5f193a3ff0f191c95d09eb0d70b6) Thanks [@Yahkob](https://github.com/Yahkob)! - add new prop `defaultTheme` to set the default color preference theme ### Patch Changes - [#3441](https://github.com/graphql/graphiql/pull/3441) [`959ed21`](https://github.com/graphql/graphiql/commit/959ed21815682fc439f64d78e23e603a8f313a6f) Thanks [@cimdalli](https://github.com/cimdalli)! - fix: set query editor to `defaultQuery` while adding a new tab or GraphiQL's default query ```graphql # Welcome to GraphiQL # # GraphiQL is an in-browser tool for writing, validating, and # testing GraphQL queries. ... ``` ## 0.25.0 ### Minor Changes - [#3532](https://github.com/graphql/graphiql/pull/3532) [`7404e8e`](https://github.com/graphql/graphiql/commit/7404e8e6c62b06107f452142493297ec70f1649c) Thanks [@Cr4xy](https://github.com/Cr4xy)! - Add webp support to graphiql results image-preview ## 0.24.0 ### Minor Changes - [#3682](https://github.com/graphql/graphiql/pull/3682) [`6c9f0df`](https://github.com/graphql/graphiql/commit/6c9f0df83ea4afe7fa59f84d83d59fba73dc3931) Thanks [@yaacovCR](https://github.com/yaacovCR)! - Support v17 of `graphql-js` from `17.0.0-alpha.2` forward. Includes support for the latest incremental delivery response format. For further details, see https://github.com/graphql/defer-stream-wg/discussions/69. ### Patch Changes - Updated dependencies [[`6c9f0df`](https://github.com/graphql/graphiql/commit/6c9f0df83ea4afe7fa59f84d83d59fba73dc3931)]: - graphql-language-service@5.3.0 - codemirror-graphql@2.1.0 - @graphiql/toolkit@0.10.0 ## 0.23.1 ### Patch Changes - [#3552](https://github.com/graphql/graphiql/pull/3552) [`6a0a5e5`](https://github.com/graphql/graphiql/commit/6a0a5e590b7b526af8a66c59a27ec3d0144af572) Thanks [@klippx](https://github.com/klippx)! - do not clear `defaultHeaders` when switching between tabs upon reload ## 0.23.0 ### Minor Changes - [#3657](https://github.com/graphql/graphiql/pull/3657) [`5bc7b84`](https://github.com/graphql/graphiql/commit/5bc7b84531b6404553787615d61a5cbcc96c1d6f) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update vite to v5 ### Patch Changes - [#3637](https://github.com/graphql/graphiql/pull/3637) [`fdec377`](https://github.com/graphql/graphiql/commit/fdec377f28ac0d918a219b78dfa2d8f0996ff84d) Thanks [@dimaMachina](https://github.com/dimaMachina)! - update eslint plugins and fix errors - [#3656](https://github.com/graphql/graphiql/pull/3656) [`93c7e9f`](https://github.com/graphql/graphiql/commit/93c7e9fd224cb4f1e9a86b3391efc1e0ef6e1e3f) Thanks [@dimaMachina](https://github.com/dimaMachina)! - set `build.minify: false` for cjs/esm builds since minified variable names change every build time - Updated dependencies [[`fdec377`](https://github.com/graphql/graphiql/commit/fdec377f28ac0d918a219b78dfa2d8f0996ff84d), [`56c6f45`](https://github.com/graphql/graphiql/commit/56c6f4571dd0dfda307ed11c5afb8c837ad928b0)]: - codemirror-graphql@2.0.13 - graphql-language-service@5.2.2 - @graphiql/toolkit@0.9.2 ## 0.22.4 ### Patch Changes - [#3634](https://github.com/graphql/graphiql/pull/3634) [`adf0ba01`](https://github.com/graphql/graphiql/commit/adf0ba019902dcac2e49ccee69b79a6665c4766d) Thanks [@dimaMachina](https://github.com/dimaMachina)! - when alpha is `1`, use `hsl` instead of `hsla` ## 0.22.3 ### Patch Changes - [#3624](https://github.com/graphql/graphiql/pull/3624) [`335d830c`](https://github.com/graphql/graphiql/commit/335d830c2a4e551ef97fbeff8ed7c538ff5cd4af) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix doc explorer search input is cut off while clicking on autocomplete results ## 0.22.2 ### Patch Changes - [#3602](https://github.com/graphql/graphiql/pull/3602) [`03ab3a6b`](https://github.com/graphql/graphiql/commit/03ab3a6b76378591ef79a828d80cc69b0b8f2842) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Avoid using deprecated Component.defaultProps for icon titles - Updated dependencies [[`aa6dbbb4`](https://github.com/graphql/graphiql/commit/aa6dbbb45bf51c1966537640fbe5c4f375735c8d)]: - graphql-language-service@5.2.1 - codemirror-graphql@2.0.12 ## 0.22.1 ### Patch Changes - [#3597](https://github.com/graphql/graphiql/pull/3597) [`224b43f5`](https://github.com/graphql/graphiql/commit/224b43f5473456f264a82998d48a34a441537f54) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix TypeScript type of the `label` prop of the `Tooltip` component ## 0.22.0 ### Minor Changes - [#3580](https://github.com/graphql/graphiql/pull/3580) [`d48f4ef5`](https://github.com/graphql/graphiql/commit/d48f4ef56578dad7ec90f33458353791e463ef7b) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Implement correct merging of incremental responses (@defer/@stream) ## 0.21.0 ### Minor Changes - [#3569](https://github.com/graphql/graphiql/pull/3569) [`5d051054`](https://github.com/graphql/graphiql/commit/5d05105469c3f0cbeb5e294da1cf6ff2355e4eb5) Thanks [@AaronMoat](https://github.com/AaronMoat)! - Update to markdown-it 14.x ## 0.20.4 ### Patch Changes - Updated dependencies [[`fc7de5a7`](https://github.com/graphql/graphiql/commit/fc7de5a75f4b23dd62dd630b705895b5fa5d0a03)]: - codemirror-graphql@2.0.11 ## 0.20.3 ### Patch Changes - [#3526](https://github.com/graphql/graphiql/pull/3526) [`2b6ea316`](https://github.com/graphql/graphiql/commit/2b6ea3166c8d8e152f16d87c878aa8a66f1b3775) Thanks [@benjie](https://github.com/benjie)! - Add new `useOptimisticState` hook that can wrap a useState-like hook to perform optimistic caching of state changes, this helps to avoid losing characters when the user is typing rapidly. Example of usage: `const [state, setState] = useOptimisticState(useOperationsEditorState());` ## 0.20.2 ### Patch Changes - [#3447](https://github.com/graphql/graphiql/pull/3447) [`e89c432d`](https://github.com/graphql/graphiql/commit/e89c432d8d2b91f087b683360f23e0686462bc02) Thanks [@acao](https://github.com/acao)! - Remove initialState for new hooks, add `additionalComponent` to toolbar to allow buttons to use context ## 0.20.1 ### Patch Changes - [#3445](https://github.com/graphql/graphiql/pull/3445) [`39bf31d1`](https://github.com/graphql/graphiql/commit/39bf31d15b1e7fb5f235ec9adc1ce8081536de4a) Thanks [@acao](https://github.com/acao)! - Export new hooks ## 0.20.0 ### Minor Changes - [#3443](https://github.com/graphql/graphiql/pull/3443) [`f6afd22d`](https://github.com/graphql/graphiql/commit/f6afd22d3f5a20089759042f16fd865646a32038) Thanks [@acao](https://github.com/acao)! - Add useHeadersEditorState and generic useEditorState hooks ## 0.19.4 ### Patch Changes - Updated dependencies [[`7b00774a`](https://github.com/graphql/graphiql/commit/7b00774affad1f25253ce49f1f48c9e3f372808c), [`7b00774a`](https://github.com/graphql/graphiql/commit/7b00774affad1f25253ce49f1f48c9e3f372808c)]: - graphql-language-service@5.2.0 - codemirror-graphql@2.0.10 ## 0.19.3 ### Patch Changes - [#3371](https://github.com/graphql/graphiql/pull/3371) [`2348641c`](https://github.com/graphql/graphiql/commit/2348641c07748691c478ac5f67032b7e9081f9cb) Thanks [@acao](https://github.com/acao)! - Solves #2825, an old bug where new tabs were created on every refresh the bug occurred when: 1. `shouldPersistHeaders` is not set to true 2. `headers` or `defaultHeaders` are provided as props 3. the user refreshes the browser ## 0.19.2 ### Patch Changes - [#3364](https://github.com/graphql/graphiql/pull/3364) [`d67c13f6`](https://github.com/graphql/graphiql/commit/d67c13f6e1f478b171801afd0767b98312db04c9) Thanks [@acao](https://github.com/acao)! - Fix search result bug on select, #33307 - Updated dependencies [[`4cbdf183`](https://github.com/graphql/graphiql/commit/4cbdf18385d34ef9bc095c376936f92a62eb9e9b)]: - @graphiql/toolkit@0.9.1 ## 0.19.1 ### Patch Changes - [#3349](https://github.com/graphql/graphiql/pull/3349) [`17069e7a`](https://github.com/graphql/graphiql/commit/17069e7a0224dbce3f5523630a898e093f5c47c9) Thanks [@acao](https://github.com/acao)! - fix display of deprecation reason on field type docs - [#3341](https://github.com/graphql/graphiql/pull/3341) [`e4a36207`](https://github.com/graphql/graphiql/commit/e4a362071edf1db53f87f271c523ab2f3a5c4717) Thanks [@acao](https://github.com/acao)! - Fix code exporter plugin on early init, add hooks - Updated dependencies [[`ffb6486d`](https://github.com/graphql/graphiql/commit/ffb6486d1eab0be2bc8fdec366b5671a5d6504d1)]: - @graphiql/toolkit@0.9.0 ## 0.19.0 ### Minor Changes - [#3130](https://github.com/graphql/graphiql/pull/3130) [`9a38de29`](https://github.com/graphql/graphiql/commit/9a38de29fddf174ba9e793ac5852407537244f87) Thanks [@lesleydreyer](https://github.com/lesleydreyer)! - - Add a "clear history" button to clear all history as well as trash icons to clear individual history items - Change so item is in history items or history favorites, not both - Fix history label editing so if the same item is in the list more than once it edits the correct label - Pass the entire history item in history functions (addToHistory, editLabel, toggleFavorite, etc.) so users building their own HistoryContext.Provider will get any additional props they added to the item in their customized functions - Adds a "setActive" callback users can use to customize their UI when the history item is clicked ## 0.18.0 ### Minor Changes - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - remove `initialTabs`, use `defaultTabs` instead - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - replace `@reach/dialog` by `@radix-ui/react-dialog` replace `@reach/visually-hidden` by `@radix-ui/react-visually-hidden` - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - replace `@reach/menu-button` by `@radix-ui/react-dropdown-menu` remove `@reach/listbox` remove `` and `` components (use `` instead) - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - fixed long list items in dropdown were hidden rename `` to `` rename `` to `` rename `` to `` rename `` to `` - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - replace `@reach/tooltip` by `@radix-ui/react-tooltip` - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - replace `@reach/combobox` with `Combobox` from `@headlessui/react` - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - tabs could be reorderded ### Patch Changes - [#2716](https://github.com/graphql/graphiql/pull/2716) [`bc9d243d`](https://github.com/graphql/graphiql/commit/bc9d243d40b95f95fc9d00d25aa0dd1733952626) Thanks [@SimenB](https://github.com/SimenB)! - Make `@types/codemirror` a dependency of `@graphiql/react` - [#3228](https://github.com/graphql/graphiql/pull/3228) [`67bf93a3`](https://github.com/graphql/graphiql/commit/67bf93a33e98c60ae3a686063a1c47037f88ef49) Thanks [@B2o5T](https://github.com/B2o5T)! - exclude peer dependencies and dependencies from bundle - Updated dependencies [[`5971d528`](https://github.com/graphql/graphiql/commit/5971d528b0608e76d9d109103f64857a790a99b9), [`d9e5089f`](https://github.com/graphql/graphiql/commit/d9e5089f78f85cd50c3e3e3ba8510f7dda3d06f5), [`61986469`](https://github.com/graphql/graphiql/commit/619864691941c46cc0b0848e8713028e20212c36)]: - graphql-language-service@5.1.7 - codemirror-graphql@2.0.9 ## 0.18.0-alpha.1 ### Patch Changes - [#2716](https://github.com/graphql/graphiql/pull/2716) [`bc9d243d`](https://github.com/graphql/graphiql/commit/bc9d243d40b95f95fc9d00d25aa0dd1733952626) Thanks [@SimenB](https://github.com/SimenB)! - Make `@types/codemirror` a dependency of `@graphiql/react` - [#3228](https://github.com/graphql/graphiql/pull/3228) [`67bf93a3`](https://github.com/graphql/graphiql/commit/67bf93a33e98c60ae3a686063a1c47037f88ef49) Thanks [@B2o5T](https://github.com/B2o5T)! - exclude peer dependencies and dependencies from bundle - Updated dependencies [[`5971d528`](https://github.com/graphql/graphiql/commit/5971d528b0608e76d9d109103f64857a790a99b9), [`d9e5089f`](https://github.com/graphql/graphiql/commit/d9e5089f78f85cd50c3e3e3ba8510f7dda3d06f5)]: - graphql-language-service@5.1.7-alpha.0 - codemirror-graphql@2.0.9-alpha.1 ## 0.18.0-alpha.0 ### Minor Changes - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - remove `initialTabs`, use `defaultTabs` instead - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - replace `@reach/dialog` by `@radix-ui/react-dialog` replace `@reach/visually-hidden` by `@radix-ui/react-visually-hidden` - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - replace `@reach/menu-button` by `@radix-ui/react-dropdown-menu` remove `@reach/listbox` remove `` and `` components (use `` instead) - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - fixed long list items in dropdown were hidden rename `` to `` rename `` to `` rename `` to `` rename `` to `` - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - replace `@reach/tooltip` by `@radix-ui/react-tooltip` - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - replace `@reach/combobox` with `Combobox` from `@headlessui/react` - [#3181](https://github.com/graphql/graphiql/pull/3181) [`9ac84bfc`](https://github.com/graphql/graphiql/commit/9ac84bfc7b847105565852a01bdca122319e3696) Thanks [@B2o5T](https://github.com/B2o5T)! - tabs could be reorderded ### Patch Changes - Updated dependencies [[`61986469`](https://github.com/graphql/graphiql/commit/619864691941c46cc0b0848e8713028e20212c36)]: - codemirror-graphql@2.0.9-alpha.0 ## 0.17.6 ### Patch Changes - [#3194](https://github.com/graphql/graphiql/pull/3194) [`911cf3e0`](https://github.com/graphql/graphiql/commit/911cf3e0b0fa13268245463c8db8299279e5c461) Thanks [@dwwoelfel](https://github.com/dwwoelfel)! - fix tab content getting replaced on `changeTab` - [#3124](https://github.com/graphql/graphiql/pull/3124) [`c645932c`](https://github.com/graphql/graphiql/commit/c645932c7973e11ad917e1d1d897fd409f8c042f) Thanks [@B2o5T](https://github.com/B2o5T)! - avoid unnecessary renders by using useMemo or useCallback - [#3197](https://github.com/graphql/graphiql/pull/3197) [`2ca4841b`](https://github.com/graphql/graphiql/commit/2ca4841baf74e87a3f067b3415f8da3347ee3898) Thanks [@B2o5T](https://github.com/B2o5T)! - remove confusing ligatures, set `font-variant-ligatures: none` - [#3136](https://github.com/graphql/graphiql/pull/3136) [`7bf90929`](https://github.com/graphql/graphiql/commit/7bf90929f62ba812c0946e0424f9f843f7b6b0ff) Thanks [@B2o5T](https://github.com/B2o5T)! - replace rest of `event.keyCode` usages by `event.code` - [#3118](https://github.com/graphql/graphiql/pull/3118) [`431b7fe1`](https://github.com/graphql/graphiql/commit/431b7fe1efefa4867f0ea617adc436b1117052e8) Thanks [@B2o5T](https://github.com/B2o5T)! - Prefer `.textContent` over `.innerText` ## 0.17.5 ### Patch Changes - [#3147](https://github.com/graphql/graphiql/pull/3147) [`2b212941`](https://github.com/graphql/graphiql/commit/2b212941628498957d95ee89a7a5a0623f391b7a) Thanks [@Yahkob](https://github.com/Yahkob)! - limit code-mirror css scope to .graphiql-container - [#3180](https://github.com/graphql/graphiql/pull/3180) [`9b333a04`](https://github.com/graphql/graphiql/commit/9b333a047d6b75db7681f484156d8772e9f91810) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Remove duplicate Vite config and again make sure to not include `react/jsx-runtime` in the bundle ## 0.17.4 ### Patch Changes - [#3077](https://github.com/graphql/graphiql/pull/3077) [`707f3cbc`](https://github.com/graphql/graphiql/commit/707f3cbca3ac2ce186058e7d2b145cdf69bf7d9c) Thanks [@Zolwiastyl](https://github.com/Zolwiastyl)! - show all schema types in explorer - Updated dependencies [[`06007498`](https://github.com/graphql/graphiql/commit/06007498880528ed75dd4d705dcbcd7c9e775939)]: - graphql-language-service@5.1.6 - codemirror-graphql@2.0.8 ## 0.17.3 ### Patch Changes - Updated dependencies [[`4d33b221`](https://github.com/graphql/graphiql/commit/4d33b2214e941f171385a1b72a1fa995714bb284)]: - graphql-language-service@5.1.5 - codemirror-graphql@2.0.7 ## 0.17.2 ### Patch Changes - [#3113](https://github.com/graphql/graphiql/pull/3113) [`2e477eb2`](https://github.com/graphql/graphiql/commit/2e477eb24672a242ae4a4f2dfaeaf41152ed7ee9) Thanks [@B2o5T](https://github.com/B2o5T)! - replace `.forEach` with `for..of` - [#3126](https://github.com/graphql/graphiql/pull/3126) [`4879984e`](https://github.com/graphql/graphiql/commit/4879984ea1803a6e9f97d81c97e8ba27aacddae9) Thanks [@B2o5T](https://github.com/B2o5T)! - Prefer KeyboardEvent#key over KeyboardEvent#keyCode - [#3109](https://github.com/graphql/graphiql/pull/3109) [`51007002`](https://github.com/graphql/graphiql/commit/510070028b7d8e98f2ba25f396519976aea5fa4b) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `no-floating-promises` eslint rule - Updated dependencies [[`2e477eb2`](https://github.com/graphql/graphiql/commit/2e477eb24672a242ae4a4f2dfaeaf41152ed7ee9), [`51007002`](https://github.com/graphql/graphiql/commit/510070028b7d8e98f2ba25f396519976aea5fa4b), [`15c26eb6`](https://github.com/graphql/graphiql/commit/15c26eb6d621a85df9eecb2b8a5fa009fa2fe040)]: - codemirror-graphql@2.0.6 - @graphiql/toolkit@0.8.4 - graphql-language-service@5.1.4 ## 0.17.1 ### Patch Changes - [#3033](https://github.com/graphql/graphiql/pull/3033) [`2d5c60ec`](https://github.com/graphql/graphiql/commit/2d5c60ecf717abafde2bddd32b2772261d3eec8b) Thanks [@B2o5T](https://github.com/B2o5T)! - remove redundant `catch` statement - [#3046](https://github.com/graphql/graphiql/pull/3046) [`b9c13328`](https://github.com/graphql/graphiql/commit/b9c13328f3d28c0026ee0f0ecc7213065c9b016d) Thanks [@B2o5T](https://github.com/B2o5T)! - Prefer .at() method for index access - [#3017](https://github.com/graphql/graphiql/pull/3017) [`4a2284f5`](https://github.com/graphql/graphiql/commit/4a2284f54809f91d03ba51b9eb4e3ba7b8b7e773) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Avoid bundling code from `react/jsx-runtime` so that the package can be used with Preact - [#3042](https://github.com/graphql/graphiql/pull/3042) [`881a2024`](https://github.com/graphql/graphiql/commit/881a202497d5a58eb5260a5aa54c0c88930d69a0) Thanks [@B2o5T](https://github.com/B2o5T)! - Prefer String#slice() over String#substr() and String#substring() - [#3061](https://github.com/graphql/graphiql/pull/3061) [`7cf4908a`](https://github.com/graphql/graphiql/commit/7cf4908a5d4bd58af315047f4dec5236e8c701fc) Thanks [@B2o5T](https://github.com/B2o5T)! - remove unneeded `reference &&` assertion, convert to switch - Updated dependencies [[`b9c13328`](https://github.com/graphql/graphiql/commit/b9c13328f3d28c0026ee0f0ecc7213065c9b016d), [`881a2024`](https://github.com/graphql/graphiql/commit/881a202497d5a58eb5260a5aa54c0c88930d69a0)]: - codemirror-graphql@2.0.5 - @graphiql/toolkit@0.8.3 - graphql-language-service@5.1.3 ## 0.17.0 ### Minor Changes - [#3012](https://github.com/graphql/graphiql/pull/3012) [`65f5176a`](https://github.com/graphql/graphiql/commit/65f5176a408cfbbc514ca60e2e4bd2ea133a8b0b) Thanks [@benjie](https://github.com/benjie)! - GraphiQL now maintains the DocExplorer navigation stack as best it can when the schema is updated ### Patch Changes - [#2993](https://github.com/graphql/graphiql/pull/2993) [`bdc966cb`](https://github.com/graphql/graphiql/commit/bdc966cba6134a72ff7fe40f76543c77ba15d4a4) Thanks [@B2o5T](https://github.com/B2o5T)! - add `unicorn/consistent-destructuring` rule - Updated dependencies [[`e68cb8bc`](https://github.com/graphql/graphiql/commit/e68cb8bcaf9baddf6fca747abab871ecd1bc7a4c), [`f788e65a`](https://github.com/graphql/graphiql/commit/f788e65aff267ec873237034831d1fd936222a9b), [`bdc966cb`](https://github.com/graphql/graphiql/commit/bdc966cba6134a72ff7fe40f76543c77ba15d4a4), [`db2a0982`](https://github.com/graphql/graphiql/commit/db2a0982a17134f0069483ab283594eb64735b7d), [`8725d1b6`](https://github.com/graphql/graphiql/commit/8725d1b6b686139286cf05dec6a84d89942128ba)]: - graphql-language-service@5.1.2 - codemirror-graphql@2.0.4 - @graphiql/toolkit@0.8.2 ## 0.16.0 ### Minor Changes - [#2895](https://github.com/graphql/graphiql/pull/2895) [`ccba2f33`](https://github.com/graphql/graphiql/commit/ccba2f33b67a03f492222f7afde1354cfd033b42) Thanks [@TheMightyPenguin](https://github.com/TheMightyPenguin)! - Add user facing setting for persisting headers ### Patch Changes - [#2931](https://github.com/graphql/graphiql/pull/2931) [`f7addb20`](https://github.com/graphql/graphiql/commit/f7addb20c4a558fbfb4112c8ff095bbc8f9d9147) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `no-negated-condition` and `no-else-return` rules - [#2964](https://github.com/graphql/graphiql/pull/2964) [`cec3fb2a`](https://github.com/graphql/graphiql/commit/cec3fb2a493c4a0c40df7dfad04e1a95ed35e786) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `unicorn/prefer-export-from` rule - [#2932](https://github.com/graphql/graphiql/pull/2932) [`11e6ad11`](https://github.com/graphql/graphiql/commit/11e6ad11e745c671eb320731697887bb8d7177b7) Thanks [@B2o5T](https://github.com/B2o5T)! - replace `compose.ts` with `clsx` for class concatenation - [#2937](https://github.com/graphql/graphiql/pull/2937) [`c70d9165`](https://github.com/graphql/graphiql/commit/c70d9165cc1ef8eb1cd0d6b506ced98c626597f9) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `unicorn/prefer-includes` - [#2933](https://github.com/graphql/graphiql/pull/2933) [`d502a33b`](https://github.com/graphql/graphiql/commit/d502a33b4332f1025e947c02d7cfdc5799365c8d) Thanks [@B2o5T](https://github.com/B2o5T)! - enable @typescript-eslint/no-unused-expressions - [#2965](https://github.com/graphql/graphiql/pull/2965) [`0669767e`](https://github.com/graphql/graphiql/commit/0669767e1e2196a78cbefe3679a52bcbb341e913) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `unicorn/prefer-optional-catch-binding` rule - [#2963](https://github.com/graphql/graphiql/pull/2963) [`f263f778`](https://github.com/graphql/graphiql/commit/f263f778cb95b9f413bd09ca56a43f5b9c2f6215) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `prefer-destructuring` rule - [#2942](https://github.com/graphql/graphiql/pull/2942) [`4ff2794c`](https://github.com/graphql/graphiql/commit/4ff2794c8b6032168e27252096cb276ce712878e) Thanks [@B2o5T](https://github.com/B2o5T)! - enable `sonarjs/no-redundant-jump` rule - Updated dependencies [[`f7addb20`](https://github.com/graphql/graphiql/commit/f7addb20c4a558fbfb4112c8ff095bbc8f9d9147), [`d1fcad72`](https://github.com/graphql/graphiql/commit/d1fcad72607e2789517dfe4936b5ec604e46762b), [`4a8b2e17`](https://github.com/graphql/graphiql/commit/4a8b2e1766a38eb4828cf9a81bf9d767070041de), [`695100bd`](https://github.com/graphql/graphiql/commit/695100bd317940ff3ffd8f56b54248c1dba1ac04), [`c70d9165`](https://github.com/graphql/graphiql/commit/c70d9165cc1ef8eb1cd0d6b506ced98c626597f9), [`c44ea4f1`](https://github.com/graphql/graphiql/commit/c44ea4f1917b97daac815c08299b934c8ca57ed9), [`0669767e`](https://github.com/graphql/graphiql/commit/0669767e1e2196a78cbefe3679a52bcbb341e913), [`18f8e80a`](https://github.com/graphql/graphiql/commit/18f8e80ae12edfd0c36adcb300cf9e06ac27ea49), [`f263f778`](https://github.com/graphql/graphiql/commit/f263f778cb95b9f413bd09ca56a43f5b9c2f6215), [`6a9d913f`](https://github.com/graphql/graphiql/commit/6a9d913f0d1b847124286b3fa1f3a2649d315171)]: - codemirror-graphql@2.0.3 - @graphiql/toolkit@0.8.1 - graphql-language-service@5.1.1 ## 0.15.0 ### Minor Changes - [#2908](https://github.com/graphql/graphiql/pull/2908) [`3340fd74`](https://github.com/graphql/graphiql/commit/3340fd745e181ba8f1f5a6ed002a04d253a78d4a) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Deprecate the `initialTabs` prop and add a `defaultTabs` props that supersedes it - [#2907](https://github.com/graphql/graphiql/pull/2907) [`3a7d0007`](https://github.com/graphql/graphiql/commit/3a7d00071922e2005777c92daf6ad0c1ce3e2816) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Clearly separate the fetching and subscription states for multipart requests (like subscriptions) and show the stop-button as long as the subscription is running ### Patch Changes - [#2910](https://github.com/graphql/graphiql/pull/2910) [`16174a05`](https://github.com/graphql/graphiql/commit/16174a053ed89fb9554d096395ab7bf69c8f6911) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix autocomplete styles for field type and description on the right - [#2919](https://github.com/graphql/graphiql/pull/2919) [`f6cae4ea`](https://github.com/graphql/graphiql/commit/f6cae4eaa0258ea7fcde97ba6368830955f0abf4) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix overflow when there are lots of tabs that don't fit into the tab bar at once - [#2905](https://github.com/graphql/graphiql/pull/2905) [`0851d5f9`](https://github.com/graphql/graphiql/commit/0851d5f9ecf709597d0a698609d88f99c4395665) Thanks [@ccbrown](https://github.com/ccbrown)! - Fix: prevent default event for graphiql-doc-explorer-back link - [#2912](https://github.com/graphql/graphiql/pull/2912) [`83364b28`](https://github.com/graphql/graphiql/commit/83364b28020b5946ed58908d6d977f1de766e75d) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add missing effect dependency to make sure updates to the `defaultHeaders` prop have the desired effect ## 0.14.0 ### Minor Changes - [#2821](https://github.com/graphql/graphiql/pull/2821) [`29630c22`](https://github.com/graphql/graphiql/commit/29630c2219bca8b825ab0897840864364a9de2e8) Thanks [@avaly](https://github.com/avaly)! - Initial tabs support ### Patch Changes - [#2885](https://github.com/graphql/graphiql/pull/2885) [`8f926489`](https://github.com/graphql/graphiql/commit/8f9264896e9971951853463a283a90ba3d1310ef) Thanks [@simhnna](https://github.com/simhnna)! - Fix stop execution button showing a dropdown - [#2886](https://github.com/graphql/graphiql/pull/2886) [`2ba2f620`](https://github.com/graphql/graphiql/commit/2ba2f620b6e7de3ae6b5ea641f33e600f7f44e08) Thanks [@B2o5T](https://github.com/B2o5T)! - feat: add `defaultHeaders` prop ## 0.13.7 ### Patch Changes - Updated dependencies [[`20869583`](https://github.com/graphql/graphiql/commit/20869583eff563f5d6494e93302a835f0e034f4b)]: - codemirror-graphql@2.0.2 ## 0.13.6 ### Patch Changes - Updated dependencies [[`353f434e`](https://github.com/graphql/graphiql/commit/353f434e5f6bfd1bf6f8ee97d4ae8ce4f897085f)]: - codemirror-graphql@2.0.1 ## 0.13.5 ### Patch Changes - [#2839](https://github.com/graphql/graphiql/pull/2839) [`682ad06e`](https://github.com/graphql/graphiql/commit/682ad06e58ded2f82fa973e8e6613dd654417fe2) Thanks [@ClemensSahs](https://github.com/ClemensSahs)! - Export the `PluginContextProvider` component ## 0.13.4 ### Patch Changes - [#2824](https://github.com/graphql/graphiql/pull/2824) [`4e2f7ff9`](https://github.com/graphql/graphiql/commit/4e2f7ff99c578ceae54a1ae17c02088bd91b89c3) Thanks [@TheMightyPenguin](https://github.com/TheMightyPenguin)! - fix: prevent key down events when pressing escape to close autocomplete dialogs ## 0.13.3 ### Patch Changes - [#2791](https://github.com/graphql/graphiql/pull/2791) [`42700076`](https://github.com/graphql/graphiql/commit/4270007671ce52f6c2250739916083611748b657) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Make sure that the info overlay in editors is shown above the vertical scrollbar * [#2792](https://github.com/graphql/graphiql/pull/2792) [`36839800`](https://github.com/graphql/graphiql/commit/36839800de128b05d11c262036c8240390c72a14) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Avoid resetting visible plugin state when explorer or history context changes - [#2778](https://github.com/graphql/graphiql/pull/2778) [`905f2e5e`](https://github.com/graphql/graphiql/commit/905f2e5ea3f0b304d27ea583e250ed4baff5016e) Thanks [@jonathanawesome](https://github.com/jonathanawesome)! - Adds a box-model reset for all children of the `.graphiql-container` class. This change facilitated another change to the `--sidebar-width` variable. ## 0.13.2 ### Patch Changes - [#2653](https://github.com/graphql/graphiql/pull/2653) [`39b4668d`](https://github.com/graphql/graphiql/commit/39b4668d43176526d37ecf07d8c86901d53e0d80) Thanks [@dylanowen](https://github.com/dylanowen)! - Fix `fetchError` not being cleared when a new `fetcher` is used ## 0.13.1 ### Patch Changes - Updated dependencies [[`e244b782`](https://github.com/graphql/graphiql/commit/e244b78291c2e2bb02d5753db82437926ebb4df4)]: - @graphiql/toolkit@0.8.0 ## 0.13.0 ### Minor Changes - [#2735](https://github.com/graphql/graphiql/pull/2735) [`ca067d88`](https://github.com/graphql/graphiql/commit/ca067d88148c5d221d196790a997ad599038fad1) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add CSS variables for color alpha values: - `--alpha-secondary`: A color for supplementary text that should be read but not be the main focus - `--alpha-tertiary`: A color for supplementary text which is optional to read, i.e. the UI would function without the user reading this text - `--alpha-background-light`, `--alpha-background-medium` and `--alpha-background-heavy`: Three alpha values used for backgrounds and borders that have different intensity ### Patch Changes - [#2757](https://github.com/graphql/graphiql/pull/2757) [`32a70065`](https://github.com/graphql/graphiql/commit/32a70065434eaa7733e28cda0ea0e7d51952e62a) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Use different colors for field names and argument names - Updated dependencies [[`674bf3f8`](https://github.com/graphql/graphiql/commit/674bf3f8ff321dfb8471b0f6e5419bb77ddc94af)]: - @graphiql/toolkit@0.7.3 ## 0.12.1 ### Patch Changes - Updated dependencies [[`bfa90f24`](https://github.com/graphql/graphiql/commit/bfa90f249be4f68049c1bb81abfb524ae623313f), [`8ab5fcd0`](https://github.com/graphql/graphiql/commit/8ab5fcd0a8399a0f8eb1b569751dd0e8390b9679)]: - @graphiql/toolkit@0.7.2 ## 0.12.0 ### Minor Changes - [#2739](https://github.com/graphql/graphiql/pull/2739) [`98e14155`](https://github.com/graphql/graphiql/commit/98e14155c650ee7c5ac639e594eb47f0052b7fa9) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add `DocsFilledIcon` component and use show that icon in the sidebar when the docs plugin is visible ### Patch Changes - [#2740](https://github.com/graphql/graphiql/pull/2740) [`7dfea94a`](https://github.com/graphql/graphiql/commit/7dfea94afc0cfe79b5080f10d840bfdce53f02d7) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Make SVG icon `stroke-width` consistent * [#2734](https://github.com/graphql/graphiql/pull/2734) [`3aa1f39f`](https://github.com/graphql/graphiql/commit/3aa1f39f6df559b54f703937ed510c8ba1f21058) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Stop propagating keyboard events too far upwards in the search component for the docs - [#2741](https://github.com/graphql/graphiql/pull/2741) [`0219eef3`](https://github.com/graphql/graphiql/commit/0219eef39146495749aca2487112db52fa3bb8fd) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add hover styles for buttons - Updated dependencies [[`48872a87`](https://github.com/graphql/graphiql/commit/48872a87e6edec0c301102baaf669ffcce043a13)]: - @graphiql/toolkit@0.7.1 ## 0.11.1 ### Patch Changes - [#2712](https://github.com/graphql/graphiql/pull/2712) [`d65f00ea`](https://github.com/graphql/graphiql/commit/d65f00ea2d158cf532d1c71844630c5d9ec13410) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Make sure the back link and title are hidden when focussing the input field for searching the docs * [#2708](https://github.com/graphql/graphiql/pull/2708) [`f15ee38d`](https://github.com/graphql/graphiql/commit/f15ee38d56e4f749c145e0a17f0ed8e9a6096ac2) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix computing the initial state for editor values and tabs to avoid duplicating tabs on page reload - [#2712](https://github.com/graphql/graphiql/pull/2712) [`d65f00ea`](https://github.com/graphql/graphiql/commit/d65f00ea2d158cf532d1c71844630c5d9ec13410) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Make sure hidden editors don't overflow ## 0.11.0 ### Minor Changes - [#2694](https://github.com/graphql/graphiql/pull/2694) [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279) Thanks [@acao](https://github.com/acao)! - BREAKING: The `onHasCompletion` export has been removed as it is only meant to be used internally. * [#2694](https://github.com/graphql/graphiql/pull/2694) [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279) Thanks [@acao](https://github.com/acao)! - Add new 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`, `ToolbarButton`, `ToolbarMenu` and `ToolbarSelect`) - Docs components (`Argument`, `DefaultValue`, `DeprecationReason`, `Directive`, `DocExplorer`, `ExplorerSection`, `FieldDocumentation`, `FieldLink`, `SchemaDocumentation`, `Search`, `TypeDocumentation` and `TypeLink`) - `History` component - A `GraphiQLProvider` component that renders all other existing provider components from `@graphiql/react` for ease of use - [#2694](https://github.com/graphql/graphiql/pull/2694) [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279) Thanks [@acao](https://github.com/acao)! - BREAKING: Add a new context provider for plugins. This induces changes to the following other contexts and their provider components: - The property `isVisible` and the methods `hide` and `show` of the `ExplorerContext` have been removed. Also, the property `isVisible` and the methods `hide`, `show` and `toggle` of the `HistoryContext` have been removed. Visibility state of plugins is now part of the `PluginContext` using the `visiblePlugin` property. The visibility state can be altered using the `setVisiblePlugin` method of the `PluginContext`. - The `isVisible` prop of the `ExplorerContextProvider` has been removed. For controlling the visibility state of plugins you can now use the `visiblePlugin` prop of the `PluginContextProvider`. - The `onToggle` prop of the `HistoryContextProvider` and the `onToggleVisibility` prop of the `ExplorerContextProvider` have been removed. For listening on visibility changes for any plugin you can now use the `onTogglePluginVisibility` prop of the `PluginContextProvider`. * [#2694](https://github.com/graphql/graphiql/pull/2694) [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279) Thanks [@acao](https://github.com/acao)! - BREAKING: The `ResponseTooltip` prop of the `ResponseEditor` has been renamed to `responseTooltip` ### Patch Changes - Updated dependencies [[`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279), [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279), [`e59ec32e`](https://github.com/graphql/graphiql/commit/e59ec32e7ccdf3f7f68656533555c63620826279)]: - codemirror-graphql@2.0.0 - @graphiql/toolkit@0.7.0 ## 0.10.1 ### Patch Changes - Updated dependencies [[`d6ff4d7a`](https://github.com/graphql/graphiql/commit/d6ff4d7a5d535a0c43fe5914016bac9ef0c2b782)]: - graphql-language-service@5.1.0 - codemirror-graphql@1.3.3 ## 0.10.0 ### Minor Changes - [#2651](https://github.com/graphql/graphiql/pull/2651) [`85d5af25`](https://github.com/graphql/graphiql/commit/85d5af25d77c29b7d02da90a431c8c15f610c22a) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - BREAKING: The following context properties have been removed as they are only meant for internal use: - The `subscription` property of the `ExecutionContext` - The `setSchema` method of the `SchemaContext` - The `setFetchError` method of the `SchemaContext` * [#2652](https://github.com/graphql/graphiql/pull/2652) [`6ff0bab9`](https://github.com/graphql/graphiql/commit/6ff0bab978d63778b8ab4ba6e79fceb36c2db87f) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - BREAKING: The `validationErrors` property of the `SchemaContext` is now always non-null. If the schema is valid then it will contain an empty list. - [#2644](https://github.com/graphql/graphiql/pull/2644) [`0aff68a6`](https://github.com/graphql/graphiql/commit/0aff68a645cceb6b9689e0f394e8bece01710efc) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - BREAKING: The `ResponseEditor` component no longer accepts the prop `value`. Instead you can now pass the prop `response` to the `EditorContextProvider`. This aligns it with the API design of the other editor components. ## 0.9.0 ### Minor Changes - [#2642](https://github.com/graphql/graphiql/pull/2642) [`100af928`](https://github.com/graphql/graphiql/commit/100af9284de18ca89524c646e86854313c5d067b) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add a new prop `operationName` to the `ExecutionContextProvider` component that controls the operation sent with the request * [#2642](https://github.com/graphql/graphiql/pull/2642) [`100af928`](https://github.com/graphql/graphiql/commit/100af9284de18ca89524c646e86854313c5d067b) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - BREAKING: The `ExecutionContextProvider` and `QueryEditor` components no longer accepts the `onEditOperationName` prop. Instead you can now pass this prop to the `EditorContextProvider` component. ## 0.8.0 ### Minor Changes - [#2636](https://github.com/graphql/graphiql/pull/2636) [`62317e0b`](https://github.com/graphql/graphiql/commit/62317e0bae6d4ccf89d9e1e6607fd8feeb100078) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - BREAKING: - The `ExecutionContextProvider` and `QueryEditor` components no longer accept the `externalFragments` prop. Instead the prop can now be passed to the `EditorContextProvider` component. The provider component will normalize the prop value and provide a map of type `Map` (using the fragment names as keys) as part of the value of the `EditorContext`. - The `QueryEditor` component no longer accept the `validationRules` prop. Instead the prop can now be passed to the `EditorContextProvider` component. The provider component will provide the list of validation rules (empty if there are none) as part of the value of the `EditorContext`. - The `ExecutionContextProvider` and `HeaderEditor` components no longer accept the `shouldPersistHeaders` prop. Instead the `EditorContextProvider` component now provides the value of its equally named prop as part of the value of the `EditorContext`. ## 0.7.1 ### Patch Changes - Updated dependencies [[`ea732ea8`](https://github.com/graphql/graphiql/commit/ea732ea8e12272c998f1467af8b3b88b6b508e12)]: - @graphiql/toolkit@0.6.1 ## 0.7.0 ### Minor Changes - [#2618](https://github.com/graphql/graphiql/pull/2618) [`4c814506`](https://github.com/graphql/graphiql/commit/4c814506183579b78731659d871cd4b0ba93305a) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add a method `introspect` to the schema context and provide a short key (`Shift-Ctrl-R`) for triggering introspection ## 0.6.0 ### Minor Changes - [#2574](https://github.com/graphql/graphiql/pull/2574) [`0c98fa59`](https://github.com/graphql/graphiql/commit/0c98fa5924eadaee33713ccd8a9be6419d50cab1) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Allow passing introspection data to the `schema` prop of the `SchemaContextProvider` component ### Patch Changes - [#2574](https://github.com/graphql/graphiql/pull/2574) [`0c98fa59`](https://github.com/graphql/graphiql/commit/0c98fa5924eadaee33713ccd8a9be6419d50cab1) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Set the schema correctly after refetching introspection (e.g. when the `fetcher` prop changes) ## 0.5.2 ### Patch Changes - [#2565](https://github.com/graphql/graphiql/pull/2565) [`f581b437`](https://github.com/graphql/graphiql/commit/f581b437e5bdab6f3ad817d230ee6d1b410bb591) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Don't invoke editor change callbacks when manually signaling "empty" changes. ## 0.5.1 ### Patch Changes - [#2561](https://github.com/graphql/graphiql/pull/2561) [`08346cba`](https://github.com/graphql/graphiql/commit/08346cba136825341881f9dfefc62a60d748e0ee) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add missing effect dependencies to make sure editors are recreated when changing the `keyMap` prop ## 0.5.0 ### Minor Changes - [#2541](https://github.com/graphql/graphiql/pull/2541) [`788d84ef`](https://github.com/graphql/graphiql/commit/788d84ef2784188981f1b4cfb78fba24153bf0cb) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add `onSchemaChange` callback prop to the `SchemaContextProvider` component ### Patch Changes - [#2545](https://github.com/graphql/graphiql/pull/2545) [`8ce5b483`](https://github.com/graphql/graphiql/commit/8ce5b483ee190b5f5dd84eaf42e5d1359ce185e6) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Avoid top-level dynamic imports from `codemirror` that break importing the package in non-browser environments ## 0.4.3 ### Patch Changes - [#2526](https://github.com/graphql/graphiql/pull/2526) [`26e44120`](https://github.com/graphql/graphiql/commit/26e44120a18d49af451c97619fe3386a65579e05) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add missing `caller` arguments to hook calls so that the error message printed when a context provider is missing is more accurate about the component or hook that caused the error ## 0.4.2 ### Patch Changes - [#2501](https://github.com/graphql/graphiql/pull/2501) [`5437ee61`](https://github.com/graphql/graphiql/commit/5437ee61e1ba6cd28ccc1cb3543df1ea788278f4) Thanks [@acao](https://github.com/acao)! - Allow Codemirror 5 `keyMap` to be defined, default `vim` or `emacs` allowed in addition to the original default of `sublime`. - Updated dependencies [[`cccefa70`](https://github.com/graphql/graphiql/commit/cccefa70c0466d60e8496e1df61aeb1490af723c)]: - graphql-language-service@5.0.6 - codemirror-graphql@1.3.2 ## 0.4.1 ### Patch Changes - Updated dependencies [[`c9c51b8a`](https://github.com/graphql/graphiql/commit/c9c51b8a98e1f0427272d3e9ad60989b32f1a1aa)]: - graphql-language-service@5.0.5 - codemirror-graphql@1.3.1 ## 0.4.0 ### Minor Changes - [#2461](https://github.com/graphql/graphiql/pull/2461) [`7dfe3ece`](https://github.com/graphql/graphiql/commit/7dfe3ece4e8ab6b3400888f7f357e394db63439d) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add `useDragResize` utility hook ## 0.3.0 ### Minor Changes - [#2453](https://github.com/graphql/graphiql/pull/2453) [`1b41e33c`](https://github.com/graphql/graphiql/commit/1b41e33c4a871a345836de58f415b7c461ced1f8) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add execution context to `@graphiql/react` and move over the logic from `graphiql` * [#2452](https://github.com/graphql/graphiql/pull/2452) [`ee0fd8bf`](https://github.com/graphql/graphiql/commit/ee0fd8bf4042053ec647080b83656dc5e54a7239) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move tab state from `graphiql` into editor context from `@graphiql/react` - [#2449](https://github.com/graphql/graphiql/pull/2449) [`a0b02eda`](https://github.com/graphql/graphiql/commit/a0b02edaa629c6113c1c5518fd3aa05b355a1921) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Assume all context values are nullable and create hooks to consume individual contexts * [#2450](https://github.com/graphql/graphiql/pull/2450) [`1e6fc68b`](https://github.com/graphql/graphiql/commit/1e6fc68b73941544ee64e0499e459f9c7d39aa14) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Extract the `copy`, `merge`, `prettify`, and `autoCompleteLeafs` functions into hooks and remove these functions from the editor context value ### Patch Changes - [#2451](https://github.com/graphql/graphiql/pull/2451) [`0659e96e`](https://github.com/graphql/graphiql/commit/0659e96e07f98d532619f29f52cba59e2d528327) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Always use the current value of the headers for the introspection request ## 0.2.1 ### Patch Changes - [#2435](https://github.com/graphql/graphiql/pull/2435) [`89f0244f`](https://github.com/graphql/graphiql/commit/89f0244f7b7cdf01c168638a09f5137788401995) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix deriving default values for editors from storage * [#2437](https://github.com/graphql/graphiql/pull/2437) [`1f933505`](https://github.com/graphql/graphiql/commit/1f9335051fffc9e6a6f950b6f8060ed521b56789) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move prettify query functionality to editor context in `@graphiql/react` - [#2435](https://github.com/graphql/graphiql/pull/2435) [`89f0244f`](https://github.com/graphql/graphiql/commit/89f0244f7b7cdf01c168638a09f5137788401995) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move the logic for deriving operation facts from the current query to `@graphiql/react` and store these facts as properties on the query editor instance * [#2448](https://github.com/graphql/graphiql/pull/2448) [`3dae62fc`](https://github.com/graphql/graphiql/commit/3dae62fc871385e148a799cde55a52a5e6b41d19) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - don't introspect the schema if it's provided via props - [#2437](https://github.com/graphql/graphiql/pull/2437) [`1f933505`](https://github.com/graphql/graphiql/commit/1f9335051fffc9e6a6f950b6f8060ed521b56789) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move copy query functionality to editor context in `@graphiql/react` * [#2437](https://github.com/graphql/graphiql/pull/2437) [`1f933505`](https://github.com/graphql/graphiql/commit/1f9335051fffc9e6a6f950b6f8060ed521b56789) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move merge query functionality to editor context in `@graphiql/react` - [#2436](https://github.com/graphql/graphiql/pull/2436) [`3e5295f0`](https://github.com/graphql/graphiql/commit/3e5295f0fd3b5f999643ea97e6cee706554f0b50) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Inline logic for clicking a reference to open the docs and remove the `onClickReference` and `onHintInformationRender` props of the editor components and hooks * [#2436](https://github.com/graphql/graphiql/pull/2436) [`3e5295f0`](https://github.com/graphql/graphiql/commit/3e5295f0fd3b5f999643ea97e6cee706554f0b50) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move visibility state for doc explorer from `graphiql` to the explorer context in `@graphiql/react` ## 0.2.0 ### Minor Changes - [#2413](https://github.com/graphql/graphiql/pull/2413) [`8be164b1`](https://github.com/graphql/graphiql/commit/8be164b1e158d00752d6d3f30630a797d07d08c9) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add a `StorageContext` and a `HistoryContext` to `@graphiql/react` that replaces the logic in the `graphiql` package * [#2420](https://github.com/graphql/graphiql/pull/2420) [`3467cd33`](https://github.com/graphql/graphiql/commit/3467cd33264e0766a0a43cf53e52ec371df26962) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add a `SchemaContext` to `@graphiql/react` that replaces the logic for fetching and validating the schema in the `graphiql` package ### Patch Changes - Updated dependencies [[`84d8985b`](https://github.com/graphql/graphiql/commit/84d8985b87701133cc41fd424a24bb61c9b7272e), [`8be164b1`](https://github.com/graphql/graphiql/commit/8be164b1e158d00752d6d3f30630a797d07d08c9), [`84d8985b`](https://github.com/graphql/graphiql/commit/84d8985b87701133cc41fd424a24bb61c9b7272e), [`84d8985b`](https://github.com/graphql/graphiql/commit/84d8985b87701133cc41fd424a24bb61c9b7272e)]: - @graphiql/toolkit@0.6.0 ## 0.1.2 ### Patch Changes - [#2427](https://github.com/graphql/graphiql/pull/2427) [`ebc864f0`](https://github.com/graphql/graphiql/commit/ebc864f0ab05000758cb2898daaa73a2f15255ec) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Mark `graphql` as external dependency to avoid importing multiple instances * [#2427](https://github.com/graphql/graphiql/pull/2427) [`ebc864f0`](https://github.com/graphql/graphiql/commit/ebc864f0ab05000758cb2898daaa73a2f15255ec) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Fix linting by also updating the options object in the internal codemirror state ## 0.1.1 ### Patch Changes - [#2423](https://github.com/graphql/graphiql/pull/2423) [`838e58da`](https://github.com/graphql/graphiql/commit/838e58dad652d8f5559af7b88d049b1c62348f2f) Thanks [@chentsulin](https://github.com/chentsulin)! - Fix peer dependency declaration by using `||` instead of `|` to link multiple major versions ## 0.1.0 ### Minor Changes - [#2409](https://github.com/graphql/graphiql/pull/2409) [`f2025ba0`](https://github.com/graphql/graphiql/commit/f2025ba06c5aa8e8ac68d29538ff135f3efc8e46) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move the logic of the variable editor from the `graphiql` package into a hook `useVariableEditor` provided by `@graphiql/react` * [#2408](https://github.com/graphql/graphiql/pull/2408) [`d825bb75`](https://github.com/graphql/graphiql/commit/d825bb7569ca6b1ebbe534b893354645c790e003) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move the logic of the query editor from the `graphiql` package into a hook `useQueryEditor` provided by `@graphiql/react` - [#2411](https://github.com/graphql/graphiql/pull/2411) [`ad448693`](https://github.com/graphql/graphiql/commit/ad4486934ba69247efd33ee500e30f8236ecd079) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Move the logic of the result viewer from the `graphiql` package into a hook `useResponseEditor` provided by `@graphiql/react` * [#2404](https://github.com/graphql/graphiql/pull/2404) [`029ddf82`](https://github.com/graphql/graphiql/commit/029ddf82c29754ab8518ae7df66f9b25361a8247) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add a context provider for editors and move the logic of the headers editor from the `graphiql` package into a hook `useHeaderEditor` provided by `@graphiql/react` ### Patch Changes - [#2370](https://github.com/graphql/graphiql/pull/2370) [`7f695b10`](https://github.com/graphql/graphiql/commit/7f695b104f9b25ba8c6d36f7827c475b297b7482) Thanks [@thomasheyenbrock](https://github.com/thomasheyenbrock)! - Add a context with provider component and hooks that manages the state related to the docs/explorer. ================================================ FILE: packages/graphiql-react/LICENSE ================================================ MIT License Copyright (c) 2021 GraphQL Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/graphiql-react/README.md ================================================ [Changelog](https://github.com/graphql/graphiql/blob/main/packages/graphiql-react/CHANGELOG.md) | [API Docs](https://graphiql-test.netlify.app/typedoc/modules/graphiql_react.html) | [NPM](https://www.npmjs.com/package/@graphiql/react) # `@graphiql/react` A React SDK for building integrated GraphQL developer experiences for the web. ## Purpose This package contains a set of building blocks that allow its users to build GraphQL IDEs with ease. It's the set of components that make up Graph*i*QL, the first and official GraphQL IDE, owned and maintained by the GraphQL Foundation. There are two kinds of building blocks that this package provides: Stateful context providers for state management and simple UI components. ## Getting started All the state for your GraphQL IDE lives in multiple contexts. The easiest way to get started is by using the `GraphiQLProvider` component that renders all the individual providers. There is one required prop called `fetcher`. This is a function that performs GraphQL request against a given endpoint. You can easily create a fetcher using the method `createGraphiQLFetcher` from the `@graphiql/toolkit` package. ```jsx import { GraphiQLProvider } from '@graphiql/react'; import { createGraphiQLFetcher } from '@graphiql/toolkit'; const fetcher = createGraphiQLFetcher({ url: 'https://my.graphql.api/graphql', }); function MyGraphQLIDE() { return (
    Hello GraphQL
    ); } ``` Inside the provider you can now use any UI component provided by `@graphiql/react`. For example, you can render an operation editor like this: ```jsx import { QueryEditor } from '@graphiql/react'; function MyGraphQLIDE() { return (
    ); } ``` The package also ships the necessary CSS that all its UI components need. You can import them from `@graphiql/react/style.css`. > **Note**: In order for these styles to apply, the UI components need to be > rendered inside an element that has a class name `graphiql-container`. By default, the UI components will try to use the [Roboto](https://fonts.google.com/specimen/Roboto) font for regular text and the [Fira Code](https://fonts.google.com/specimen/Fira+Code) font for mono-space text. If you want to use the default fonts you can load them using these files: - `@graphiql/react/font/roboto.css` - `@graphiql/react/font/fira-code.css`. You can, of course, use any other method to load these fonts (for example, loading them from Google Fonts). Further details on how to use `@graphiql/react` can be found in the reference implementation of a GraphQL IDE - Graph*i*QL - in the [`graphiql` package](https://github.com/graphql/graphiql/blob/main/packages/graphiql/src/components/GraphiQL.tsx). ## Available Stores GraphiQL uses a set of state management stores, each responsible for a specific part of the IDE's behavior. These stores contain all logic related to state management and can be accessed via custom React hooks. ### Core Hooks - **`useMonaco`**: Access `monaco-editor` exports and the `monaco-graphql` instance. Designed for safe use in SSR environments. - **`useGraphiQL`**: Access the current state. - **`useGraphiQLActions`**: Trigger actions that mutate the state. This hook **never** rerenders. The `useGraphiQLActions` hook **exposes all actions** across store slices. The `useGraphiQL` hook **provides access to the following store slices**: | Store Slice | Responsibilities | | ---------------------------------------- | --------------------------------------------------------------------------------------------------------- | | [`storage`](./src/stores/storage.ts) | Provides a storage API that can be used to persist state in the browser (by default using `localStorage`) | | [`editor`](./src/stores/editor.ts) | Manages **query**, **variables**, **headers**, and **response** editors and tabs | | [`execution`](./src/stores/execution.ts) | Handles the execution of GraphQL requests | | [`plugin`](./src/stores/plugin.ts) | Manages plugins and the currently active plugin | | [`schema`](./src/stores/schema.ts) | Fetches, validates, and stores the GraphQL schema | | [`theme`](./src/stores/theme.ts) | Manages the current theme and provides a method to update it | ### Usage Example ```js import { useGraphiQL, useGraphiQLActions } from '@graphiql/react'; // Get an action to fetch the schema and an action to change theme const { introspect, setTheme } = useGraphiQLActions(); // Use a selector to access specific parts of the state like current schema and theme const { schema, theme } = useGraphiQL(state => ({ schema: state.schema, theme: state.theme, })); ``` All store properties are documented using TSDoc comments. If you're using an IDE like VSCode for development, these descriptions will show up in auto-complete tooltips. All these descriptions can also be found in the [API Docs](https://graphiql-test.netlify.app/typedoc/modules/graphiql_react.html). ## Theming All the components from `@graphiql/react` have been designed with customization in mind. We achieve this using CSS variables. All variables that are available for customization can be found in the [`root.css` file](https://github.com/graphql/graphiql/blob/main/packages/graphiql-react/src/style/root.css). ### Colors Colors are defined using the [HSL format](https://en.wikipedia.org/wiki/HSL_and_HSV). All CSS variables for colors are defined as a list of the three values that make up HSL (hue, saturation and lightness). This approach allows `@graphiql/react` to use transparent colors by passing the value of the CSS variable in the `hsla` function. This enables us to provide truly reusable UI elements where good contrasts are preserved regardless of the elements background. ## Development If you want to develop with `@graphiql/react` locally - in particular when working on the `graphiql` package - all you need to do is run `yarn dev` in the package folder in a separate terminal. This will build the package using Vite. When using it in combination with `yarn dev:graphiql` (running in the repo root) this will give you auto-reloading when working on `graphiql` and `@graphiql/react` simultaneously. ================================================ FILE: packages/graphiql-react/font/fira-code.css ================================================ @font-face { font-family: Fira Code; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff;base64,d09GRgABAAAAADhUAA8AAAAAVfwAAQABAAAAAAAAAAAAAAAAAAAAAAAAAABHREVGAAABWAAAAHIAAACmCwIKakdQT1MAAAHMAAAAIAAAACBEdkx1R1NVQgAAAewAAABAAAAAQodMa01PUy8yAAACLAAAAFQAAABgc+SqD1NUQVQAAAKAAAAAKgAAAC55kWzdY21hcAAAAqwAAAFAAAABxDJPUwdnYXNwAAAD7AAAAAgAAAAIAAAAEGdseWYAAAP0AAAvawAASRaIk5X9aGVhZAAAM2AAAAA2AAAANhL1JvtoaGVhAAAzmAAAAB8AAAAkAzn+dWhtdHgAADO4AAABdwAAA7RA9GIebG9jYQAANTAAAAHhAAAB5vJU4EVtYXhwAAA3FAAAABwAAAAgAWACg25hbWUAADcwAAABCwAAAkgzWFNlcG9zdAAAODwAAAAWAAAAIP+fADN42h3DsTFFUQAFwD0vhQwyKQCQAgARNAENKEAMAHQAEEEPQANK+Xf+7KyoNAPOVFq1F9GhS/QYFCNFjJkQU+bEQhFLRaxYExu2xI5dsedAHDkWp87FVRE37sRDEU9FvHgTH77ETxF//qWo0FgfaprNFW0AAAABAAAACgAcAB4AAURGTFQACAAEAAAAAP//AAAAAAAAeNpjYGRgYOBisGNwYGBzcfMJYVBLrizKYTBIL0rNZjDISSzJYzCoyszLAJKVlZUMBgwsDEDw/z8DHAAAwqUNgnjaY2Bh2ck4gYGVgYHlC8skBgaGSRCaaTWDEVMFkObm4GQFUgwsIAIZOIe4ODEcYElg1Wff87eGgYGjhPlFAgPD/PvXgWbJsiYClSgwsAIA3zcQA3jaY2AEQg4gZmAQAZMyDEzl6RklICYDEwMziGRkYpwApPYwMAAAOVADUwAAeNpiYGBgAmJmIBYBkoxgmoVxA5DmYuAAyjGxVLL0s6xn1f//n4GBJYGli2USyyYgGwYYgeoABcEDchgAAACwPGOn2TY7b51t27Zt2zZq27btnzQJEOgqurqlm9u6u6OHu3q6p5f7enugj4f6eqSfx/p7YoCnBnqmiytOaXZai0GeG+yFIV4a6pVhXhvujRHeGumdUd4b7YMxPhnns/G+mOCrib6Z5LsAP0z20xS/TPXbdH/N8M9MswSZLVigEHOEmivMPOHmi/DfApEWirJItMViLBFrqTjLxFsuwQqJVkqySrLVUqyRaq0066RbL8MGmTbKskm2zXJskWurPNvk267ADoV2KrJLsd1K7FFqrzL7lNuvwgGVDqpySLXDahxR66g6x9Q7rsEJjU5qMtZH0/xxRquz2pzT7ryOTicvZ3UAAQAB//8AD3jahVsHXBPJ98/MbhKxoAECCoLGCIgNJYRYAOkg0pEmioIgiiBNxa5I71KsKBZaQEDOw16venrdcnpe88rPcr3rCRn+bydF4PB/HwkmQ/a977x5/e3yWF5Q7z52Gf9tHsMT8ibx7Hm8UIlIYimSiJCRQDrBSi53cJDbW0knCIT0o72Dg8zO2FhsJBAy9txbMf1aEDuq+1emoecGUo43MByX7Gu7YJyt6chhxqZO4dbhsdZRCRsmWVhM4l78t/+5uZIf8/wYZo1NTY2VAs/AuYHDhgnMDM2ko1xXOa5aO5L8zX113JQpPMyz4fHYAn4soBvK47lKGCmSISmSMMxy1VdrjqOrX6Krp1V16No3aCk5yo99fhj9gh/wcO9juO4KXDeSZ6C5TiKUGErE9AXX42qyavkrqAb/KiY2K9Ba0pyIIog58UcLqtWkysi0MjKmDP2GH/EQrxvomQG9YUBNBCTULyFqQYRgnNHzgNE3Ym+RGRXEpIQfWw5XRPc+YeX8LJ6Ux/OcYIXl9gZUdiZCKxCnPhYbGRvL7BwUIom1RCQQ4Mz633KX1n+YWnAyeNW8kvAFpamuofUbfLKdyG9i9NGSmyZ1yPHnk2joyUh/35S5s+bk3Dty7fm6CeNRwy5Vmp0XDzh+wOMx32gwqhHK4bec+YZ8gOx6fkR25AN+bEn3qZISdkEJyHYJIAwFhCN5ZnCFERZINTgBpoFwFJZOwKJRBjI7AzY0/Rtl87fp6d82K79JP723o2PvwZaOvfjER+TKqVeQ852PkduZk+TqJ8gQTST3yU/w72sk4QGPaNLEHgUeo3kTOR4CgdACmwin45ezctiaFFu0dMIZm1WHsuo+S8v8BnhmdO0/0XHgcEvHAXyi6s/zcwz9chJ8kqoWnECOL3gbISn5jPyo5Y14enBmzSCP4cCZkTLwIzM0hB+2+eZ3dYefvN5R3XjnUCOnNOzI7t/4sd0xLO4m7DHuWme4NkMty1AZQvAj5X6WX0PTke1FshGdvkZaSOMF1MmPVf2CRap81Ri8RlWFv+SutoWrs+HqIZy2SEWIo4A7O4ntVZSC0ruwoeonLGKCVAH4JMioCM5BxMp443iTebwEI6oi1gKNvclkGvuzpuojRpzOwGfQH+bC5Kk2HitMZrcm1p0mv9bmrbcvDZka2+r/1lvEP6B8+r6OioSH8+bor9fz9Jq/4GR1fUdkxtIx5tsnWpw5pCoO9EIjNyTEJYDS9P4JCC4Bgmm8OTxXwGxnIDYSStQKakKRvAyPiYMDomjod62sEPxFYmXFJHQ1sKqH+klJc6PsAhxzw5OqFfNy4kua7t9atDRCvsh1unuJS+Ym83F55NnCXWuC3d2XzxymjxKiokegTUwgKyM//qqwflVpY5VpOycmblXEyeqGE+GpsYB+3MSlQcExqvvrYuNXLl0sX4s+3XuxqZ3TtcLeJ8wj/n2w+PGwBxORVA0aUGssD3BqrQ4gzlNWj5q7P6LoZHjcuZ3RxfKfc8vnpIcs2j55yib+ffHzuSULA4qf1tf9UzHPadgHHxeeXbzCBeu7eHOcDoG8xCAvU54EOFngF3Lq5yI1wkD+/IXFwcE5noG+l5bvv5ee8UFp3tVEjMmidYeGYUumHN3aVDt/hm3qHDdgeORZ+dZHR8xsDdAnTR0tx0GbNsC+fuG/xRNx2mTU51DkYN14eaz/jPAp06ZsDyrtIJf4b3XPC3A1Em0WS2qLWFkeh7Ya0JqzMo2dq7HpsJpoDw+OFS/afT1h5fWamhuJK9+tKSwpKiwsKmRlBX83H31WVvi0sf5ZSdH12x/duHHz5nWOLolkHgFdtbxBwAqZyFo0kLRW3nji0koH/Qrl7P3hZcf9orvacnIdVodE7pxis5WVeblnPp8rxqODFwAbEHkBCPz0oji1wBHnQ9ky1pyz5Ng+hixj7vxcWPP4alu+8trh/AaG39PNmvcsYGx7PmZOcXa4mUSxcrhuJOBD+lho7YwVXARBrJyUW6afKjFN2TZ/7CyyqwvMejJr3v356pPr9PMNfNcGA6HlzKHeXq3nFwggRnI0R8PnfWDbYqApZaSGgEUmgn+AxhA+i6R42JYPlX/daz616cCmM433/mp7f9MBXKbKxJ/iQtV57EVfG1TW3BrQ84LTmQ0e0lZ7NtRHao7IWmGsORsrqVQB7+hbjfnhmdW3MwOyA8L3xmz/oaHqn0Wrgy+mHn0lrHLxn0Y3/QvDAvPDMtv841b8j5+16FhS2Ob5w4TBlas3v5m+ImaZl9/e7CWZDtW28YG+cTO8nVeGhQGWZtibHuxtFI+XCXvioCAZODB7AwVqbhPo66E/v2ozHEb0wen5bOra7c++8/wwPleHhsR0u4N8msl99pKQ5fF5xjwr8GUgHqmCP5CSIeiHZmMKE33MXqot8LBEPT/2ZXDDb0fokHXG4V7eS4wzhyzcWUyCkFVx8WB8BXr28b5jXBUK1zG+8fZwYpq4BicmoCcmh8+FdFecFjB9tKCQRE8MTTuYYrpyZ7i1J5nThYrRCn5sjzA8Z8lc/ZKRs1ZFMA97ipn1oO0JGtmIeOI+dqjPRTLOEDk3b1iWveGovdhjw/bgjafimYZ2gNtdnBM6q8jBY3zC6c3Y6PlhoMDoostQsB1jiDAimkmxUki7pCLuvEchoPfztu6/CfkBordrZXXZXvQ+xBrCu//eg8+A7hZVR1EjmohzKUnY5UJNvmHO6RFPZIT76I8hZAJYpzam/6AJhf+0Fj4IWOVdu+zU68NVx3CM/uWGtbXzlgV8ws8iStLwKznfEBsY7+L+DOlVIf69IFmiRwJwkfR+z1YCQzvgYmwMYQLrosN0GtAVMoFAm9zIuZOHN87wF2xlzeIxHnYhu5YtW28xPi1+7tqY2TKPMcopLtIZCx1kfq0LZ0udZ5hZukzix3p+Su688R35NWt1QnzyvIqfT7yBpnzqmfaY/FV/+uaimM3oBpmVFW+ZcGlvIxrxJBVOxwgkmga4jDkfFwt8NbYilcplWo+H5BKJGNm3ly6tCe+o7uo88HB78W+HVBfRePQAov9U++y1B7cWR58tPfhGNGuZnc35ziCQaiNIFbJjek5iKXfQAl2qpMvoQMEh4VKHgt6vvjrBhskLkvc92LT9f/uWbpwdNjXIMbIkSh9dJ3Z6YWXRfkut4Qw796jyIP14YjOrATk9eowcj9lMyjAzXfxRZ9Wpr1fajOYxuvxXALqiD1ZJ018kgQ0ihcTEhibA50kBKUBWDWTnVMxMo/nMte7ZOFVViT2qq4EAzxd+naBZtL5a41y5bYCQGDU9mYYeuvXl8eP3qpDf58ivjfxMfr5eRYqnYTwNPNYF/jJVmsqWkv+s2xInq2qwV0kJYFwA1BNormTEecdMQwl1hPCPQUjO5T5ihKwl4gUPcNJHx+ozWjKakIC8nYVskV0aOU/m8fHn+C/VMC5/oq8inJAJ1JMzVbV40bZt3A4s4dcjugND3lgu3mQBZImJRGTSh5thX26Wx7FUoLqruIddr9XvX9y+5MBj8n0WGopGpJMvyXI+3o1gRzUFqmo0gHn8Wo75WtVBHLV9O/BuJGHsMKEI9jYBMrSZID11fFOAXiuMIKzQbN4ECe2pk3YwtpQjMDiAYcKXWipM0JVtO3yqM1ZWBZxyXbsvIj5l8gIvrH/qwN7be5Z+9VDlhZpUHYyUDEPLfMkf6eQ3v+ckTJ4X5rZk1tBhrllRKKYmyVlvqKm1hbW3FB9CVZt24ruhO9C3lbtU99kVYXfvhh0Frwd6z+6mceobHq+fF4ygXnAW/L2en0XrIXUIQZwTNFTnRuxq0Tgjq2ki8t5lkngBze22SFsy1WMc+51ATz67ezOYx0rmTkaioQgoU0rCdwVWnE3AiTzsLUAeoAcGEG0bNPXEZF3Vw5GnfsLazkCkzfSRNYhPHcYZfYzmZxY6OhZmZnC/M6Lmzo1a5OiKro2OSBR7N+3ZlH6g0TA810SJHB98jlzbW8hrD74mrzfnISM0DeK2MXlMbsK/X1Q/7DDNL1AH7u7PNzQngv3mAtZtoDd8TVUkAQ0Rcs6akZO3SdF1ZqahqqKdicvLQ737uhXwTZbXCvtYQP20IWQe1nCdUGKNXgRjuQzcCQMeG8ioc2GFgwPD0TxurHq9GC8OSJ3oOtFNNte1/fD3r37SvnXLhnof5HP2R4gHu3Y9e2Zrlik2ne+ft3nfHv7kb68TG3Qnf1dsxLHQaPSl2ptj3miIpG9Q3HCuCaDbUgUaNNtg39hpZqNH+P/OOSrJfGRViXoGzzzgHL2IlMs84BzBI4CH+eUPjvMl4LyHcjbQcdZ4C1oGsXuKzacMJ3MOd3QcQ00XyQz0900Nq+eqdeDVLmIPjgmnc5dA+nuBlhEXMTVEdISAKroe19oat9oehZ4mO1DT66RKBkcaoyaDwkmrmhQuIcd4mHqxXfSEROCL5TKJmOkLzHcfqvA4wqHafpFEog9usuNyckjyQEwmGl+or/GCUrlEQwC7F7/yGzpWigoukWB05zYuUa1jr+9TXcLu9GLMawXZ5FHZiLSyEdLQD74IXmxesfnUEctUz9rb8ZB2tVAqOWEDAhD988OcfAuA/zmqXVxWCl0Jpg8FxgtlGpA/jhOvjg50ntOXbltcrsrQEWB4CtDOY9QTmnC6GctdDS/DAfpoOEBfsR75vAPveDf/QLufm1uWl1C+g9NTd6krp6dN7NvdczjXzuS3lau6cGCI3/yQcr9Fz2/Zmq3llDU3a/9+QE8zvFwqgRH9JAAvNpdTjDjYPROn2Tt7o9sBqNJ9e/casqXgHcbw5vw/HRE0nXlRQUFypeCSX1pgQt8AZzZ3F0ftey1pc0PwYrdcX/ftiXNjWtOQfcC+Tb6h1TGrdvl6FlzPHXL81Qo/P6ekXE/jeuT8qAOaJtHurmvlM2fn3Dv8zrN0UrXiQlfXsvgjMZG18bFX62L2fnj2ekbcsqO7Dy/lkG4nE9hUQGrI+foEDkj/VNzaUBf0AVefKnkit6eJODu3oSDTI2b81NEustlzFi1eXXA6JNa1MjD96rrUy+vW7lYsmnejupn8VncUjZg59WBS3ObxBiuGj3G2d8+R8bM83NIVtquf3nr/2RqvaRlOUdrUgGYjIP2l/aVvyMleLhEy1pzu+baTEHakgVr87Nxue/a93bshGmg7EgIuj+AoOQOlbf01GfXpc7DbOGo9x//d7tCQ/mhA0wNqI6CYqPG0hpzPlEolckQp8zXajbsMf32ll8cmlptP0VfFnkSHT0KvrLx7hlpb+Jbdq9mPQVuAWoJOz0z6eMBBsm6N2qnCBubeWqCDZ+DabJ4F32eq9k4iZjDyeOu6vwaSZuU951Ec+g5NHYQ4tRKg7sN1H6kkBokU+ErXnfYtNC54Q1xgcgYJA5p66hUNnTGDU1JLGLdcvt2xozhlvxNy7vi0nR3KyaQv1Ta/SDVVjbA5GSPIENbws2D/UprPG0EK27eXoYveiGa30zGyp38SG8lkYvg7uwYzqiAmJC9oSYZtqOJoVvm99RkfFG45n0hiA7J89LCB0HV1zxO7sRmi0Yk1ufmF+IZIbtb12fLZkpW2wfuR/PG3yOvEPvIhck768sSZz+NJrNuKSfaW7lYrygpAZxGRAz4uPrnS+PTDItBkbZcTNJlP8xxajwtZ+JaYfus3Ho9KLoqdSissI67zmEmjBA39Ek5+Ck6SA0N6c/tbaNE5kmJLvsfWZR2iZ1+RL/25UE5dZB0/lquTVMuCVBUotKq06sEH5DiJ6hPMuZO3hhMrAr4GgItqlYQRYNp5YBSGiNbDzJ02cn2myUyF50IHP4nTLLlZADP9QKGnJaK59Xtk5RXS3ZKywDJ7rEf2r9dwTLcNLX6p942iWqvu5AyA3zeO4Efg292k6hxEXxOQ+oFFzf0CE+ZVAvJsmsWLaFTR0VKoUY8n5m1t6Nv2rloOat+gpK7NNVarq5HNXlIlMzIT0Nh/18olb4+Yal48WMUMOgvgOOlaAv1ztMobC9QhAYJowUgZI669AChlhmoRy5nbAc2TWT5G73bcRQw7sSHg9zfOoXsHSz0tORnjD+fvK14h7nFjLpskl+524aqanmDmhFbQoFW07qJahTRapVsVfKJb/RHBqnbWABqJeTxtx4hea6S+djKHPQqsLZB2wsdB9gKW9KIil+nqdYy4Yt3AOIphGGe9rtqEKs+owGu5PUhv83d1td9uRj2VypGqhOFNeK+BgynS/5+bLNE9nDSS5v+Rcx370Uzy5q8Ik9+/43BQjhRtoBrtHzp7oaviF3tQd6HoqrF6VcVhLoNqX8qPhWvG05itUzha6WgLa6SudoTYfvmeLEXk/Op1Bw7vzvu9IKHlgyUbvyR70UXVMWaS6q/NxlJ32+SZzgfzsrOK405kZr+RwkxD5yp3EezMYaDdJ8EZwGBCMfyMdKsUmUkfvLS6oatjtKs8ps9Ew5hn/u+ZBrIzUEiMDQzVbdn+Uw3Cb9rLV20UHKyv2zcc7xy251/TjZ6/kfCfZ+QZu/rpL7887Ychog8y2ocR3IVVc/XqDwhWaQ+K7s1UvTcxT7f6iW71xxerwvW61Z9SudUEnRzM1N/9EU4IjQKLcNVEXW2UpPUNtudCAL5loCrXhUJa4HC0aP+J0hqrkx4LeU8UW66pe8ZwWpoAbp4Z4GXU1JG6knr9ypXlGg/p6NJeh49z3NAT8hYpfqeysp+/EQ6h3AnKy+NOyhx4ZWt4AadYoD3QHffNR5i7rZwvttS4tLqepVxmMuNCv8xkIMP+KYpu32CpVtxsiOfN+1+vH68xVOaYDLoeC7D+oP5PDHhoC3uijKtWLGWaeYsxXlr5KB+Z/vxFO0l5+PWBzvDq6PPlH3yHhz8/XIady2pXbpRzezPo/Y6tBkpc5iJT2w3NaUGalI4mwhoCbS5Lh//oGk0tZRqTguw7YvnbuzOzNlfFefksnjpnRvXWjjXr947smDPLxmsKn9/BCqL2jI0+VVhzO72g4UTVhuWxa9IzmN9RCVnXM7JuFyNQjV0W76Gsmb9h3pzN3uefpMAe7UCztlFk6vrcGoKS8b94y7UWDm9YWBEKmTHZja5tp3ZPj3KTh9rx+W0sf/HRnp8qahoOd3ad6UXCO/fMTYrKULIB6UyI8G474A5Mt7pf+iEFryjcVJ67tvitSx2XJCxPE2fCAAONEKESyoH2IsCJqPlK1DlNJYoAylH7lqL9H5EC8gWyq2nYf4TsZt4sgtyUH/vGlcQD8SaqQziwcGNFXmb3earlwGFo7//Y3X12KR9MwpY0Ikto30ifZRZkNXbM1kqWH7mn550E08nS8aNm4OEdlyYOH2c5Y66Z8gT+YqBQ+RvHeuX/cQNHqeZgB2LY8nh/vA+3yzjAUMtpE517yrXRlJ744IDwbHIHAuyUtpTAHb5tsxWTvSbz+e2AZTeeG0qD7WXs1nNf1eq7f+2/cYB2ayfOEIdYmuOPg8+pXKVIp1S0SpBQ/tS++vPXxyiX1DLHDcmmA5F7FnWE+TulevH5rXz+gi01eD7esW+faofqSEj9hj/u5W/w7Kh1WT9vzia38vd2OEEszAJOSZoZxoDaSCakb7Vaz2qHQ4rpmPsPby/8ZkWcf2vmwsKghQWBj42+ia4Ke6V+zaXQxCjSW33k8baYfWH+Of4b7/CzwsJWOnvPjFsQsNy22mFtzI49fl7LYlakXN2UXBM6dPj8DUFrGqK5fVvosqQJ/86SDAfkZP0ypcPtpGzG6BmzPMIc/CY4znIwDRjgUgbNzzieehApX+POm2YmXF8LIW5ShZBEyCkYZYaOdt7+sJn8iOacfPpjC3IgJiiBf1UK2jVz7sR4qm9wzH/i4SDqcTgBup8PcPYBYk61aqJa04BXCnixA1S/LWhmq62VpXJd01skQbSeS/m98OoKt/UHF62OX7DFtyIrEF8np22QbRs5iuL4sasvb0uoXzuvTJGTUVnWPRlXJOGVqjiVE+fFRgGXNq5PAnykwAdpvZi61ap1ioYi0CrNHRGjIE3ZmPnpgT9Plj0hG8Kzq/O/w/5isgkpyHXUjoMdru7YemYF5F82qrv4DB5XlF+Wo5rPj60gMyvgVgvQYe39AqDDQppLaWb48HkI1emT8BmSRDU+V4h1/L4tIHTNDwf4qX440qc3xb6SRnakNfVrAzG9f4COVNA8Xcr56Ih+3mBgJBIY6mouOoMXRXCHNY46h4sTR1hYzZiLfwlIl3rQZkqnf65k3lynNW5C+bqobRXGWg8BuvOxxkOQBdBWMQKtyslaUeiBmnX9lqatqkOwNzmgq6caPI43Bfb5H70d1LeDtDO/tuPfHZ6OJqJPPgH/Mrnt/2vxAJRyra+hVYEjjZiauUrmy+Yq0Irrbr+2dHd4R80vP9Q+3Fb0W53qmyuo619TFSuum8/wHgHVRfQUR9C6Vga2QkecHHkFR5M7VYgN2KkObakzC6ta8tblpsaLhb8e6uxAy/5G5sxliOnL12xXqLryGiveiCdQPH3Iw70hJOJFhRT6/8jJjstbNNkEbtJWSBFg7cZjfPzzt+zdg1r6VUiC3kcQua5pcq2RgHsCpznuIvBwjISRWoPsrWViiUKtSZYSTpUYJO/frhWNuSm0tUDPLGzZW3uM7qrMsMHECRYjJKicRCKTVCO9MRNt0aqCKkVO5YHXm/bbV5H7qDkbflllkyj4lZ09c82R319FPc8PZ7OLSE7TD03r0Se7sK/qNLzWqqbgAtVGXAAYkwBtAr0HRQRaZMnpUSbojoEOnABDrJdRJy0R87nkXlOa0ej7Cp62PHq8DE9VeWL9ry1MnLz9ya9dDjmZSE5eq/soEY18a8QUiyKmu8hiyogq2zdRgApVPj9cyTqSnvfJkzNr2WaSXORSjqLePNpjD0EfndHGZyEg835pjUy5M++1k1cH1MjDOU4vK5E1XQ3wGJp7M8Bj6NO5hzXoWhFrTrM60WAtdDwi7aOmPx+0nk3bk3ap8cGfxz9MRj8RQyxHj8lC1EZfo1XvcmscvWSgP5SVUbukiZKuiqP2MOjwXipF2y8nbdq5IbDdJyjo8zXrLqVtXOyzxW/r3eLaz3yDfLuyKisLc2/j1ZFeC4NmTE+Y6zFv+7KoVDOh40q/1L1+EY7J8nlJURELOf7XwYAe0XsaqOygkEScTgNjxDxSDh9KXN5TDtdDF+Buhm/RT4lXfHoaWXNitOKaMxPB2d55kH6cYAhvFJ3RD6ABRNRNCtR/Rs9cqx8uJAHv1guHC9EZtDK32NNbQL7rP6TPUbMsvWPfs41jGXJo+0RmW08iCUdWuWzRgCk9vSuFntMo6uk192rAZ0N6bq0A9ibs01CNkUpUlzgpRMxNpWPb8v0HlVExfo0zKOfLDq711egIWbsq2mUWugd73QJnbw80IKenfkY9Z6fuxVCqdWUIqKOx3h//knq94PEvgf4LN7hkY5djsIPW+jM7jvrBm2lktk3C4g0J6Fb3t0AO0J0B9HqgBRZ976jRSQxSrRd3aUw9dmtl6r0jcVfnh7gW++crhxN99OvIuuwF5a5BPq+zsvw/Ghu7S12cUmfMaLmQd7x+mt2auU7aOnAzlch3NPatg90o+BY8I8pVDImFWOeDwaDlMjl6sakbaKj4r7Lqu+u3fVpC3m9vRz5HDgdtX7Cbb/FL/jfe+7cVHHZnWvLvq+YQD2nc4g3Lgf5e4LcL9iSkeqGZdVtq8zk634bt9b/VCbleudKK7y4sdQubGeectVGESkimoDzZOWbqIudan5wribGvgQDdS8lU1tx41uxV1jYnDuada548aYWzc95fzXXdu+CcfGBnSay5dsrtqi76oMiUm0CegS+gE6+SI+RQG3oFLSZ6HRUV3Hkz1T0pQBrn508iepxmrwQqDUCFgfM2AGvXeHqATdMDIIjPFqomNeLfVCMXIscP0Ox6QogK/UFGAB1hCUmkZPf1ACGGs282F6j9x1RbOOVz3PDpgZY9TTXNSEbeX8VVMgnkBskZidNZHKY6jj4mtvT1B/pgMZmF3llM7FDrjh2QpXsBj2vAQ8gbBVzGAxcNXo6DoaGGA+rD2qsReZCL6AL5NaXn7xXkd/KqEJvpqSZ9jP65cbh6/sH5NbCVWSXEoR+39q1be5ZRLDeIA/eC0z4KU+3hgilQn0zRTrRhoE3rL834WmMsmvG2dpj9Su5O5fm0au+YINKMjqo6mZlkXk39m8lXt6ZkTg3xRW5+5E8YYgc9I2GzCsMSUgyGW/m5RS/YgRZV7CT7yvYnFvjqDzObZG7jYyVcsfCnnxae5nQ9lESy6VTXv+Xx+nmHy9QbZICkWtjN9Fx1U2utYiL0Nak8gyz+mbB06QQPqcOo8aMmWI0i4D16tjHD05cbGqQJBZNn9CRylCklQQH0ACpo7+PhQe4OyF7wPhdYmS7jsnbGfebT/e/rE1hr3T7IBZuPTixcaLzg8sn8nW3nR2++RkpTC52ci9esyXdyKUgOVigCg+fOJlFbxe7rlmhm07/mn1uJctQ31Klvriu4ceeTGzfu3bpBJ7CAMAK0guUNpXYOqiDlsmzGTHXsolKJvxSrvsKL8/JUoOxl8K33SRTzNXx/FNXUSZzm9w9K1AxEoEkDmznM7CV+S3NnTZCf3BheFNjzIxDPNd7mT8fXdo7eyqMofXVUnOeK4PW+pfFkOzWPvfn5z1+3NUsxGuMVVLR5zz4O8QyIKa/SGGv2sihrSeM6xNp3Gn+419YBsbar6d73rW8n41GbzL35L4u4RSQYWRVx55ZMpFzchXPbSs/te8RxvsVNq4Fzn2k1v++Emd1TYuHFV1krb6EZl0gd2v8uafhITRSSAohMrZTTD0TMadktLtsFakaaXBeEpKUklsqloluti2JmIYtOch5tPUtenRWzCGhEPnyIlMRM9Q56/PQpGc2h8gc6y+FO1OGAinozzngVHCpLCdc5w9fRgfdIg1KpbANYPVfQTfIJOY/laiT8t8Q9+1Hrvfx8jtZIboZO730cxclW8WJvDIyu0VDlFWR3mRxAB98jxy4ou1E9q2fUd19M7U6g0gZyAm/50sl1SgkcQiyxUyrRB0qNfNAdMgX254Yud3+rrb1OAQ315BrUqV/dsVuJ3hGR+SQFSFQrmeri4p6UgRQuAoqtQGGw6fFWOCiKgLHQ8Fc7eLgSOM4C+1TClZqpd6bmKjRQoftpvlg0C1d2kBu4NhDqoImuM+d5Hz+m5zYvKFkxRJa/OqOSKnRVzxquyk8FhQ7J27gXaiC0f0FgoFdKSMx+SEo43Jkwu/and2g7QEeJdi6Avm5C/cIbgJu00r6VCfvce8zsrewM8syNyT04v/BKlnDTfu95c+e5uu7LIfctg+22V3vkLBHuupmefKPEc4Pip9onlyODixYezYtq3OlXHF4d5Ru+2C/g8I0KdrSh+L2PS7siinf83qrsKTYdD+jOkAk0FzHkzRh8Xq3oH7N1npPCxMk5jTCuXjqOjqtnRy2OCiyaE+L5+pJDX6xd90Vdwiu+Ie4FXoWdwWUDZ9Wb7CetmetR8FcjBHEnpzRbW0D2SignL9gVO7v/OSMhPTE5E1hq7sVHt41IgZJsV580U1Pak8pUloIFZkIccIIr6Z3z6g6wCAtIykmun9FBUqBKus709DQwi3tY4sfxSuXy2f6azZcipGnBIDaO02zVmasojxy/9ufTq6QN5X5AHmh0DE9Fv5ENqJAYq95Hb/I0c+wwDXY6x56C5RJNJsGn5HGjwc+t3YysVWXRisrRhFJzb8ya5+ZyuSHsgxLmkO0BSrGU0hjdtH6QTJaN5RB6901ntWIZJKnlYV1mzPBMNM8XDEIVx6WgL/rSZPRU7TgUGQ1O812g+Zh/h06a+8cPGj4g33aJDYnLdZjgcGLzrpaeb5V4adbSlQtXxG1sr1EV8N8weD4F8LzGzRCBCp/m21oLH4Qam039TWxwXJ5cqgCSSiCpOZJBKYshHwij8dmG0/JQ7STaWD2K5g9yD75Bn1vwxTPNkw1G28v2bissRJ1M4I4Av5WzQuY0La14L2Xl5ZzLNzEi61aXDEO/MFm4yzl2KjeFtnPYvmX7hgO+Uyck2brDnfmHnlXCYwncnfn3lB0t7RCTxETOoYKYpFRPqMMgUmnv1xcIAC33mVaggiHwrS30W78STs8+gah9hzX/14SaM5KXTag/URYgs1Okc8Zd1Bq/bkLTOfKFf5q6ewnBGjytI3pT1buA2D7fGFNcryS/kqgBkToUTmgRcBVpdUcCTYp+0+krSnJytL61c4ynj+Xc6dIR4xkbWu1RX1lJvu/8ojDMOtlkdvLrh1GrprjjKF8nUbQu/e/Z9JsvMB8Zogk5/YCi5n6BA/PeA9TLgPbLZtPmJAKotChr84o8vfl9L87V4YN7tzT15JhBK0rNYBrqyrkdcVqjKfue721eQqvL9x1cwGh2kdykaBcFutGTXKSeSa8CbK1AV93NgFzHygpQMcb9JtLWzF2/YzZClu1qfpfP8i2O+H55sRW9mlfg6Ys56pgJO7tRNQnfi78RpnrOmqtm4g+1sgUNok8IUQ0aptagn3Sr/Ee61Ue/wqr2WR7QvuE8XT+EXrtZfS3tYnD5tRnY08S+9SvmagBIUIyMxPTsrOUvqlifxvdj0z7a9d6PmME/qbpQxc7SSsSW7wrM8wjwPglV7NPm43/nIYM/TKeJs/lD+PCA2KcWty9OmZU5xw1QUH4U62k11l6dZdDVLepViph2WPiPdZneoz8QyHkziYT8z1w9i3b9z1n09Pi6rfYrPfcmlx6qP9SR51V1O3PTXdKOTqnqGClBWSTSJsgx2nPegZryjdlRJ3Nz3kxmXNHf5TmqC46AgXZZ+O8Ahm0UwxMeT7f6SLf66EWtQld3aFd5jLaC0c6iBz53g9S1NEP9U/8nb9Bh1cPh+Zs35/duLdLDpkMK+j+Cozp2trUVlyqbmpT9uV9Wc8fcKu1P0NVc9epfuh4L3ZVhn13RVfrdbA1+3aqgQLf6OJBbpbGHfnen+rsPuSm0I9jAGNa87xTahJYsOJ/z8z5K/IWR6itd2k07/bQ3Qynl6KTG8iqAK9Q+mhm0xeAzaHU5ZMhVRujBq6+mwWBY60+mq8uj51ApFRUNcCrAmLyXlwe0o4GLv4bLy+bcfXIIZunPPzv0cVqq1H9lEwN5DcwrIE+B7blSHwZRIbYPdUtOYW0pxXd+f6ah+JDMZ1ZSIgmolhK5NyEzE+SmfcoN7HsE1TMDOmn8DOzCQXNn5eAjZctBsz9Nf89QZCJiAgO2Bw5pcZ81Y74NnfyF7VE1J1X6Bu1NjE6aZGAZ5ha23MrHziVl7rSpsfFHWsy89m/En6ts4lM8W/Z4ZcE40OPS9yls4d/Hjj6viJ6XP2fx+x+WnFqUVrg4PdseDWUfG3f7gecRA95skMMksIkXjTNrad+pM+2jmryYTLNZfH5868q8Zp9lt99evTk75+9/Pn6QtW6FXYKTItqBz8e/qZnn5pzYGZm0PGrnsUNrdlmeiXL0bN0LyEBK+0FDp9G4p54762bN8IZyM0QKpKCa+z80bfWWnTtJA4r5+Ot3ThPy+VHk6sXpMdqfq6FeWTuGJKJ3xWS8pkDFvGHcOVAOkwfMkxg+nfma/PtMQrzHT59gOnw81j9+zWSklUMQPuuXE3R8juN0v+kwiObzl9Qap5o6p712CNWRIWg1+efkNyWR0zwr05HvUNLmGddX8oAhGjDUA4bBp87yQRDgKeR+ayuyalvvlxfcNsd5qp8tn22H8X4tKvKjYdQFXVUlk8XAUzWU/DOAJY0kPzDf0NpowOyXBlWptYQGWizihr2bNzQsiHXaGBRQFrU3zzHJ7oYB2un9xvq7Twu+ZGXuc5Ntp4V0ln932cQETconfBsXZIIMW37P4WYGsDMv2NkYbpbtObg89THSDLlxy7L9UcpYf8cUD5Zpw3zvrGoSRzqZICNy0Sz0UCq2Hqr6OTPFU1m9IGPurKyAwje3OmIBaiotJYu4PTWB9/TQ9PiF/W7a0I2vBzEmGeM67P3cwl1Va89AT/+b/UV3Nodtc1q8MfXS2tQvgoJ82oOydm5KwquLFkZEJc2TJ8+N9N+TEpQymxm7JmLJDnePuQnTZwQt9IrkvMVCyKZ6aDYledkMW5u34U/7uKYjSrJ+9Ahr56Ve3pZzbKXDJf38Ev/NQXI44DYBptdtnN7Q/g1S9724+TVfrcdiOso6g0yfnmg7efQfZH7yw4+IvrfZVEuL4eNQ8U8m+laKoP4ujzgap5rMTnmrAdUVkD84tQUrjIQYrgS5CnhjqP1zPOSGln0a6CKhSGZCHx0VinT2b8WW/Y5GnPv0BhmRmjcnvCIqINb6xF79yemznWKnTomU2YbIxoNyEKT6Bn26A71pXPR3Y8vTfGc5EUEzZbtbaGGIl+pHF5+Arr01p0IgygzjnuqiFbMJVBMKQKI5QQgE1pqTlSBDEwZRDC+vK/Du75LXpyQnnEyKXZVwaj1q6ul4WHMbvS/ctsw/0c1Pdjxlc+fi6JZ1bccxJp2LkoeifCaKORa/Ojpm55hJFavja0IgtfzMmvihWxeUU6bF2SyseFZ35Gm5ptC4r+xs7QCvr33WFry+iEZnzROx8NmAzgbgrlja39HNxVG/5yx6fdCXPj2/9euCMZnJ5Ppq1RsD2mBM70+aXosIdG/mQF/2Xx0Xe2/TaRPHgUuzbP/cGNQimDEISJO6S91mOvtA88XdOXi1YohdQVJGlU4/QCd3qT0b8X55H6ZPF4jq6ZT+lYDhf+DC5uTt48fRnLYzL+kFoTtad9f97X/1g0pA2ta0Tzim79OG2tilmYkL0WzlNr9tvs/Pnr95P/3OPuLWgVqNoUeQNGFx+NWctr0ZtQGMSTG9c/Z9sIwJoJEMxKeJmom4zixeYhXoL244/l5ps29UV1F7knKX/pyjioi8qZO3+izPnGm/Ep1WVbE/QNJ4+J/yTWQomEJ1cGTBKhfV307ePq8eKT7D3S3Tm0wiaN32nxNz/4BUXamJ07R1W0TftKelX93G7/2Be4pJnRfSqZUtnZeb0Hm5QiZCMNwRghuTqxWMGTgrF3/NuI9FH5t6sF+qvv1nxSg9sblNu4l0rLGeKarKuHXQrnZf1/3mrhkHYbp8qoIbkleQBegUJt9VnVnj2V5h4pzUVYbKwcKelCIliYQXp+VPiAl6ApgSuQk57TWJtRPyBAlF1OcmKcjN4NYWDiHqizwR3fh9lJ6l3DWu4HiQcl0qSiIu2KXnprmb47Sh5Jvvh/iMxd+Yewt+LGWYh9u6toagyKCjm06258WUYaj3Sg2c086W9CxAJ0s52KUkALRqPuBZPXhtrpmKX1eSutEjrZ2gNgfvPmGEhPHg8pLBS/NkdWaCtE8G8kZzujodq0teE/jt4EDfY6EI85rvregs6uhoLen88SnaMSL7/R1YQNiajlFMQE/XqLYa1KN6/hpRick2HtJOa+gcUkSf7oUIzPlF0E9hHxa4ZePmKaZmx0ebLb1+pK729Whl1n7Q/1j9OGXWGjSqKoeoDtY8yNcnm8Sodnh6RzyuVa3dmidiDkMU1s4/edOBC0cda580BoYGChkdS6mNQa4Adjq7sGaNLV0O7EvcOtJkS9z+akfr3dKJw8a4Ozq6jD46xsXR0c1U38qSNY8nDy4+Jn+uW5u6CTG/XUSS5RmXO5clNSyOq1vUY0x+SjgYubghaekrV9IByzVswzzBF3gMzR3F15gJ2KaqCjwxMmT/ZA4JClhv3mO2k8e7ynPhKiIzvoip5j8CvTeh8RtCh9o1SPq8R0UznJ1nTJs3D6VOd3aebjtvHl/kON3Wycl2uqP2fx7WcgDeQqAFUUkBL2RYu/v1+51V9/hTUbQXOStD0f7kPA8hX74PE89/h0PqCtkQE696iE35PlCaIrSWSJnZvPH0CWCuxyQTDxxd45YlwQaZy8M9Ul0d11g7jPWVyN3JI4fx31YNWe7oFjHF1CR2pMiSo1VN5IyU58QTg9VABaFJkYQcMRooGT3TxNVWds7jFZYGFrOtM3YGNDo5TQvwlk6TCYX5giEZoV5Zy0B+pgIeUyX4hBXyHkFc+wVWDPjfMgeF62HlsWZlvkDBLBecgZUnmhXNTgQwB+JxaGz5I5gcwRA6meh/6wIO98sOGbLWONzbK0a8dkjYTv6I/ncioKkCPWaHkAXqv/YSXs//AaUcDTsAAAEAAAAFAIMbFkmEXw889QADB9AAAAAA2wktdwAAAADdVa6+8iv8GAlQCWAAAAAGAAIAAAAAAAB42mNgZGBg3/O3hoGBM+GT9rcNnAFAEVTwAgCTpQasAHjaXdMzYOhQGIbhnGvbtm1v17Zt27Ztq7bNpbb2qe7UTvU7fOXwxPl1kmYe1hqMbuZRlcu+DNuRhJ06bo0FmIinPFfC/gl+4grey1BcV4xeWAR72YnpOKhYGzAY3WryYxmWYzhs0VfvzZIueACnevFDZRl66t5jzFTexbitHBOV28JBsRcjSYptj5Hav9WzwzG60ay2Sk09Lxv0LOp3umgOppPquY3+Ot6rPqcobxvsw3YMxGUMQGucRKd6a+RFXcWKPw85nK8De+sYWuKn+jqBWAThPa5rdjfgrxgX8RlLcARj1eNfrNd754CqKq1DIiYpfrqsREe4wAshmIXzynVfx6dh4ZNqiUckussV1Z6l/LFI0LNH8bTe9/kT76Wm3+uIlff1+OO6aA5mnmbxWvM9jSfoolq+oq3uvdds7bABQ7BF92v+iyTqKlLfz5HI+QkUcHwYS9FXfU1HtGWZrtTR13Q1y8wF8970MV3MUo4mmnHV0dcStgB42gXBAwDjQAAAsNq2t/X6tm3btm3btm3btm3bto0EgqDyUGtoMrQGegr9hdPDbeHR8Cr4IIIiTZFZyEXkIxqgldB26AR0BnoAI7FkWEusIzYF24U9wS28MT4eP49/IkKiMjGReEK8Ib6QDpmUbE+OJE+TfymaSkdVpXpQ06gd1A3aorPQI+lr9Gf6N5OEKc30ZlYx55i/bFm2BtuAbc0uZ69xOJeMq8aN5qZxC7mV3BbuLfeDx3iRL8pX4Gvzzfi5/Ap+M7+PP8lf4e/zvwRCyC10E4YIK4VvYg6xpbhafCq+lYDUUlos3ZR5ubhcXq4u95ZPKZKSS2muTFXeqDnVFmoHdYZ6Q/2h5dGKaGW0dtps7ax2VSf0QnpTfYy+T/9jFDZKG5WNHsZg46Tx0ARmFbO+OcxcZV4wP1uGlc2qbE2yHtqp7OJ2A3uEvda+6WBOMqeyM89Z6Wx09jjf3SRuJbeLu8C95N51X7gf3N9eZi+fV9Kr4o32pnkLvTXeA++1981HfN63fODn8Yv7vfwt/g3/QZAj6BwsCZ7FErHKsVGx03E0ni3eK345fjv+OMEkqiVmJQ6HcJgu7BseDT8CF5QFk8ECsBpcBC/At8iPCkQlo0pR7ahxNDAa9R/zOY7nAAAAeNpjYGRgYPjExMaQwFDBwAXmIQAzAwsALeMB5njalJDFWYQxEEAf7lxxyA13d+eC63Xd5XccCqCWrYECqIBukHyD60ZfMj5AJdcUUVBcAeRAuIBWcsKF1HInXMQC98LF9BXUC5fQWLAmXEpXgV+4lpGCGzQXQHXBrbD2yTIGJmfYJIgRx0UxxACDjNDLE+mtOCBOBMUaCWwCKG0Z1n872Bgknzik7RfxcIljYOOg6NB+XUwcpuinnxgJreERpI8QBhn6cTHI4pDijH4k0muczm9jb7zmvUfkiTzSBLAZpY8Bnf00yxywwtITffb5Zt37yf73WOqT9hERbBwSugL1Fj2PiNIj6ZBDCJsEJi4Ofdp3mj4MbGL0s80aGzwunCEVZh4AkbdX7QB42mNgZgCD/3MYjIAUIwMaAAAqlAHSAAA=) format('woff'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } @font-face { font-family: Fira Code; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff;base64,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) format('woff'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } @font-face { font-family: Fira Code; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff;base64,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) format('woff'); unicode-range: U+1F00-1FFF; } @font-face { font-family: Fira Code; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff;base64,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) format('woff'); unicode-range: U+0370-03FF; } @font-face { font-family: Fira Code; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff;base64,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) format('woff'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: Fira Code; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff;base64,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) format('woff'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } ================================================ FILE: packages/graphiql-react/font/roboto.css ================================================ @font-face { font-family: Roboto; font-style: italic; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } @font-face { font-family: Roboto; font-style: italic; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } @font-face { font-family: Roboto; font-style: italic; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,d09GMgABAAAAAAMwAA4AAAAABZgAAALdAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANBEMCoI4ghsLEAABNgIkAxwEIAWDCgcgG3YEyI7DdHsjE9IUV+CFDh74vPL9/MmgO0un0soqjWt7En2kQoCMtXsRxyxkMqP9iO6NfSiUaLJuoRIKnhI0+ImbcWOB5XOAFVmCgxZQQmuBJRhZtsUCXm/492Dyuk2YZJdkdApZeOzyEQgKOwDgRjASBEEBVmAlgACtOHEhpjLyyrACMAB0vaLa6cAw5bc5bvhA2uwO7zXAyKPmkYNnAJgBxLEMDxFLqVBPI6EQ/daTr/QOAgfCngRoZc4UZiL623qCkf/oHVsfRCOuAIbJyF4ajQQKQLmQhNBAA4aygH9b19Xw4iAC8DkKM6WrYw/ABMAOWEAamA7sgBWACgAUSlc3SCmlc95o45idYD92Qt/+5gF19v3FALtB9+7dq/h6/Ljyu/zzYfnngwdlHxO+k39nOcO/e7nPf2vCoo3HVlmNTdnWwW3JZffuVU6cQX14kb3qUGOOJ+mjP9iMeb1Nivq5gXpJUWm+cmVK56e6PjI2uce23hHlG48vyDvym5/5q+wbkjq90rN+z53D6zXqmVUPVshZoVtrZgc4vleS1NNrni6VR8I/vTrpzpPwu1+1Pel4xBIzK16W3KcLNnVGl2RGZHbPXBAvhw4M02Ci/t0BBfw/p79XS9V7CKAMF0++DK9rtI/7MXvGATjz0TEA4K4oef476t9dS555BAoLBYCA6ei/FSzVgvg/cIR45gpTaLWeLiB+oa4xJuTks7r7/xwCmCzlpoJKALCDQmkyEsCsN0mELUADghGsGgAF6c9IXkabDYyqg6WMkZd9z7BT5gaphhhqnOH66aOvkTQhggQLpsk0xBB9DNSLJttgPQTQJBtoIE0JEY2wb+1lhF6GG62XngKUGKLFECMNkW2kZgP10+M31GZUwfojwkU0uAcQkISKFNtqGMlau3vIjjRUjMANjYkDNKeouYh7CRBmuD4CHQgHG6GXET8oT7ZU6QqUStddiABBJPSv6P315AAA) format('woff2'); unicode-range: U+1F00-1FFF; } @font-face { font-family: Roboto; font-style: italic; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0370-03FF; } @font-face { font-family: Roboto; font-style: italic; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,d09GMgABAAAAAA8YAA4AAAAAIAwAAA7AAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjQbhlocNgZgAIEAEQwKqgSlAAuCFgABNgIkA4QoBCAFgwoHIBt7G6OilpNWKhD8VYINh9o6+IoibkckFlELYovEnhpqEw5rTn/e1suwBSjaNcu4suz9n3jcWQcRrZXVPXCMsw+MIR+FMuwj40/HiI9xLIFVlPzc/Dy/zT/3XR5pAGb8ja8LKxcWukgzwYhaYGNU/ZQFxqLUVbuKhLd+MV/4m+w5Zhh/TqIcXmFFha2pbQiiNXT2bz+xUcQ2ClBzETSjEUCShW9ljKqw9VUk7wy62bj2txdropFFKSzBta/GGt+Y27eGWiiWyt7ti0gzFst8qOChQ0ge4e4Xlam50l6yu9/9571CniizBRTuQZii8rm9Jr3MJgXO5YHQ3fG/aiWhUC9UCdG2QoIRVa66XrCQtr6N6d8LoO2fUBohjoNU0/lfEUIVAcAkglGnCGlSg8wqhwgFeZAnQEDWpEUo2+9j5/Cu5Dy+i3cj9dodvLthT+/jQXc+j+9jQ4rqABCgQFVZgfgbAXENFhRCfbAhSLvJmn6RxTicVSDHB8Ca+Dznc0Prx37oR1d4uq/bnwjmW1rxklSRuTn+CMHl/qVl73Pmgos3js84a3+7n77Iq+1vE+1Fe3EhBXNMmbNkzZa9pZZz5IzPDdJur1AZsxYCloY5KVb4Id2f00SQWKZSyXIZxEFWb0ciZZweIg8biEPPNMhI8ZFLF97yWrRtwsAfKm+mqTSkjNRXIJrSEARYZDpddprdgvERSxcFBLCwysSIBqbLTaXhv2f1A0M8oA30gf5m+sC+2Pj79CaTVAsJ99HmgMzkreYnj7uutWi3UZCfeEK3Tp7cg4LQ/QaGwOPB9geMQt8AsFuWoEsXXiiY1jpMckLx8uE3sWE+MOLIUDHqk+R+m7xPvo7+098gHWLLQNHq1djde79LPpSvKM6AiH99Hmb+irlbd3fp3ZrbtzYPEtmzFO10pFtaeULsgC6LMEdY/2D3Brv7XjMJlrmHZcjjUJMYXcIDQaKhRP2xtyjW4vtCx/AR2IYtAaVikUCEbFqOgZggNHw9TiTV0zivDoHumy5YOohObF03tTrQ4VJlsBoLVDxVP/tDiqGrWr4E+6dyMcgcXBHwjcvr/Wio6T8/k2j3OHZ7eEDLUvDYK0qwnHYVzdyxP6a+hhg6UzcgxO0qdGIquQ71IHGYGYFAgyY689cq3+BFK+UiisgwhzE80guq+evJ7BabrUvK89hDJ6GjaKnXnHitv5Kiv71suv9EU0JXyUb011Rpa9fDLWF9SPrArCFyfg46z168k3t2zuGwtbZT1/xVsaOxlwjJ7KV+eFNfSxJie1oCtpsVqnixnwdz5u2z4oToO5UhpzRdZZMnPr1WRb0EyaYInb9lcHiuauG7pwjRQ8pZyD+89BCy7roasB0G/tFty5j8x3YGm069vWUZqwXisRsa+XTgOhfV/vxvhS0czgPe3oieIlQz2Spt5ypuqKo4fvp2+SIadwu6N9UfWxL75NKakCgf59Aidg4vWB9lT4ud57P8FGjmUT8XYDza6guZC2dpxRBWBi89oRP77VGElIrA6MCemtZEzOKmnqPApyu9WSAF3ksWM8OYQDxnfYS2X+7t9b9Ys+Bp6vl409pkS8dxps+CulHTNUbAluhid+nMSJBU6dB07+5VxIcfL+sJyb2PfcTKD8qEwLQYzAApmcHCQOhpnK38zNesrPt9GAWVoSAMu+fy1x3OO2aaIRnikpKp5Wq3s4dhKdEn8MNHNTpF8nOSHI2uvRsuCCB3X/1Hvhs2KFQQJzdlfCHbyWzHiD6tNK/OtKP4Iv6oTf+Ao82ctyoJgsYG2PdbyJmmKw24GJ9vKTHiPCYcyOmWm7V4D+WLusFvhQI4Q0qYoqt695xlHuBq4nxuxC12FVN0bYqZdp3dWv6/GLeQZyXqPUzRDQife3X1jsGFjkDF3SGGih4lJ+Fbc656cy7M77xWfXL+KZDGaxo0lg/jarRdQiti/KN64OEeYHkxQoOTg1Egqg6WXysFevCW+hMb4tEo3j0j1++jQlmjPMe+IPZG7d7Wa3i3yuAfaRwrnL7aVwBntBUGqxhnRPnEThy6KcpCyh6GIW7aJvFu3IS33aPuWyBVIqrjuqJQJzVn0Ou9fUMXjiX6SzzfwTuFY/i+HufuKnZvJ+NuyVZiGO+do48TDlQHpvs0p77olAj34NKGKB/nsEuJSOFUEjHcZdIhCyfyBcnDcH8na8ZuJ6/i3HETuX+C8BQK6oI/i9aVooM1gT/kmpS4XU2/XlZV4RJ0qMbvs0yj3EgL61X9bbdEqjMjI1ssIPyIluCo/XLptIB1rOwcsQCLiem7yuNwKrZw6zRux41z3Mm0XdL0vasNKW6rNzoTB8mYfrpIUcqasfsH+tmqCoZHDea9KqaeIxzc2PJND7xwvqdxsEMea+cfe0HjEzw2nd8D69PPTch6nhvipm2unCIr8P/T3G1GPJoPt7uacVpUcHxDzUmk3vw7apHGZ5xwVNhG1CV0RKIenNnv9c62liKv93C/g58BKSxXqCDObE39QHZQ4tWH9U7POCj2DBMPcHFrBCO1iLupF/RXajiqRVOiyZY11ZMG8j1Kzs3kdOPlRryX8pM3H3ELYY/c13SvAU9Tvhvp/eRsBYN566dxdtkq2Y3h3Pxa+YbsgQwdziq8inG4ypu1ZxCX4n1VPp/lG+fp/TS3HOmpzOpNwJWUo/fUjyZiF3p2RqUQJ+D/qv0/g7tQonUlUTZTzK1pBeVT5+b2M5PylRq67/zKbiGu4vdyapef4ZT2iv++xUZ85i+NTuaOh+D5oE52pK9rkGRE8P9Rjs3fOoM7cPNlxfFHkXaAFjv4Se9UKfanensobAYrlzdy9Sh5dGyklWArycbCyuxlVv7f9ZtwLqqvQ9n1QK3bjF3htCfLAbYe3mQl5hQHzT8tvWniSWjH51BZCfniQKRxJ8YB9XrrJMPszqtKraJYBsOR6dohF7OFEIcQG6hb+jRZbrCy4Ytc190n72O+u+0K/KiIVW+OhdVZCSOsM74QyW8m6hNRCKpDOHUrOuBrc137WvmqWW+Ykz5pekYdK+3a33Xesm7n2TdEM9hanBkr79zfedaVbEz2zG9C42AreNDYM3lzQgqW5MRIHnfroBdTNiaUcpcZmElNWU84zXd2WSnfKb8fDYOdVzsn1r3f/Owhkx/ou9QweWXoBT3+Oi7TJTDQgZexYsNbNmSFH7zNtT44OJ0MNr22MYW98XkoB9UmhYoRmbIJFamn7uNw8u6F0sJtv7mz3EPfs3A+Edau0g0Ws2N04UBKIcpFdemhNQin5yORRsaEDH19UKSr4ZZ1oS6EludGhdkfmsB5XhbfVteJ0POCy6ltu9WbdycW5sB32JZko3yQsWLh0qZc86629z4/JuEij7bwof4Ec7Nc+9j/DfgWeNz5AAQPAJCCHjJC1gRJGrSAAJ/X/10iV+QSC2CgmAY/shNMh18hpAxcEuTlkDmyMizaBN5AU5pQbgAoAIYAdiARDIJGShoMSeQxWJFRp4cxwdeBjsONlkrjsTQ6ARvSkCaEj+gkTIg6cTLs3NhmIIIHWendyzREcarpFFJBk7mYTilvX0aPuuKjdDq0tZROq0WjM6Ejvjyjjrwx87gCKTRmHpvvLyAVlnTBRHIj0yU05Bm505C+sHEfcu30+pcoAx1zQHbS2MFXOu6wVkrjJ2l0wkH9KU0ceUQn7Q2uc3L3nPoYNj8ip524AU+BdEC1QyneD1RqLObISfKS4gHDlGeJFUyTZgp4a7IBigCtM/T6WuFoyDDY8lgoyKTGGztjBKSlhZqWQ7Z4CdLSQlFakC2ehbS0YIsO2eJJSNs91GWj141Rl1UD5bxaJ49MgcqmtYiUzJ2L4rlz/tHQa8mRhkyHjfuBLDu9/lPKICd5HxhLMvsZ0flRQhzJBKAhf4irAiKEbaruhDCQE1KrDO0LmjsXm+bO+UtDryJ3GjKxP3A/oCtD7P03SJXc7RekRgQAYoAWxCXXGoEY4ATiiotU4D5ox5qmLCZw2ceZpxNf1W141usmAJD7RO/XO4hjwL5cedhoT84LX+UOMCu7GA7QX37Kk/bYuqtHQHsy2n7OFXBLa9WhyscvAnGs9ozYEsxRf87Mxm3FKYWPiyjd/d7peoekWgb2j//py51391nW3IoUXC377AfbJKxVYgBMbMPDbKX4y2H83DKdHy7F+qFQb20L5Nm+hx/Ut7PNEviUcmc2YoB3FrdniRGJi9OHSj5Pd4d7pt4uqZaJJzLOvZQ7t/ZT1kxHaj50xmDbhHWaI8AdoIfHXwZ6K1uQq1cPREr6Vj6Z7vsIr2osSx5dVjU6487j9hjTduP2JC6i9MjRZuu9NtUydJCXY3zVvig/GSnQdWOwTQLN5osL8KQ9jcaa4tQez29CO5EIamI/x7UHxxrXZjwSF/J0LSGgXHvsXis4xbZR8snSvk7474vX+QUPZxOTBBdjX8a1BYfAtad66hjFkcws6VAl8Iuxe23RlCkiqPde+TkMTzlOAAG68Hqx6cZAyHPJX1rtAoBPvxwjAH/k/vPN5uefzJorDUKGAhCk7v7LAJlhUeyvl7uB/CCaYVCaEfjA5D+48Y5lGvYdj5V9KFk9l6jcwWip6JYumbPjjHnGsjp58OMFK5kFPzcSUMY71OUwN/+yOj6y3AcvV5zl1CflL/sy98o2qRx/0fAObsL/j7jefYpoKPXinOv8PLcZL1/5eu7w5VSJcyrFPfVS8HI42lh7hvT4SIW1ZvqY02TfZc5sceQG4UPVry+jRS5e9K29zL7IkmpteFBt0qA9irCg2RoYb6YMQMBALWXeSAKgCKXjUAlIewyTZAA8Apws8h4Jip7LRldmUSs702p1X0bjN1p011kuJEmWI1WMKNHS6TJjwjTJ0+UmSQGJJ5x8pUQRjFZwLAjxy9wX8zRWF+bNQqkyh+ECRtwlCR+EdH0lrDDxC0dHlEfrjtx7GytNDHiiJsGo05w1e4WjrV3xxYy6p0tmxzgBWbqRaHyyMEvIiORUUYxtoUT1elpBX0OHcsa3jge+xSo+kwmM+AFiLIEIAAAA) format('woff2'); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; } @font-face { font-family: Roboto; font-style: italic; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: Roboto; font-style: italic; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,d09GMgABAAAAADGMAA4AAAAAWyAAADEzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbmWQchV4GYACDIBEMCv886AILhAoAATYCJAOIEAQgBYMKByAbZ0wT7jBjHICxQe4g+S8SbPeQiQpRInToLKePPxGOhTMcUcL4M/miSRWxMQ1YOUKSWZ7/z7+e/7mrdp3u+0Bm/MjoDGRGpt8pxZHLvYbn7fbefze2G8ZKqC3aMhrEztjZK2etnazVJaeMJkVbQykpO+2tYW0Bl62mU0VMX3dfTn359t+MKSV06g8AV6TZHSVSI1PjNC6wZc8luVqHS8uBw/Hzu5fIXWkNH8JtcACzp/+/qe3bub47rGWvz9mHSGnIPlQuOlILR8vZpqKo3tw3Y8+bN+MwtkFCjrLPQSOTJBFsESXSmJRyaS1xN3tJ0VDFXKVYNOSip4OOugw/xgp/7TP3oeLulUYIYjlSvjK53y+tgxrbOz0opcYAAuIoRA5NXr/2b3etYBjuX453h6HY4CBIiyMoShQoSRIoRQooXTooSxYoRx6oVQfMqB8gCAMcBzgJBJQaYp6YY6y3De62tzewABsf1gr2BxsfdcrDD2x8fDk0AGwEH/eI4ADBjTIIAqjxuRNbN5CoJlyv4AB3NEWIJ6fzFBJSCeVkQbIsWYW8g1BLdCS6k1WIvsRQYjaxlnieOElWIy4QV8nRJAyaM8EYUj6plpxIGsBaN8nppBUTiSpkweVlyTumqyg1BRUBEmvSPxkEhe0/wQFHTzxmgCRRdf0p1slilsyuk3XnNd27nKl2+Vd56VTXBiD3FcgXykTj23mfhDT6x/WAzEsfBtKhp+0j438AFan7oDkeUyp53luqM+9buYIj6jSF8LFCe9jPiUS+CrcgfFg/kkP+zIVPlXtZavZfmTrxAGUV4fC/cnKXK5nPyyyLqA7rdG91sQovZDHT6v4+TmPO5E0asLBzNQv5gA6Ql1iR9+XNcT5IXZZSQos/kVMpyFnASZjJzdgih6cJZGMaEQ0TaO1qC7JqXmfl+n2LDmTZZfVCRL2GzTfPTsi9/VVy2Bd1RN5QW5Cj5q3gVk9jw0knlbSQsMkeEp6vBEA4NCMrdYdPNkTpwAdtA+pCxR7gFMbk+uHtfxbYyuV7WQuaEdMgVxyIZbQ/M7efkbd/wdmdeWs5xafyfPwJxAJIOyxjVp/acq51+Ku0eoBPeC9L4avD8lXN9boWyIzjLLHy81104RBQ0XBssMlmW2y13Q677bGXIiUqVB1w0CF69BkwZsqMOSvWbNlx4KRCpWo1Ro254qpxE6657oabbrntgSkPPTJt1rIVL6x66533Pvjok+9++OmX3yClTMNRIUgV2wHCZgmDOJG2AzPC2DK5DbGicPhBiSCtPKOT13Q30IMjYA6W1a2ywiav2GaVwybzfFmVoFbWkzEWK1fgKozDBFwznuWZ5zAH87AAi8ZSXluGFXgBq/AO3sMH+AifjM955Qt8hW/G96z6MQLZ5VJ7f5thrDEk5Tg8pUxRyRLVvHEgs2YhcQPgybcuTHKaShJcplmFzy7jjh3Ois1mSTGUnnxZOQGHTpA61uLIAhccAgJAg9eKYcHYZQQKeUc5wWN4AjPwtLEIAiaqpS6fTSerdAF6cAQsSb3M02EFpkqCaqgxlrJqGVbgBawaPzH9gt+NqXTyhi7owRGwhDxYgmVYgRewOndEnwBru9hhITD35TvAe/gAH+FTYzxmUrGhCmqhntyENxzwGJ7ADDxtTGVAmjGYVDdPoqMpZIfqnZXvAR/gI3yaPLIuo6zznl2eQ+hZoZ4vXNwQo593o/AVKGlhhIGSBfTSjNxBUOqPQ6tMs9aEXP6x9IrNrcCDaZCeS7JyUV3ugyrDA+mjg/aEGEGEJwOOZRCTYdhzRzbYAmebPciUHPTztegQowcmyaDpGqYsSLFismybrmPP0XrZTTepUGuz+jurYNSq7d76xNJ3v9nBKOpHERRBCZDgYJiNTMwmxrKZQVsYngKj2M6odjBhuxm0hwlSYnTKjEKFiVNlovYzpgOM5iAToMUItBmRjhJyD0mAk2ZKmhNDLFyiq/U4QOZgbA6MzFEx3AZiWElEFZRE0uKW1aolJECCp6bQmGsw1yfHcsNteA9Mgx57imJ2a0rzzCKCpaZClq0ieVuM884nKKUxsp9tIlgiC1kpQSxiwthKEFFFICmMHDGMghJBLoXZC4bZpxj4IQXJKIQcFEAqMomEeqAjpCBmiBCXQizBoKOMxsbF45eABEmKfnOSwuQSw+QVQ2XKCSOKLBREFgqmBF2GEgYkKAxLxJCMVCCmV0EUEXGs89k3eCS1sW5zdFcMwAAMuOlglIc/kXsMpP/POnsCuY/38XIB5RTWVm9/fEDYMcB7PNfNHwx8zgSDkSdzg8tPJ3OfQFGoUoN2PGddRP6kadcBVCHe6r5a0lD4Nj9bbKNv/7O6NHhztxlgEDO6lRWY2T0MZ1rc+0hjYUAhFU8ERORnwFTTFmuDyYhHgGREJAAg3Q9HpvdtEuoT+rP4EoK/wPPfwI7/gPzvLsYjIiFzcTce1+IeUJTQTt9VhOlYKdQNgrWNMRnWPz2dMO1ohcBFf/z1z38IwGcKQgyIk4SpRnPOeRKECBMhSqyzdA1BmEo4uYJbDJXLhyoO1gq8HIE9TCmKXj26ncRzSp/T+vFholEMiBYi1BlnDRoybAQEFcO484fxFwqDEbQGsGiEAqJpHnfBejq40AqF6yZCyhRHATvhRO878ZfbUqjeWspCQ60wpTo4zESbYQKCC0bNrUJ4YL1+7QbqQnp4fo+nzzQfn6XnAlcC7gK4COAO9zDWARDI3w38Ax65qx5AGnwLQN9y8UiThuTAVKchSDTDVe6PqztSg0cCHC9eg249LrjqjhXv/Yc7y3yMjKvjyXh6ESZ9JH2s9GnS4tJS0rLSG6V3S6tIaxZCC93bnSz73////89/cDxpDU7o0euicZNe+FA7y0zZOqdKi0pLbvUuaeV5V75liUwuE8olwHTUlLnZRuVw6O/EX/7/+39bMJfFX5LkuQTxYkQadw4Unn9/nvysBHbpBdW1t1R7W1vmE5Xvby+aZNT9ve0XnyzFY0/MeGpWqjTPPDdn3oJF6TL2vK+JTFk+++Krb77L9gOEIcHy34kA1QAw9gD4F3DCC4Fzb+uAvg4YfwSwVGo0Wx/CQ2AUowEbRLBQC5cqH3H2B3Rs80LAWiiLqaRi80HAKlijMPt0XGURP0cBAJspRFHokF1BLLBFI5DXrL9FyFuaKmFW+SjEJdHGT5jEvo/ZBL7rFnjILzyWll2tkQYWJenZ1WM1TnpCTpMG9JT/wfyJtRvv6XZEooquJm8nOdqrqbrSOgOjga2v3BZOzHjFChcYsK25VGaG87jpwORWWE7g95tVGgM/IReSV06lNLMgickRjRQtMmX648w5sc+nd0vC+5lxhRjLPjtLjszdi0+0xikYjDG94I4pgIkWHj0W1esh2UTHmEUuSC6UqelnGn5uOtXI1kEwvPbkgz8fOzOPTFdc8pRywVOnQaWAkdbOeOhiPUEHTAzuSGyS6IStZUaK4yJtKzRk4mVOGkPXLCcJYx5UsZXDLFKngaK1LrTPupjPipztRt6YCo9oUZ4jdLlKNc8dY5YzpECflyvHPPnhwC8zMeo1tryYQMeICx4GdviUlen9o2b6ipKBZ7lpemuknwZWDzTH/T4ZkgqXPXSrqjRG466WDKVd8NJOK+1ch2k4c+Gbj80j0521CgTLN7PfPXxq1EhvTaw2OeMa1XegWg6kxMdxJM/NZWs825J14iK1nKioS63WHES5S1Oh1D3VnVqmfJJelgXDTPBqEOQo61oV98mszcc1xkJe4bdCYJZIkx+fUpDw8GlmCrahmd43nUgIkuURGZYWkigyxwtts5aujBXLBAlpcVQZ21srAaNd1f8ZL5jMdS5+LW4cpVMsJHke8WWMnOKTFHI9lU2IVZuHcj1Q25N997duK5lRxiY5vGaVbxxzHRx6dlDCpZ5r+nWSrAwkK4NUMny6quLlvjPTM6fMaGnf2e7d+TzpkWRdEGzBucwESjkaSrg6DBN+eepbK7SSqaLGLBOV476CgX4/6dHDmgdSESz357kkLaGKnrJFtqpk/RzlZYSybs76cCA0SV0wHL4GCtiOnvvnk+GFXppzmyEQcPAbUgFmNK8qFLMvlAw3ye1R0MQzLahq4UuyVXnQCaSj7YcHN0M7ZLPjH9Xmcjjwo73XK9ZyeT3zza5svCUQOMoSuHxRRdqAuJhNXiITxGqCZrqxQnP7g1vg3NuOVuuvV8KAZ1+HyFpKqWWiRvjwLpatpEOQYd4s4TSTF1uOBnLarcE21slPtxRzAk2PE0sDzxyG6SloTmPTDoQ+BNccj9Am9tpSEgiR0pKZYa6yYZpRamENGngQjnrbrmEccxdTey86pVVUq6/Ap7nRHRWP7dKduCF784Em3IVfd84XXArItTWw1d7NbnlFNV2O9vWOHXMNL/DUXIAhcM8hvaDMfNNrkSknA95fi2lW2d8dtcv2V5Qe3W4TFGC8KHapIkV/fN4Z7EhIEEr22T86Ndeko1LTRTKyDASL+wwn75Aod3r8z8fO5Uema59IaIy+ofn39yIWb6XVOZdVPdQKQ65j7TCIdQqZWi7VNYxvldNJlQZ0JQT8HRjRmnV9XGjyeMM7gJQ9yZrfwLQd8GxT4ysZawcEoJDk6PRpjDVBSnTnl8TZO0efnba6CFjz5N4Lu/o4pnpgJsYYlKGS/vmdtj36YiiB3aCEqeOn5QL0L+81UnhdvCoovhKjtao36jh1GMZr0JjAeregp//Q/N4C8JlhzlHeE91DpYqQEGVg5aoy7lxjdWUP0c5YjYEgWW/Mp2qv7jdnKccNze2NVb5QpURarH9OIKE9idBRRwYjy4HkShZWqdkSHmhnUjFBdqGNOzDr7ClOg/PoOOVZ9YU/ta1OkXlOZ0g8PNAsI8OalT6u2ikutT3apm1mTNT7NtLAKaQ0ZUHJctsT6AqGAgGKoXwRYWFthZx1+YfxahuQUcsVnRqc+0ZEj6hE+miVbZPsv58RdJmdS5U8Eq+r3OpQJ4MMkCY7jPk5Mr0lnQVyTW2goz+Lqnhp1z58wxS0rIncwuW9lYgZjDHBfcmhRxsJZJhZcfwjDfxBT11lN+W5czM6h4LZOboDru7nYhnOKmuLi5oyZ1dOtFiWu3OLFxSvbTvKNg+LbeV5pJnluuVr3fcTU8h4Qz9SRiRmu9Ah2GvQp6d0Cmca12b+ohqIb0Y91kowe+loFyQXfF6C54/lMFi0X/z52Jl79OlvCb6ZqimivF/1+9yAgLiKsrXqbJria/OtE0WBVt7MWH64o+S9bK28cVkKP9fOBF59kg/VVe0QTdaOJk+XVz8vwr8ARTZyJrWUq8hLaR3GWbxb3BW7O6i4IGPZ2EHbvDWi/QN/uAWDKPJpkVzkjuLiile0XGwQaiptNr1rujl5iUirRsPTvEfbqd5cHcjtXjwQHpK+S2nJGxQxX10kLq+OiL/dcXn/0n1qFuXtTddf/O7LhaTmpdkqSheK24dPfaMaexDnuBdM3d7jttkU2JJlovQoom8yT3RJDtj7in6l1HQXhTFLAptK892ojBLnzCwip5V+Sb8Nw7ybZ2tTvLLbox2tiVJ1lDyCUeyYlXOUy4/9l7jDdx7ceRfRPUd/x7dfiFhUBOq2shM+JJfWlRcoVnuau5pqjMH47jrK2I4a1MdZi5K0UWaLqXcoRhErGD4tfOLVzUSeAXE/Ha97CXDMQx8mrz7czExQoQQmDMRZFnFz+NEIrJ8UlFMrofJGKzat17Orm4FyKTmQdLi5aFr9FTcNN8CWdlJJ4GWUtMJ2a/bXT66dqdnhJ4eLTzB67MyQMY4Cx/vouLYcltz69zIXZ6Sc8sywCsxyC+R4sxchSk4jAQGnC3gOvRc9bxJ772LUe0irmNdP8HnnlkAmWfwu9jGZVXST/OFGUS3bnIJGunjNgcx5O53TQbm3UqoQ5Zh3rav2BI2qe5A1gtEFswTPc2T1Pli8tOvqTpexfYXhYvFtCzbQ/QG4zQtBu7i34eYxgOeNIQ97gCeykrXC31MjFk8g6JAJHRDYUd1MKRU6LyFkxaj9eHdYYfuQA+oAomUBZnbHgPG3DNK7QpMMMP6alxxcrvpVVlVYWrUikvk/ofxDJJtdcbyo8vhvpRU7Yy3nWceZ7jsfp37ei3fL/kp0+QV2seLJlj4Jf5z195dE0kcpTQ8f8oQ3PineNFsiWfiBceE0sdiz1g0LhMXJ1ACSpX0Myz8vXK2K4ErrXLo7wpE5XyR7sUmk7SVlkE9JDq0Jg/GwMxVIT12NRPntxES8ASOtvyMWRcKiLmKcE61goPtwPM5E0/GjBnR3p5iQDAlH1D0OQ03o4UExeYKPQXmdxDj8YVpuf28CioDFHcREvAYt+1TPgXic8WFndagFXT2iyxoR9GdqQ7c/oYxpX1x19gl6u2oD7QTG4O2ioCNbDXRSiIHU5kcTTSgdnuwkxpO6buQXu/yItU0Xrj4h/q+qq/bLdd3AnoxJNAKX59oN0rCyEEZbT18MO5nhF5dHRE+J5kruvZWevsYUbydTc01zbiQQ8cg+4p1o8KwYpOpLr/Tx0Z7jRuIxtaFzkVEE+PuOr4q77TZuawjvCnE9dKJaAVld2c9n+sDWGkOJYCsYrCK/DB/guq8PKnC5htWYrhU6gzlTLYEomhG00SgQCtxlV651VMGPXa9iW8xOOJosMysS5AK2NtGzpXqzjG8MvOjbb6712gcASdZLPyRfIles/JRg+rpF8FlqRrx8BjTdBX+hyx8n9MT1gBrYFdusSJBvAo84Z9CZP8S3UI+ks+7TdkX6zqe4QTTwjfAK0yfpyL7ao0vdTjVPo0eCw7i/Fwg5uO5pmRdbZeghQBdHOk9IxXffWT8P7Afo7jeTM6ROSlyWBgPHhXJFyS7O7e2sfNoxbrYHSkYnG9g5fYCWln17ISAV60cP7jHamBdu3Lezvz9yAYijXREgtT+bFk4L4ab6wiBYn8kK6QPM08y5ETiAJp/S+0meOR0x+1w3uXQTQwTGRN9PoCE0+5zI6wd4bkRmEEpAHVXUREp4UmoiygZgb9HLMfHyURXTARXTVMHwXejF1R33x3lJN66BJ0/P3nso3qnCzTumlgD74SUa6w77uYjAJOqBUzP4gQ5CRFSKF0xAvecEqujpUb1hSBcGbo8Fqvw+gdp140jiveHLjAw+CoZN0QbT1GTOU0Gpa/gT6M4y4yLRW7pPM7Q8S0W5wBl2hMjbEA5DE7OdVS7G6iAS132OWU222VLmbAV0Wg7uDDt4dede0R8iFSPgcOoBkn9mb5iSw17bfqIv4+Ka1WtoBM3MM3opsVVDqcqGe/WbiA70s/jF86gH3XjMSjGhBkaUB6EYeLKBHk8NicwJgHHoZDVhnQzF3TvLGXFhVTEthOLlm+YM/WF1IdgdnKhn2GJgCoNhY5z+DDWJVpDx/klyCupBVz4Tb2K+EvXqYanRO/DyAjUbHiL26tQPW9QWsNeBqIuZoGrfNjcUg+udoJf7s+JO7nUGhIQ9f6SHHkeLFe29G73uJji4TmGrRIOc+6GtEsflwI57+ZaYNP93tFihEoxdNwHUKmnBTif9nEy0YwMEoqgOlmG2yAMmBzKtTwN285erPNiGzt6gNzP5Q21RXi7WwuXfDzFqP05eZygMz813AP0PgtbQ35pmkNGVj4VALp9aQ26oMJrhJcFsLNUjVZ6sLoFLd8aK8XxLCp1w2oe1ktOOPUVRf78sU4WJ/ccknheeAO2ow1Q8NNtq+TwQa61Suwen6y+LW3nzxrFLmHBbsfrN+WSnp/2nDuA6QzFfnH3pF0rqT1XnbNxFEZk3QOlurNHVmGs7w3gtbDxv8JDY88hWoCowxesEz2fH6X2syS8+Lhucz5ACGGNrVhbH222pm0HmmSJGDD3sWEoYkqtmgITeJEYQzcffLw63BgA91uSWeU3iAj4duxbPfYcvRKYUQ2aEgk5ANAF3E70HhMVh2s4FETiC+yO7/rdQOf4o/kz+dC6qwF2t2d1twFMQBfrAKa6S8CWyrtyBsujdsIxNcw87Cx5sJMoty56hJDKqT/aWIHAAO+FugyYkalPOnItE3TmT++5ANTjFhJs84mr+Lyie5UdToMO7qOspHNAH87GphKh3pApCuG4ZfxOz5iR2HX1YZd4bomQVlMSjYcIfiU1Mdg525MqJh0XwHi7GX1VbV6IGgOiR0IbxF0keGPEPuorBcwA33BgYBkrL7hNB+UKUvMX5cgtdQHefU0eHKRHcfC6MRh0n2IlgbeOD8+aLwpOIGVse+9ScI2m+/i5g19ZL1NoO5ngOyFryBL40bhlr/K50Xm6HwvW2aGYXMjVP2IQ4bzu7CogekE71pWn6nmtwfimWcmkW3GFgwsnGbiaE/cBX4yPV3U6sCbGsDZlAD9BXKdIX5L1LI1nI3eFkE3OxAj9WNl2C0tC9inQF1gtMDT9aMVuIRnA/xDf/r3HARtlVWdOLYRnMf37HvMKa3Pz+88E6DVA1WsXMFIhOq0xA1gAo8QymJ7MD/37SE9DPBHeSg7/ha/BxavZ1olzL41G3UC52JynI/7iYOdmManGg1zuWMF4xVTT0UqLgA+PpXi7YGcIvkS3/BONBt4GJh8G43ux8sATeL7OvUDJ5d4r3zHvSJsBLDii8UslMYMQm5aUiWQAU70YIHR/W6z5YuS6V/YEcWTT4wT0DS8Fuc/0m8HEjgJyWU5wEM+GZFHoQp/S6Qeke/bViSYL/XXRB3zeXPCwTLASHjRPihwEpqb5SBg0nAaMp9hWGEHtYfmt2RaJOC5jheZSUxzILGrQllI/di3Z7xsyjpDwZpITMMCuzenNQBX6SJ36ckvIUHADrv5x8sB3Pa2WH8a6AcxfRSY0uid2fjxP3AHLLwQkRjdlL61p4XcQleeS2JWQNbk0XcQPvDNjSlNK+bVXxidmD+1CRr7h6eEVvYhK4Tr17PLf5fo294LDTFkHz9JvgZa2sRC1evGq/e+QXibonYuVgc8vqINMqc0ikgsvRORsIqF95zZwB+SZA+ZYYyDl6NlCkYphplTkCpMcGqc9PNTyMbXxYD36VR4uXRwPZ/if5NzfcAnx/yc2lWa0oH/bxiKnkLtGLyyOAakl2dgx0hPYw31HAkA9IjknFN0z8YTsaHmM0HhXBGQhPMe/nWMFqq30GG59lgi6+H9WVdMTaHRwyE+W05JGvJURjo8gxf31cG3MA8P0PJBUMohrUM4u7LODXY44VeVX7onYU2mPyULW5Gfmg+jTTD+BFkjOsCRVx7AQMj9S2aw4+WDocyjz6hV6pzq4p+PoiMwd1oBszHe0A+gQlO6NcbOiR8KUtTkiDEBqWAcykOM155DspsVg/ck7w2sNntoIWdkhCzjAqQ6cWCOe38oWwfL86L1hLiGq2/KxaUod8scZ0i0/gE+caWpRhzeszG2rJ8+nJWCs6N0UawNQIahSzUVZx6q0UdBxllHgd1XB5GAA5t7hYa92OGjo4JBAX2AoiKBpdbaL5rawEsUY3O2+nRrjbkClU/hM6hobSnQV850Tz5yi7u4C5lAgvH3czNgobRk5Z6yJbqZrrJG8L/biBPwYn3JStPANcChtQIuqrkMzhOKWk8JA7VuppehlFiA9wsHzvWh90AoU2WnxQLanFF6OR78x7QIQzkFd9FlXA4pvss2Fj/PBxEz1mTgnWgiJOkdxwfOYA4IPFfuqYSv/G7LvXdzC6HNAgdKgDYu4qtAfDnMrm46lQXZ0lUKJ7N0msivZlWEqCkffx7k0FxvD8pWHQ+Ckv/lCIrB9CCioP4CY4vf5w09L/KljsZ7YCPhDVVBWOzCi4iDxhvo24acWp2+gEqrrL4YVf7Q+bMLdlZ9RjrrAhXtgz+vZAxDgtwD7CBbYjtzpSiQifOqYCRN1VxTKLjg+iSlR0YxwrN2LRPNHztb8p1SgDXiqw/8MoE2LXlf17m5eH0uHlApvvtFJGWwX1XfFznQCCBjksMscds8EqHL0uMEKJdkbUyKgcd5SDjc4LD4BDu0Q5zVnEG8kx2DByi3Ym85laT5oAJzKtYMhHp8COjzMvDqj2RrUoqNKWsL+gDqVjI9NgfanxAHKKlz7WFnvq+l1QUkwXqoD8ecIFfIwWO/vmOY/bOjhzrDCgwQtWorAyB456dhnKxIYfgW2ozILU61ZLMofu/LL1AvG44PIaJGMERtYzuFnyw4pvTYnnCPnfBlphE7w5hMpOA2ji43EUOkCN7W/IujSHhK22ooPba6rwQXj3iLJxo0CsCz4fQ9X9wC7kmIcrLLACa6fU5PFXRPPHAhu2CBEMjWR86OVqLA0/6FdNTT5Wd0E0/4I8HtzyjU8eRdWodIp9NmSIH3ruyBaczhFTDewS3qeRlCJo5L/Qu0DbH1G3AxdkBVWy6ZoqfeDgCSBUojIs9UClhIh2ibrtKiFaqPTg1m0URRuLwfuTG7KenVpLFLvSV7KjZPa83P9wFTQyRTlbJjavf5dGuIup6TAFypYsUazFdke1GGr/unPgZbmzePlh0cJt5sy9EpWSIjlg1r9uT8k7dpfEbRM9ZkYxUaBwmrz2ldSiipmju3jofa1tFJn30uOnHDwNyHlyKlKfoLYUsz5tD+ijFzNXzheDkF/T2luZUvNSdy7bB2rSipUNpL5CbexMqfK2wJo9Be/YneJ3THUF0ouJjMLH5LVvJW7vcvHxAob3KfTGy9M5MA6L5g7qHD6cgcm1htZgAicuT+aicMzP3tpMY/+hI97HWB6gr6uFUip4Xvyr8fY6J9QjL9A5P3kNrCY5w9pgcecuIJg2OXJ8jfwqX+F1+JrCYXouNUCOEnl3MDVccNs8f9tc8tri62WdvtwUZ1SBv/KfvkjG8kJqwZljEvc5lUc9r2OSta8law7DwM2ST8VvNYjX1kr9Eb0h9PUCvg1dmCTyhgDBxyXKHR1DVU0CiWt/KYrXgoNqAUNp59BVlBFXm+FfUJ+2xoJsxS6zlvYKDa3NjQ8q6Yvio2GYGd5bEVDUXbzWimrNKjARc40ILsuP37kQzAjSu1Mf7YdC0cO4wlmBaHqw7q26SD8Uhh7FFcwA2RTx2rInc3d+CMWqSDarCsWo7FM/p6S+Vyhmj2SzqhqLW7kzAUh0UpPIAP9eoaRMDKR8HQAaH8+wzt9z8vSktdN71t6YhdPo4zLlaj/AWxyMS9I8CsxgyV47V5Im1cA3QNDaeMPHYM5r+pm7nq4+tBaiX1p3uEL09lx4G80tUa/0E+NSymJQOhwIZXhTTJz8GebaUrSQ14Sq3a0KQuV0N/39otBETbRnt1AxRdeRG74F0Fts6HvrOc/PdTRso9fNfxgS2D40Z28+TTNLevlgaykqRMcf0VvJLpyR209qYR6qbsSX5AO8haaLDXSE8YWS/+hsgoGRjQbWQZA9f09M6DYinINDyODZQCznnNDN//AibgQZPOdH2G4Qurro5nD9EjoFJUbzbAVHha8vuhwdHwaUASTSfK2BsPNIz84y2CciGjnjggdj2gJA2lYRgpEFFmi140UNheJ/Mj4ZRqPUUnLMXltlWpxm1BFbDYl8h6OY16FwfQew71TEgAIxRLJhEwi7q/GOe6H4+WJboQnhG8uuttcuoL7MvTtySJGnJifO3AyLw4aQ3sxpFPsyPTXx0fUQaGf/3T01EjsSsMc0m2RuCkA2rjSRELRFw8lE3kCO5EyjWEltZ2ZbcAg6lgT17ZoaqCQxH+hAd82serUD1lguUNISzhPOzwOMsTMooKHBEzrD+FLojrj1NR7QBSYXxnqa7NfdqWhhfNRpn9EeRSsLsGXRykWk3FmtrlmtLly0PEyttoko+FlOpEIOnKjW5oS4bnE1p+pxtT6oA2P92SpACe0pTYARMDsO50GMLo/9NFoYA4RCPQ2BOrTf72EyuStQ0r6W4l4fGReH5YXhnAnhFephW1EiLqA/MRWGw9IY/4pd6ooqaraH3GkeuTgrACS+gRc7NxwHYksqnlyy+RbyQBE2gHeuJZ2WGaCOqTSygwOyTsAMY33rqX6m1hMgaEv8cA+b+8eZoOeVPH4fWigIBK7wQPMU2K/G+vh3F/gHL6mpgDbtREmUhnn0BJVhyK8FL+BO1faiTsmngtfV1V4WM/tE0t0ChcD6qSu5qGGMVknQZrZMTpShPNQwTisjaDHb7o3rnyE76QQbQCOMG8TwIpkQPfT8daAp5IbQ3YBOO9XfrMHbzdk2PJgWTHNxCLGHLjA1kOVwGrBbP1/noW507hqjhTFwvjfEw9ZCtPTroe098x975BlDdycngF8gsFFwlsQ5r2pt4DWKV9QffHhQvHyfNrvHSCay3+ku2GQabYQzTgjCG0YauidHGOPt/wEJxtHGwFCwBYUax1RXjLzw6cQtA+cdcuHYqbPzzvHYLZQYldxcfuf/jhByFL3dcnj+YL06V+H4P+gnZbbNLdfAqwbHx/3myH2WubCrSAcZUgzldofrKQeh87g/GzbRhYqBFJ+3a/1bcAe8XmAMU5Jyx976FgkDRaUBgSme94ijDAA5lyqZ8fSIxLwwBO7zqUtHWWlhtwZ9ImE96jlFKyE5nvhMPZK+16+oRDlQjtz0YqgbnYJBuiqVPvqB0CPblWLprehbXLY/3FF/n7OarZJjFNn0iJ8J8sYyygULgQ4QjIRn7XdZtJ/hoCLY3k3OJR//e/rxPKBaUr0sI22QFyzwZVj2sQXKf58chP6w0UrG4ET7JRQPe+L0njKzWGHnSRoFNN/EWC9gA2tV9RT2ZGZFHOSVacF6XXWlrW+vg8iWQKotSc/GSvX03mNYR+2eOopTugvF2MMOKC9zeBt3BtNsRVpryXOpSdgwes5mT9ALsj7NZqSgKhQQgPg+le9KVPxux3lYntqtVTuzryxjMknZf2ViX1wHrgCNXme3M7IThrhYPI7/ROoCUFuwvi595pqI4k5P3e1bFzST+x9wtL+Pw02wacnEE9pu9ShNAQW3jyURrggTLdk19YT3GXnQGtrL/voWyr0ZFkO4KWm3dh1h766TpeSUXbbXB/0/1qJJthUb05PSHD8tnJSDTcxIDdEcwaHLopyWHPL1xBhsELnHOJP5Qvsa+n0UkzP7UR3qXsRGaIMHcOZF3BoveBxxK2wI+/NrcZnYyBOwuOF4qHzgJQ22TbM0QQV6UufMEqxX2LqVZa33CerBe2zl6/g/0SVq3WzQhDYQPYJl0eiChX5Mp174+pP0fQU5siHBkJycVw42LRlFwnMhW11PPZ3GYuHJOL0ZZgY7qj/WiewXmuiEdeELAvbHa6iNqwfDGDgSKOfYOf0ZnwqH8yx+CJSuXYfbtrtW9xjSwIUG57tjGbjLM2JDQjirguAmf5SDu7gi3K8lU+GONVcplv8FR0KdaUaetkBR8wOjGAa2n2yrxJhCdF/A3BsJbRPjbMyCQyyhdWKMjUVwkIvFAUc5BSNtU4d96lsVjHWByvIsNSAqzWHDbf7sDgtMyj+KQD0Wm2MPJeZ81GCD1dpAIC7McdPj5oiniaT1s7jrZgHjgbCbXlixSJZwch87ct0cwIm76gcXiGSzfPgMJ9kZgOS99EPKxcvXdPaL1mz84FHu2ZpZJVYC/MfqPWj4g3cIDbQy9fa3FsPbBB6zNfP0sQQUiVPJcXPJHNvUSsBy4xsQLNGp4KUCE67LH8v8w88Z2LWwJpikR9CmRqSlBWGOWIwMriFIMhzOo7d71349DYRiukUze4RiWw7QVMRfQJuSNTJNPutcYQO8d03+UrRQbKhIZhjQaGFfjtqpVahdYOMg6quZezc3yEHUumw833jcxmi8gG4SCQ645siJl8sBO8rurlbR/BZAdxMfiHALduyF2jBVVktEri5wVwBcQjKLNKtHovkPV12lFL7AAaD81SNRSNUtIoDhyAqev+Zq5d+YLT5erPXRYAv0h2e2OHEElqf5V21PDTNSuO3+hePQVF9AqOIntAn1YTqwI1Po7mK8lYl+qAMzN2iIKFQH7wqAi1BmnmY1LZr/SL4pkOJxg1hFGE3aSiX5UQ4ehnlQXepS12y2Cz0m4Mn0S2X4ip6eutgBLWGg0PlNZiQF9rqnt7v/JpRZoDvOi+U/l1wI1NPNVD/f+XgKRu+offio8nif3ka7dP3E1vKywuPZMP4Gu0ROOWGPk72qrZqCncE12+ud1/VP43A4sLWeOkK2F9ZoVKa6o7XUJJR4mlpJi2L3dJ/JtLxq/d/Z6Insjs7Tu3egGFcsFZMc5fQRULw7loKXnGDzweL1zDyastVbOMlrTXv16xfYj8Y9/7v5/MtJZVkHoJUWln9fJMVEpfP34WOJqSgYH9NTnQxDYWECzrUEkNwDoLqlKVHDTk2Lp/ESrBtdS0um/sUs50wNPaBvWDHeDx91sv43Kuqi5OgI3SC9fXC1yB7uN9lJ0FZ2ireysvdW1QMNvDFez1hxn3CSLQjWJwRm6PqpoDDMuzEhFmPGYQXhOBdCUo2urSLyRr6NsREwBGaGj55TU1dUPGhxyM2U/v5rqaaQpWexQ1FX1dE2VGGX4X5w6ZDBIVu/qDx8ID66ty0JxsNUHqVgl9BdMPdgBy0+o9rh6AkTtF8/bts2Iy/5AxZ2BHU7lSNAw+PATssDF3ZuEL0sXhEHbIKrhsXLhwPi//i85LqqEPX56P/qST5j/tsvAFyB/Q8AdtgKZohNBJEZAuZx3ez4f/6Fx0sl/xzWcDyo3lBOgCv1MBqVFJ4oFtKI8cZF04tZoT6gx2m57kmor1yDN8WAeZ3UNGpoa/k5MPiWWkzupcDzkWq6WcUeGBWlDNRVHjdUWXvZrLV2Zbq62Z6dB4GhDZ6QUQO9UKnz9FN6n35a70d+SADi/wG8kiQgEHovq7GGxhU2aNpZs3xKkZMYVp8T8/3coLAgVDmpb+3uNgoqvtRxkxFVl/Pd36Klf18dJolhdSkx33jctyDKJ2rmXWKYiMT8xMd9c9bfZSvu9Xdb0J9dSiQxbAgm5pf4BoUlW/vTvmXR7Ssr6ncvRZIYVu8S832J+5aCf6A3nvO0yLAZgAho8wBnQ+RxbLzwaTih8qhaxIwCH1B9HazxoK+nAS/qeqg/TS9yz864r2zM6dd8Y9iGsMsFyt3bQgQoT45nZmPNY31zzXhNN/fNiQD/PiyJ4UNsK7DEt1GCt3QbPDrNxn9AJQSxwnfoi1LoUOv7wMwGqCgkYCUKowiKamKaOvHTULJuDSmYGNM63nITALbrLgLo8J7cxf5k6q7Np2pu7dQcZmFea7NRMfPnaQIqp9XkGwTW9atHv4bnQP3Er1zntI2cLpuyqrfYejg1A71zHtw4ylp4Cm0A3CKf2tx9bqNmrCyewpE5vkS5B5XJHlnomFgaXTSyx8w6q3EUmxufrviRO16vYR2jYLxaQ3yzMj+tPupZbcU1oQOYjT9DbKwdAthATgL9ip0i6K/TXxF/z06m9xXbX/j8FAs9HO6f6xpVoN+3Owy7JAM9YJwNgtg8n3j67+XRyudFFVjP2smIyItFJyqRaetWJvwHj5oN6Z3imO2vdmBdh8LdWZ13NgAzmtrCi8us173f1njX/O1pHw7PlTajlVdzbgNE/7DMnBkpVADqK+s/NIxv6K+t9pF11Vqgz1qvcRlWe+0GgPoIYOPsZkNqAxwbSstBa76xwIwYnS1TWXP8arNG60YCWS1cNhpnAn2t2uMiTxLvjT1/8QTnRftibGpWmobvY7kyVn9NKM2/5kDG4oVxaF0DAePSUw79mNjvlNv/d5LYHgB88U8sBQD4UZn95pfS3ymywT4EhgwDUMDu8QcaAEdncOyf/1kB/IDjHqpROXeO94/PJ3UcAY2RZqLvMmtP+mvQcM9SKXed45Rj41wKpiu/DmRQhSkYCsSGkL3zQAoi0hvwE0RgD+AhGAKhDtSrldZrctWbmvnHkwbj+ydKZfZr2WFAc4nnZD+nukSELhmqHULSgtYyF7WKKS3mtRlKv0javtptkrqKlrOIfk9PLbfvUukWm7pL+2Lz6l+atzdG+0Ue9GntfTKvh1j+T2UXtqmJnrqMZ3aSRqDJ1rC7Paxtcdrt60hvpDVGhPrzxrWJtfXG9lqK4PxJms3bHpFqs8hURtBqjzzqEHqj09qmAIVRQqNN2c2bAtZziXMxY3MgLUm+Xcsq1TsySCZ3wfGxf5PmY+sy69x8XsXYvYZGreR738zs1PVkW8d1JhudvWzaStK2nsus9H18sNrbbRgL7MeCgBFlqrlZnlNiBlNLfcvEWPBsFrk4ewisQYObAOjfOOrnQO7vjiS15W1ezqS7gVK3kdoqcLqcfUfSbC7lTslcfaWwC2SxE6YzT5XIaCyITpud/4F6C1ADAFiXaNvEVFWF3qqQVWWpHBMGxh1lYyClo03DUqU8HDkNR9gsyvuxwK09mfayVx2lq61Yd7DQrfOzAGB/o4vteYkYP21NLL+1DzHCIAXbgQqKUAhukAVF0AjxIx3tyTcUCynAdXrrCHsK48w6hBV++/tJ4ShCsYVYUAbNYVgZZmHzohCkMNtfQmFHIVdGCPsyaAm3ijCLKTsKNQJau7SmaTkqr838aKmdz1JD6bMRCwLVoJAwK3gQwAnAgJ2DAAL2PCGwyQB4IMCuB9E4Aqb7roeIC984bj28jQolYaQP3F8GC5M0cAWKEsyHF2+hpO2yw86nIU0Hl4P582isJ4AbBanugn+bmaAK4UgPHXoIFs4pdwpuistVIFTq0dW78OfDrWu8dKusVKRC+EAF2AMKO++2j6p14/dVm5Qnkh8qkIrtT4yQCgvxQC4pDwq0XjAv29MeAiyXIa40oHwNWoyYKyVvgdrxD7Dw5dx8uTsCAAAA) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: Roboto; font-style: italic; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } @font-face { font-family: Roboto; font-style: italic; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } @font-face { font-family: Roboto; font-style: italic; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,d09GMgABAAAAAANUAA4AAAAABbwAAAMBAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANBEMCoI0ghgLEAABNgIkAxwEIAWDMgcgG5sECK4GbGM62A+KOMNGmZWUwcdhKI9l4Sh/WwYP/3af9w0W4ERa2bOg405uoSptTooGKkF8HniO5b+Iojvye4dReBbNtVHwcLQTG2gBzQfYOqjJ/XYU/jItwgxa4I3czM4Fj9LAAnlHz+dzgSO71Jqn2QML8H66dROj0qAFLYnRhtm0b89/erW/v8l/LA6we9gCizDBtQzSf4EtkcwDT6RtmgYEQXnDKGQslZyX/CkQSFgBAE4ERggEAgmwACwQgADMsONAJKVkFWEBgAJgwMz1NlLWec3G+jtZu+rXO1i7rx/sZi0AEwB5WVY28FUE1CORQAjvtSPftAwCQQjGAbTUfm4qwrvbNmDEf5pjR4JoxElAiYiMWjQyIAEy4EBGAA4UNKCgIMC7a5Cej2sCAA+SMEEyYA2AMQBWgCmQAObACrAAQAUAJCSDMEDmo7CztfXoRGu7SUeVdbvosOq6N6PHnZ2yf9l3eXPj/q2qXdkjBL+qrix1cYsqzItOvXfRPaMXkUvPeFWoxr7tZB8gfxIhMauBapmSUhO8d3O8wUt0MoI7UAxLzt0/zhCwJnVHrsPYXenm8suPeLYORWqn/3wwK6Qp+frDiYGvxHSXFzoXfpihfmlODl9oFbOqKa8nXbZgd6axNivh4JS8xEZKChij/nuDBPx/MrxQA/WBACCtK44947xa66g/k0YcALjxaesDuBuQP/7x/3bTwmQACVMkAAQYd/7HYBqK1H97hriqWIzlN7cD8Qu1mY6Ql7eR9v8qAcCY/apKqAgArEBCCmOEAExoJiOUENTgBAI3NSBhwSjIbLboV0Blo3PIiN06hxVFfmrr0WtMvzYtWg3SBPDjz58mVY8eLTrpNOm6NfKhidepk6ZAbgbym+oG6PoN0zXxUaBHgx6Demiy6Zq0GdIl3aB6ndo04r7WvSV0/Qa0Nd2+yKcNFCrSvh/6dNKO3xV33aBeEXxNZKTyQUaverfOR49+LZno1XUboBt4oSzpEiXLUSjZDgF8+JHBMIY0KQAA) format('woff2'); unicode-range: U+1F00-1FFF; } @font-face { font-family: Roboto; font-style: italic; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0370-03FF; } @font-face { font-family: Roboto; font-style: italic; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; } @font-face { font-family: Roboto; font-style: italic; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: Roboto; font-style: italic; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: Roboto; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } @font-face { font-family: Roboto; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } @font-face { font-family: Roboto; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,d09GMgABAAAAAALsAA4AAAAABWAAAAKbAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANBEMCoIYgXsLEAABNgIkAxwEIAWCdAcgG0AEAB6HcYyyEjO2Dy0eKLv4XvfsrGs+wIhEBOHOERRRTI2158fc/aln0WYmSJq8uTRSIgUyIVMqpfa/7uYHCqzWDuHREj0f5UuuL+ZAokTaYgiIs5sF5aUutjO7QhBlgMaYvCAIIqqoCggoq0+HjRlX70MGclDLyR3Z8fb0q/ectzCv30obmLesvO5hBhRhcp7kToaLpaRXpL0htKmb5C3rIgzUIwA1fnqrhHSbqXhA3v+sK1wRtcWuhdyg9E5tGXERkaAhroCGeNqCnJxAm6m1Sb58SICvFhXFWnVAAWQoYRjYADJUQQqIYm0uSZKkfpYv1sv21dm9b7kWbV6i3BQ2Z/sOf/hl+ezXH88LRz75pnLuq4/MO/Zx+eyHc3x9VDn3yfx9n1ILyusq3ps75y90fVZ657PJ2iXgF+odHbvzv7Lrm+uTsPR0WJqYcelN7180rHDDnbeWbrx0QHht49uXjCzffOsd5RsvGvHe4yF5o+Ej97/ZMP62+Z+3Wz/08CtZ/FezhpdvG/nb6PMhC9vNvHFx3Du9X47etewROuONg4L0v2eI+L9X7dt0evq+gNihfvWttiuWK4f8VmxWBM/+WK8b8F6Y9evfLf57r9SjuA2URBAobPm/Smni3y3+n1TqgQEACsl5awAI/5AetjNp65A+/38vDAUXaayPL4CMKHYkEFC0DlfIlbAMegyqlmGU2eSTO58TTHX2xLyWvlczc/wY7eDo5WxlYenKyMvNg9Go5MAatqis2Jty2oytLaPupFxOlsgFObsjM05dBxMHVwcMbeFma4xFh8jZxUr2e62Th09I7Bd96I2RI3gzYzqKcsHjqZzGjsamlojTwdmCy9bKFNm7IBcudRU5BU09BQ5eTm5coMaMAw==) format('woff2'); unicode-range: U+1F00-1FFF; } @font-face { font-family: Roboto; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0370-03FF; } @font-face { font-family: Roboto; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; } @font-face { font-family: Roboto; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: Roboto; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: Roboto; font-style: normal; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } @font-face { font-family: Roboto; font-style: normal; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } @font-face { font-family: Roboto; font-style: normal; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,d09GMgABAAAAAAMAAA4AAAAABWwAAAKuAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANBEMCoIYgXkLEAABNgIkAxwEIAWDAAcgG0oEAB6D426JQgSiDJGrY+EepR5ejwf4/fWd+/C1EBKYZDS7sRFxHTf9uCJn/m9Of4qsOwRQBbqEex0QSbKziM9Pj42dA85/tYTLU84Cj+f+PIAlq3AtV5GCrQWUqr11TNFedSEUjKs7rSju46fX7RWCSHFAeYQcQRBEKIqiAgIKlGZBdO5a3w4akEBWj6orkgSzThrq5iF0WjfiKGe7e/0dAHkwOR8nW+GblHR72hyEGmzEl02NcDPu9oBKt35NVVBcoyEuIJNhau72SE3EHkhapkdqCiZGhBhliQWUJVETSCQCNfr8o/boWoBjI3miLHqQC4ojH22AaUBxFAUpIBJlJeIVGIvLFI6PlFi4hGYVs0brZ4ZZlT0rbz1SLT+50xlW3X269vh2x+CpO/n7bw02ebvIys0wMkpteMHUIq4PGfxCRBdKjxXGaDRIc42rK+a/qgeebsfBvjGMiQ14cnJjW8fSe6fHlr2NIrgbeH2jS+k9X+md9WJP/5IvZ8LRg1cQ3gz+dJMePnr2/6ZSiy3c9rHc87Zj4tqOx0WLe1U0VR2OOEt9kq4gV/r/NBEyVbPvpL70poCoTunu3LVVZ4nW3xWV8gAKP5VqBMD10Pruq+7/52x5c4B8EQjkzs5oyJ/1JzxT0mgEACA3XjUZACFDut7UuAEqPZepikCuTcprJBVAcSJREzIBeaYSC4kSGAs2BJU5IFLcQjt+sxNAqr55kwOx947iBrvVCRYwpBuDQusVLFWyFCmCVcEwCg8JVsPPK1GwEjxesNZJv6dyHtID6dYP8UnUCvPAemHBGiA+jD6CVgilD8+tWyfSPRiYXwVJDNNkydPUzvrRmeBZvFdArqSTDSCJ3ALcvDp0JBHWjTK8pb0Qvx7N35CkXo0yFRq1qZAgVaJkYiA7H3AA) format('woff2'); unicode-range: U+1F00-1FFF; } @font-face { font-family: Roboto; font-style: normal; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0370-03FF; } @font-face { font-family: Roboto; font-style: normal; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,d09GMgABAAAAAA2QAA4AAAAAHpwAAA05AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjQbhlocNgZgAIEAEQwKpyCiAguCFgABNgIkA4QoBCAFgwAHIBvzGSMD9YOxSif4qwPz0HjxoHC9VRNbrMu/12kLLcb/5dFJkAyh0DCYQABqQVD7hmAGzfIo/4k/8899o8ALZ4VCytZgim8X1vbXSKk3P7+/99yvLGmCnpXn1FfyhvB+f5FagPgStyR8kP87bfntzf9vCnc4PA/hUOgM9tZ3O7ENQqEEaozVJgy1CWz36yYeaBRQZEFQSKmFVAH8X01TKv3d/p/dz00uqGnOCfsA5ILCOgsLIdKmyIp0bqWzlFZZCAmvpUEHN4DDYAAgAZDElqjeg6N0eSgukSleVCbzvyIQgwsAAGlsmHB+SKQIJMsvQgyAA+BAAALYpKlzDK29MyjOWJmF4grDGCgeV5WHIrQ9ZR7cEJdwAIAABsDgMwRaIwD5JAVwBn0qhE3bhzqZED5wH9ChbwNV0I/Gbp7Y8MvXnHL8+34hgHxO8x7nho4BIfruwvrFlXJejpEXr95QP5TKdnycP82rfo+/2cIHccrW0TMwMjEzb9GyVes2IdH/CXRWWWoABZK/QyHXnNr4t92jdch8kcaXGAOXvZup6l10nhMX0N8CsFLyssunnZMSac8IgwZAgqUFmUGzUj8AiaSwIQA3qBLkFg5fAuVllk8PQATTamBesoC+kDLBQjVbbxgUSZJkSXanLIgvQOsTs6yhL9IgrpAAUB3Pzx6vAjA6hXjSSo4rD6lWA2NtUJnQk/6SwASgu6ozQBLoOwDgZQWMJCSBGZHt8OQQOEffex8JDxgkMfISH/kSimD/c/9L//ukv/R/gAzyEC/5UAsN+b/3v/C/Kl+UzgQ0M/eZw//1erjoYYUbC+5fXXwxAzuriHEqlgb9H270mw0AZLrcCoBxDOCVAdEVYPEAAHG3XLofczKvYcmEVkXI0Pi76yaAs3tnYQ7udZFZMXmincQeacG0eexkHk5jx4xx0drpYq2EkW487uIKpW4VLtxFl9sZ7nGRueLdMWN8/HD925L4kb8r3mXjiLfHOqKcTmOI0d3wjPEifTtO2xh7/MTL67a8mxebU+qlW/MeXmjWNPXalne+KSZesOf/T/Ey5bYt7y7h2OXEPHshwxnRh1axnsJ0s9ioQLWFS8XqjowxcmB+iMA4jGKGxnuyiQi0YFvWD9DVVp1Mm89Tu0hTA40TfCidkFVhx2b0D/DZ/h6wUlKuFXHcPJ0XL4JzRczTkvE2YTqO3LS+9k/0aSU6zBKp0PodOK0dPYA0pTRZlaUcLk8X628YDcOg9Uo1i63iArYw58MJ97UvQCAgRvUGt134eMzpzPt+OuaJ4Btax4S7MlXeW5ftLl0o2RKrSgVqt0q7yKD0fhTmvVIthpIjLNPUhm0HNKspGd+lN273ov6JSROz8bmfV2hK78GgOqRwzjYMAcNqaJWgbJw1D+657xwJbNHsBuZl1kiO7ZB5msExOrcIeXk7Z9FQreio2YzPnL3VN3FIK4RL4osobCD9ggo3q7E0cnxZ31HbKVAa835F+/XOWPzl0xj8BWM0hX9+/Wc6SrFyL/NsC4TyTq4x/L09+tYPGGjtZqI5MlC+SJPiwxrjsHdb+Thl2Epcd/+vp9ug4uDZVju3bG8EYuWq3bVlVvjuE8Ba+QmY3lx9vgTy/b0Gofx7mQpONs5bpun7u6vvz6WqOPuJv1hP3T9PAnrY9Nlm0fn76P9v9PNW7t3Pcn3/wGV7e/TT8cXltSWcxfej/+f6CK1/ygpaM9q/ZAUdykzcUblQCZKCpw47hSPATHuNITHdbXubcgfAxqdLtZs6eriY+5qpfm4VWbfdYtz8w+3o/fcX8zb3GoOB8Zq/jk7JznZsruVgBuqnfbhXcM/fviP4XwIbl+3BfdPH518VefG8Y/zGyKUaU/erTqqMmjANWobd86e88P841rwxL//uWYzhtseW+XV99G8+09MSKrtc9rapf+cxOp907Amfih2UACa8LPuSokvXzM3QzpUtVSuQoRUA9TO+G2femllx44mxvbC0jP54e1bVU19h8wXub7Nmv+XsmGovWIgdkT8LCu/s3TtxbeXo3p5tn6eP/4Uojbd+LnsHb+xvrjD621c7ex6XeL71dNu2EH39lLZRe0tIEFYSEeEF96BO2sH/NquRqsax+vSx92PRy6L/ZJjb/xs8+aX8S5gad2uitfBFr/qP+s3IoT85baY95uSYlOa/Ytz75H2z4fOdSwptxOv+49EYZfww9tOtmRUPZ1VAhXoN7sqyXu2VVnEsNSZ8P/rj3VmVj8MK0MdKI7oKZvF2f7/bvlbHSaixJ5vP9lrsb/2YN55aPlzUjsIXuyN8Q7nimbWkahVMfdJH8eKP7CtL6yvql5zEYQtQaN3d8f/Vcw+vKGk9VFsnQzcAgRLDHvQfX+qSObFnub9iMwIFg+r3b6rSucz3rYpntCyEnFd3ZWmAq8alBpZhx/3R691SsV49bTxN3HpWombNDO2aftqaGVo1QNHTMxp7G0FhgXT6N35ZJRzbBZGsUy63lr5C8T5HN4TuSAExeTd+YH9/9tvCpsKzYkX+uPq/rREl9l7MO2edTuj7w8g2jee2u/YG7+1ajUJQSxHvt2wMlwm3RyRUnCR9ZuXb1JEJVI7Cn/hnLkQKl7JDS6buVWzZXqnI6CqccXPiWkVVbumsmDO+Mnfs1ngUFrCjuK7H1nePKtRtpdu/MYvK8jvWeUCyQenqNQzkil2NVpG10J7Fllwsnb9tMq4uUq9MNYWHQsNWev4Xl9IYn2+rVJ0yNQO6CsUWuPTb+2nLTqyZk7govUdsvY7+miIzaub3r0rD6rkzvTNx/y7l/PWTwtHcEz/LFf5jX8U5d3b/tHP20zOtt8fe7101+BRGBjgAhTi8QSspgoNPBIhMjNdypAwRnEv/opY4rCEZ1avIvEaUVGuHgh33F3Z8Cm4fAcJ7/IIIbMseP1eFakWCwKLyIoEXQ+rJ2EFsPRLJuSESKdhLAlpK/TciFXuIQkutd9VOs/qwotPqn+SZiF2VtN+9ZCC2nms9HU9JtEcifdRHTp+UNklk4AlJaxkjITLxHK18TeYY6cy8S4sGFjeaiFYKke/ABq6aYkAjEvg2qYsEng6px2M2KfdIxFejJJIxlXi15AohkYJZJK6lVH0jUjGT6LXUKlftNKuPMDqt6kmeidhVKFWC8a9UpR4qg1iMjBBrPLTWKP4ASOkGd4CNqjjBBFBPE2/U/4BPIGEED6kBRc5Rj6cxKHKJejwtQJGL1ONpDopcoh5PC1Bw0fKLWKm5axKZGEYnJCGjxBobQDOpnYpPascmkSCoSU4k8HpIPR7nSLJHIr4NJd0vsAF0xOv0d2lh/gkAvASSlm2cz9GCl5TKaO/8giAZwzXWOqSZ1E6lNTs2YiWcnnQghtfpTxDNL5I6jQlo/RiiHTqGGFIEVr4Oj/QZarT0GMY3R1UEH7H1WVUZ6guPIaA6f1MmEinTgKBgwxc6EABM0AO2Ex+bDxBVFSNa6xD7Le7qEcBYqCR0M2CMFe8xTof4nBLECB1i38Ub4AD8nJKGw6yDcS4BfOZyAQkYrc2v2G9ef1k6UyCnyRG1FTKAn8oEeHSRg7pOjrI591BlLXtYPUe4P2wTrGRCJMHgGoyiYItyiLJIWpI3l6WMZyDuImg2cQMBo4kZ5AS8PjGAqWWmQyFyGpXg4g0ShFtt7NiUCTqPKsZ0kY2Milysnlbpyx6GO/eHbYOVsp8k/AQY3r4LAPosx3PvOuoSMEbqU1GJOEP3IwpmsYoG5mKuxI3QXYdkpmaYDgXJzEhXhXTcyQRkUuSgbpOxNnKvykX2kHqO5KK2CVYycRINLSN7lcSezEhAMAmZlI+Jb8wMMinMzDmxvBvjevE5AWPEuIl952WfKzqTL6dRvFRS0IwIXvGGboTIUCrLxCNmzmESjZnBi+DlUObP/FzAcJhudo7LP7cwIzNBBd8o8Q3G5r98WAIQACPV93vL+zZnt+JrS4wFAMDeZ96CAJBHZqEPaZ/zrA6WcABWGAAAAlRf0wFY+6iYWQXbhQfds1kBuoKR+c2LJvDxLAQNCD+JLHQXMhjHH0Cxr8GMIIpwC7TmGWjA9dHEIMA4XoQGPAwj2FM4jK8wkL9FA4MeC0QeWvImNBDtGMc/IZo9Q5AlYBi7xGjgszLwmZFNYSFDYRgnwGhOoA2SAMNys7VQL2z0W2+4vYHx9BqDXjfj1ugPea5ucWPFs6H+EsseGAvWvYTE9NkW6fk6jBSjMbk9aBBgZLwY3+JIydwi3aazol0qmhOThVn3YulgxbpovJwf0WAQBJhtgUgHnAgAuMBgNLgQwKI7O0o8ALQHkk5iPegGl5ErsvKKHLqQ4cuWgL+rdWnqnzqByCKjEEiqtK62TpaYtkkwwFnYuNt4r5r2ckFlc07MjiLa2LgNI9NT2Ztmoa/ghUClirT9YgdFw1lsQihjPdvUi0SZgnJ4J2qzp2dk5mvl0aLpGkhmliiaahGjremZmNuvKn9Mk0BG2Cx3vMLwns9H0bJn26p1B06ta7hoaLMbzEz39gYAAA==) format('woff2'); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; } @font-face { font-family: Roboto; font-style: normal; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: Roboto; font-style: normal; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } ================================================ FILE: packages/graphiql-react/package.json ================================================ { "name": "@graphiql/react", "version": "0.37.3", "sideEffects": [ "dist/setup-workers/*" ], "repository": { "type": "git", "url": "https://github.com/graphql/graphiql", "directory": "packages/graphiql-react" }, "homepage": "https://github.com/graphql/graphiql/tree/master/packages/graphiql-react#readme", "bugs": { "url": "https://github.com/graphql/graphiql/issues?q=issue+label:@graphiql/react" }, "license": "MIT", "exports": { "./package.json": "./package.json", "./style.css": "./dist/style.css", "./font/*": "./font/*", ".": "./dist/index.js", "./setup-workers/*": { "types": "./dist/setup-workers/*.d.ts", "import": "./dist/setup-workers/*.js" } }, "types": "dist/index.d.ts", "keywords": [ "react", "graphql", "sdk", "monaco-editor", "monaco-graphql", "monaco" ], "files": [ "dist", "font" ], "scripts": { "types:check": "tsc --noEmit", "dev": "vite build --watch --emptyOutDir=false", "build": "vite build", "test": "vitest --typecheck" }, "peerDependencies": { "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", "react": "^18 || ^19", "react-compiler-runtime": "19.1.0-rc.1", "react-dom": "^18 || ^19" }, "dependencies": { "@graphiql/toolkit": "^0.11.3", "@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", "clsx": "^1.2.1", "framer-motion": "^12.12", "get-value": "^3.0.1", "graphql-language-service": "^5.5.0", "jsonc-parser": "^3.3.1", "markdown-it": "^14.1.0", "monaco-editor": "0.52.2", "monaco-graphql": "^1.7.3", "prettier": "^3.5.3", "set-value": "^4.1.0", "zustand": "^5" }, "devDependencies": { "@babel/helper-string-parser": "^7.19.4", "@types/get-value": "^3.0.5", "@types/markdown-it": "^14.1.2", "@types/react-dom": "^19.1.2", "@types/set-value": "^4.0.1", "@vitejs/plugin-react": "^4.4.1", "babel-plugin-react-compiler": "19.1.0-rc.1", "graphql": "^16.9.0", "react": "^19.1.0", "react-dom": "^19.1.0", "typescript": "^4.6.3", "vite": "^6.3.4", "vite-plugin-dts": "^4.5.3", "vite-plugin-svgr": "^4.3.0" }, "browser": { "//": "Prevents esm.sh from injecting Node.js globals like `process`, which can break browser features (e.g., Mac `Cmd` key) when loading from CDN.", "buffer": false, "process": false } } ================================================ FILE: packages/graphiql-react/setup-files.ts ================================================ // to make it works like Jest (auto-mocking) vi.mock('monaco-editor'); export {}; ================================================ FILE: packages/graphiql-react/src/components/button/index.css ================================================ .graphiql-un-styled { all: unset; border-radius: var(--border-radius-4); cursor: pointer; &:hover { background-color: hsla(var(--color-neutral), var(--alpha-background-light)); } &:active { background-color: hsla( var(--color-neutral), var(--alpha-background-medium) ); } &:focus { outline: hsla(var(--color-neutral), var(--alpha-background-heavy)) auto 1px; } } .graphiql-button, button.graphiql-button { background-color: hsla(var(--color-neutral), var(--alpha-background-light)); border: none; border-radius: var(--border-radius-4); color: hsl(var(--color-neutral)); cursor: pointer; font-size: var(--font-size-body); padding: var(--px-8) var(--px-12); &:hover, &:active { background-color: hsla( var(--color-neutral), var(--alpha-background-medium) ); } &:focus { outline: hsla(var(--color-neutral), var(--alpha-background-heavy)) auto 1px; } &.graphiql-button-success { background-color: hsla(var(--color-success), var(--alpha-background-heavy)); } &.graphiql-button-error { background-color: hsla(var(--color-error), var(--alpha-background-heavy)); } } ================================================ FILE: packages/graphiql-react/src/components/button/index.tsx ================================================ import { ComponentPropsWithoutRef, forwardRef } from 'react'; import { cn } from '../../utility'; import './index.css'; type UnStyledButtonProps = ComponentPropsWithoutRef<'button'>; export const UnStyledButton = forwardRef< HTMLButtonElement, UnStyledButtonProps >((props, ref) => (