Skip to content

[wip] use zustand-persist #4031

New issue

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

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

Already on GitHub? Sign in to your account

Draft
wants to merge 72 commits into
base: graphiql-5
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
edf3b80
upd
dimaMachina Jun 11, 2025
85e37ae
upd
dimaMachina Jun 11, 2025
f9fa3ef
upd
dimaMachina Jun 12, 2025
fdc800c
upd
dimaMachina Jun 12, 2025
4fdf8df
upd
dimaMachina Jun 12, 2025
65eea18
upd
dimaMachina Jun 12, 2025
50c16f3
upd
dimaMachina Jun 12, 2025
3fc873b
upd
dimaMachina Jun 12, 2025
80f0210
visible plugin
dimaMachina Jun 12, 2025
433f1d1
visible plugin
dimaMachina Jun 12, 2025
1005c59
visible plugin
dimaMachina Jun 12, 2025
9db8f1e
visible plugin
dimaMachina Jun 12, 2025
b6faf05
visible plugin
dimaMachina Jun 12, 2025
e2333d7
Merge branch 'graphiql-5' into storage-key-2
dimaMachina Jun 22, 2025
fa56f25
upd
dimaMachina Jun 22, 2025
dcb58f5
upd
dimaMachina Jun 22, 2025
4a8e5f2
lint
dimaMachina Jun 22, 2025
f7378c8
add storage slice
dimaMachina Jun 22, 2025
429a643
add storage slice
dimaMachina Jun 22, 2025
cd1b7bf
upd
dimaMachina Jun 22, 2025
d4e07db
upd
dimaMachina Jun 22, 2025
fd6d42b
upd
dimaMachina Jun 22, 2025
31ffc69
upd
dimaMachina Jun 22, 2025
25a7af8
upd
dimaMachina Jun 22, 2025
a8824ee
upd
dimaMachina Jun 22, 2025
06c5061
lint
dimaMachina Jun 22, 2025
92dd841
upd
dimaMachina Jun 22, 2025
aa8ed00
fix type errors
dimaMachina Jun 22, 2025
6183871
add ts-expect
dimaMachina Jun 22, 2025
39b2a8a
upd
dimaMachina Jun 22, 2025
a90f932
upd
dimaMachina Jun 22, 2025
3a1273e
upd
dimaMachina Jun 22, 2025
7ac40a9
upd
dimaMachina Jun 22, 2025
a919c2a
upd
dimaMachina Jun 22, 2025
a3f887f
upd
dimaMachina Jun 22, 2025
f21fa94
upd
dimaMachina Jun 22, 2025
9640b26
upd
dimaMachina Jun 22, 2025
4d0c850
upd
dimaMachina Jun 22, 2025
25d80e0
upd resize
dimaMachina Jun 22, 2025
6166ef7
upd provider
dimaMachina Jun 22, 2025
dec8b86
upd provider
dimaMachina Jun 22, 2025
a01ca53
upd provider
dimaMachina Jun 22, 2025
fd7114c
upd toolkit/query.ts
dimaMachina Jun 22, 2025
928b463
upd
dimaMachina Jun 22, 2025
9306b8a
upd [skip ci]
dimaMachina Jun 22, 2025
607f949
upd [skip ci]
dimaMachina Jun 22, 2025
bab8f93
get default tabs state
dimaMachina Jun 22, 2025
fa298dd
tabs cleanup
dimaMachina Jun 22, 2025
3b24b96
upd
dimaMachina Jun 22, 2025
3252b13
remove storeTabs
dimaMachina Jun 22, 2025
ed5567e
upd
dimaMachina Jun 22, 2025
12ab3d5
upd
dimaMachina Jun 22, 2025
b69bfc5
upd
dimaMachina Jun 23, 2025
7ad875f
remove `clearHeadersFromTabs` and `serializeTabState`
dimaMachina Jun 23, 2025
9503865
save showPersistHeadersSettings in storage
dimaMachina Jun 23, 2025
ba0eda9
rm
dimaMachina Jun 23, 2025
fdeb156
fix clear storage
dimaMachina Jun 23, 2025
510ce6d
onChangeEditor
dimaMachina Jun 23, 2025
897e40c
onChangeEditor header editor
dimaMachina Jun 23, 2025
69d4231
upd resize hook
dimaMachina Jun 23, 2025
f2761d7
upd resize hook
dimaMachina Jun 23, 2025
2fc411c
upd query editor
dimaMachina Jun 23, 2025
19300c9
upd
dimaMachina Jun 23, 2025
de16d06
upd
dimaMachina Jun 23, 2025
a2024b9
upd
dimaMachina Jun 23, 2025
686cfe9
remove unused CodeMirror CSS classes from GraphiQL 4
dimaMachina Jun 23, 2025
ab81045
changeset
dimaMachina Jun 23, 2025
0a3734f
upd resize
dimaMachina Jun 23, 2025
22c167e
upd toolkit
dimaMachina Jun 23, 2025
55ba6ee
upd
dimaMachina Jun 23, 2025
e224c48
upd
dimaMachina Jun 23, 2025
3c0407b
prettier
dimaMachina Jun 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .changeset/little-impalas-applaud.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
#'@graphiql/plugin-history': minor
#'@graphiql/toolkit': minor
#'@graphiql/react': minor
#'graphiql': minor
---

remove `createLocalStorage` from `@graphiql/toolkit`

deprecate `useStorage` and `useTheme` hooks, use `useGraphiQLActions` and `useGraphiQL` hooks instead.

remove `StorageAPI`, replace it with `persist` and `createJSONStorage` from `zustand/middleware`

remove unused CodeMirror CSS classes from GraphiQL 4
4 changes: 2 additions & 2 deletions docs/migration/graphiql-5.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,14 @@ function App() {
> Clicking on a reference in the Query 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.
- Add new `useGraphiQL` and `useGraphiQLActions` hooks instead. See updated [README](../../packages/graphiql-react/README.md#core-hooks) 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 query editor will start out empty
- 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
- remove `onClickReference` from variable editor
- fix shortcut text per OS for default query and in run query in execute query button's tooltip
- fix shortcut text per OS for a default query and in run query in execute query button's tooltip

The `ToolbarMenu` component has changed.

Expand Down
6 changes: 3 additions & 3 deletions examples/graphiql-webpack/src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { explorerPlugin } from '@graphiql/plugin-explorer';
import { getSnippets } from './snippets';
import { codeExporterPlugin } from '@graphiql/plugin-code-exporter';
import { createGraphiQLFetcher } from '@graphiql/toolkit';
import { useStorage } from '@graphiql/react';
import { useGraphiQL } from '@graphiql/react';
import { serverSelectPlugin, LAST_URL_KEY } from './select-server-plugin';
import 'graphiql/setup-workers/webpack';
import './index.css';
Expand Down Expand Up @@ -91,8 +91,8 @@ function App() {
* provider tree. `<GraphiQLStorageBound>` must be rendered as a child of `<GraphiQL>`.
*/
function GraphiQLStorageBound({ setUrl }) {
const storage = useStorage();
const lastUrl = storage.get(LAST_URL_KEY) ?? STARTING_URL;
const storage = useGraphiQL(state => state.storage);
const lastUrl = storage.getItem(LAST_URL_KEY) ?? STARTING_URL;

useEffect(() => {
setUrl(lastUrl);
Expand Down
6 changes: 3 additions & 3 deletions examples/graphiql-webpack/src/select-server-plugin.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import * as React from 'react';
import { useStorage, useSchemaStore } from '@graphiql/react';
import { useGraphiQL, useSchemaStore } from '@graphiql/react';

export const LAST_URL_KEY = 'lastURL';

export const PREV_URLS_KEY = 'previousURLs';

const SelectServer = ({ url, setUrl }) => {
const inputRef = React.useRef(null);
const storage = useStorage();
const lastUrl = storage.get(LAST_URL_KEY);
const storage = useGraphiQL(state => state.storage);
const lastUrl = storage.getItem(LAST_URL_KEY);
const currentUrl = lastUrl ?? url;
const [inputValue, setInputValue] = React.useState(currentUrl);
const [previousUrls, setPreviousUrls] = React.useState(
Expand Down
2 changes: 1 addition & 1 deletion packages/graphiql-plugin-doc-explorer/src/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const DOC_EXPLORER_PLUGIN: GraphiQLPlugin = {
title: 'Documentation Explorer',
icon: function Icon() {
const visiblePlugin = useGraphiQL(state => state.visiblePlugin);
return visiblePlugin === DOC_EXPLORER_PLUGIN ? (
return visiblePlugin === DOC_EXPLORER_PLUGIN.title ? (
<DocsFilledIcon />
) : (
<DocsIcon />
Expand Down
19 changes: 7 additions & 12 deletions packages/graphiql-plugin-history/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@ import {
HistoryStore as ToolkitHistoryStore,
QueryStoreItem,
} from '@graphiql/toolkit';
import {
useGraphiQL,
pick,
useStorage,
createBoundedUseStore,
} from '@graphiql/react';
import { useGraphiQL, pick, createBoundedUseStore } from '@graphiql/react';

const historyStore = createStore<HistoryStoreType>((set, get) => ({
historyStorage: null,
Expand Down Expand Up @@ -44,7 +39,7 @@ type HistoryStoreType = {
actions: {
/**
* Add an operation to the history.
* @param operation The operation that was executed, consisting of the query,
* @param operation - The operation that was executed, consisting of the query,
* variables, headers, and operation name.
*/
addToHistory(operation: {
Expand All @@ -55,11 +50,11 @@ type HistoryStoreType = {
}): void;
/**
* Change the custom label of an item from the history.
* @param args An object containing the label (`undefined` if it should be
* @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
* @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(
Expand Down Expand Up @@ -90,9 +85,9 @@ type HistoryStoreType = {
}): void;
/**
* Delete an operation from the history.
* @param args The operation that was executed, consisting of the query,
* @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
* @param clearFavorites - This is only if you press the 'clear' button
*/
deleteFromHistory(args: QueryStoreItem, clearFavorites?: boolean): void;
/**
Expand Down Expand Up @@ -126,7 +121,7 @@ export const HistoryStore: FC<HistoryStoreProps> = ({
pick('isFetching', 'tabs', 'activeTabIndex'),
);
const activeTab = tabs[activeTabIndex]!;
const storage = useStorage();
const storage = useGraphiQL(state => state.storage);

const historyStorage = // eslint-disable-line react-hooks/exhaustive-deps -- false positive, code is optimized by React Compiler
new ToolkitHistoryStore(storage, maxHistoryLength);
Expand Down
20 changes: 9 additions & 11 deletions packages/graphiql-react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,28 +81,26 @@ 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
## Core Hooks

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

- **`useStorage`**: Provides a storage API that can be used to persist state in the browser (by default using `localStorage`).
- **`useTheme`**: Manages the current theme and provides a method to update it.
- **`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 |
| ----------- | -------------------------------------------------------------------------------- |
| `editor` | Manages **query**, **variables**, **headers**, and **response** editors and tabs |
| `execution` | Handles the execution of GraphQL requests |
| `plugin` | Manages plugins and the currently active plugin |
| `schema` | Fetches, validates, and stores the GraphQL schema |
| Store Slice | Responsibilities |
| ----------- | --------------------------------------------------------------------------------------------------------- |
| `storage` | Provides a storage API that can be used to persist state in the browser (by default using `localStorage`) |
| `theme` | Manages the current theme and provides a method to update it. |
| `editor` | Manages **query**, **variables**, **headers**, and **response** editors and tabs |
| `execution` | Handles the execution of GraphQL requests |
| `schema` | Fetches, validates, and stores the GraphQL schema |
| `plugin` | Manages plugins and the currently active plugin |

### Usage Example

Expand Down
6 changes: 0 additions & 6 deletions packages/graphiql-react/src/components/dialog/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@
position: fixed;
inset: 0;
background-color: hsla(var(--color-neutral), var(--alpha-background-heavy));
/**
* CodeMirror has a `z-index` set for the container of the scrollbar of the
* editor, so we have to add one here to make sure that the dialog is shown
* above the editor scrollbar (if they are visible).
*/
z-index: 10;
}

.graphiql-dialog {
Expand Down
23 changes: 11 additions & 12 deletions packages/graphiql-react/src/components/header-editor.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { FC, useEffect, useRef } from 'react';
import { useGraphiQL, useGraphiQLActions } from './provider';
import type { EditorProps } from '../types';
import { HEADER_URI, KEY_BINDINGS, STORAGE_KEY } from '../constants';
import { HEADER_URI, KEY_BINDINGS } from '../constants';
import {
getOrCreateModel,
createEditor,
useChangeHandler,
debounce,
onEditorContainerKeyDown,
pick,
cleanupDisposables,
cn,
} from '../utility';
Expand All @@ -21,21 +20,21 @@ interface HeaderEditorProps extends EditorProps {
}

export const HeaderEditor: FC<HeaderEditorProps> = ({ onEdit, ...props }) => {
const { setEditor, run, prettifyEditors, mergeQuery } = useGraphiQLActions();
const { initialHeaders, shouldPersistHeaders } = useGraphiQL(
pick('initialHeaders', 'shouldPersistHeaders'),
);
const { setEditor, run, prettifyEditors, mergeQuery, updateActiveTabValues } =
useGraphiQLActions();
const initialHeaders = useGraphiQL(state => state.initialHeaders);
const ref = useRef<HTMLDivElement>(null!);
useChangeHandler(
onEdit,
shouldPersistHeaders ? STORAGE_KEY.headers : null,
'headers',
);
useEffect(() => {
const model = getOrCreateModel({ uri: HEADER_URI, value: initialHeaders });
const editor = createEditor(ref, { model });
setEditor({ headerEditor: editor });
const handleChange = debounce(100, () => {
const value = model.getValue();
updateActiveTabValues({ headers: value });
onEdit?.(value);
});
const disposables = [
model.onDidChangeContent(handleChange),
editor.addAction({ ...KEY_BINDINGS.runQuery, run }),
editor.addAction({ ...KEY_BINDINGS.prettify, run: prettifyEditors }),
editor.addAction({ ...KEY_BINDINGS.mergeFragments, run: mergeQuery }),
Expand Down
41 changes: 3 additions & 38 deletions packages/graphiql-react/src/components/markdown-content/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@
*/

.graphiql-markdown-description,
.graphiql-markdown-deprecation,
.CodeMirror-hint-information-description,
.CodeMirror-hint-information-deprecation-reason,
.CodeMirror-info .info-description,
.CodeMirror-info .info-deprecation {
.graphiql-markdown-deprecation {
& blockquote {
margin-left: 0;
margin-right: 0;
Expand Down Expand Up @@ -68,9 +64,7 @@
}
}

.graphiql-markdown-description,
.CodeMirror-hint-information-description,
.CodeMirror-info .info-description {
.graphiql-markdown-description {
& a {
color: hsl(var(--color-primary));
text-decoration: none;
Expand All @@ -95,9 +89,7 @@
}
}

.graphiql-markdown-deprecation,
.CodeMirror-hint-information-deprecation-reason,
.CodeMirror-info .info-deprecation {
.graphiql-markdown-deprecation {
& a {
color: hsl(var(--color-warning));
text-decoration: underline;
Expand All @@ -120,30 +112,3 @@
.graphiql-markdown-preview > :not(:first-child) {
display: none;
}

/**
* We show deprecations in the following places:
* - In the hint tooltip when typing in the query editor.
* - In the info tooltip when hovering over a field in the query editor.
*/

.CodeMirror-hint-information-deprecation,
.CodeMirror-info .info-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));
margin-top: var(--px-12);
padding: var(--px-6) var(--px-8);
}

.CodeMirror-hint-information-deprecation-label,
.CodeMirror-info .info-deprecation-label {
font-size: var(--font-size-hint);
font-weight: var(--font-weight-medium);
}

.CodeMirror-hint-information-deprecation-reason,
.CodeMirror-info .info-deprecation-reason {
margin-top: var(--px-6);
}
Loading
Loading