Skip to content

Commit b5eb598

Browse files
v6: Align GraphQL syntax colors and color type names by category (#4403)
## Summary This PR does two related things for GraphQL identifier coloring across the first-party plugins. **1. Align colors across plugins.** Type names, field names, and argument names now use the same colors across the doc explorer, history, and query builder. Doc explorer was already internally consistent (orange types, green fields, purple arguments), so it's the reference the other two now follow. History's saved query labels (previously plain foreground text) are now the same green as field names. Query builder previously colored composite return types and type-condition names blue and left argument names uncolored; both now match doc explorer. **2. Color type names by category.** Instead of every type name being orange, type-name references are colored by GraphQL kind, so a field list is no longer a monotonous wall of orange: | Kind | Color | |---|---| | object / interface / union | orange | | scalar | blue | | enum | green | | input object | gold | This applies in the schema-aware plugins (doc explorer and query builder). The Monaco query editor is unchanged — it isn't schema-aware, so type names in query text stay orange. ### Public API The scheme is exposed so third-party plugins can conform to it and retheme it: - Four CSS tokens — `--type-composite`, `--type-scalar`, `--type-enum`, `--type-input` — are the supported retheming surface (documented in `tokens.css`). - `typeCategory(type)` is exported from `@graphiql/react`; it buckets any GraphQL type into `'scalar' | 'enum' | 'input' | 'composite'`, unwrapping list/non-null wrappers. Class names, internal selectors, and the `data-type-kind` attribute remain private. Light-theme `--type-input` uses a darker gold than the dark theme so it clears WCAG AA as text (~5–6.5:1 against the doc-explorer surfaces). ## Test plan - [x] **Alignment:** Open the doc explorer, history, and query builder in the same session. A field name is the same green in all three; an argument name is the same purple in both doc explorer and query builder. - [x] **Category colors (doc explorer):** Browse a schema with mixed field types. Scalar return types (`String`/`Int`/`Boolean`/`ID`/custom scalars) are blue, enum types green, object/interface/union types orange, and input object types gold. - [x] **Category colors (query builder):** Expand the field tree. Scalar-returning fields are blue, enum-returning fields green, object/interface/union fields orange. - [x] **Arguments (doc explorer):** A field with an input-object argument shows the input type name in gold, clearly distinct from the purple argument name beside it. - [x] **Type conditions (query builder):** Expand an interface/union field's possible types. The `... on TypeName` labels are orange. - [x] **Search (doc explorer):** Search results show type names colored by the same category scheme. - [x] **History:** Saved query entries show their label/operation name in green. - [x] **Light theme:** Switch themes and spot-check the same views. All four category colors stay legible against the panel background — the gold in particular should read as a clear dark gold, not washed out. Refs: #4219
1 parent cf0ebba commit b5eb598

20 files changed

Lines changed: 317 additions & 56 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@graphiql/react': patch
3+
'@graphiql/plugin-history': patch
4+
'@graphiql/plugin-query-builder': patch
5+
---
6+
7+
Align GraphQL syntax coloring across the doc explorer, history, and query builder plugins, so type names, field names, and argument names use the same colors everywhere.
8+
9+
Type names are now colored by category — scalars blue, enums green, input
10+
objects gold, and objects/interfaces/unions orange — instead of uniform
11+
orange. The mapping is exposed as public API: the `--type-scalar`,
12+
`--type-enum`, `--type-input`, and `--type-composite` CSS tokens (retheming
13+
surface) and the `typeCategory` helper exported from `@graphiql/react`.

docs/migration/graphiql-6.0.0.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ The new tokens are stored as `L% C H` component triplets (lightness percent, chr
4141
- **Borders:** `--border-default`, `--border-muted`, `--border-strong`
4242
- **Foreground:** `--fg-default`, `--fg-strong`, `--fg-muted`, `--fg-subtle`, `--fg-disabled`, `--fg-dim`
4343
- **Accents:** `--accent-blue`, `--accent-green`, `--accent-green-light`, `--accent-yellow`, `--accent-orange`, `--accent-red`, `--accent-purple`, `--accent-pink`
44+
- **Type-name categories:** `--type-composite`, `--type-scalar`, `--type-enum`, `--type-input`
4445
- **Run button:** `--btn-primary`, `--btn-primary-border`
4546
- **Radii:** `--radius-sm`, `--radius-md`, `--radius-lg`
4647
- **Shadow:** `--shadow-popover`
@@ -49,6 +50,29 @@ There is no published mapping from the nine v5 `--color-*` names to these — th
4950

5051
The v5 variables are still documented in the [`@graphiql/react` README](../../packages/graphiql-react/README.md#theming); the new token file itself, [`tokens.css`](../../packages/graphiql-react/src/style/tokens.css), is the source of truth for the v6 set until the README catches up.
5152

53+
### Type-name colors
54+
55+
In the schema-aware plugins — the doc explorer and the query builder — type-name references are colored by their GraphQL kind rather than all sharing one color. This makes a field list easier to scan: leaf types stand out from the objects you drill into.
56+
57+
| Kind | Token | Default |
58+
| ------------------------ | ------------------ | ------- |
59+
| object, interface, union | `--type-composite` | orange |
60+
| scalar | `--type-scalar` | blue |
61+
| enum | `--type-enum` | green |
62+
| input object | `--type-input` | gold |
63+
64+
These four `--type-*` tokens are the supported surface for retheming type-name colors. By default each aliases an accent token (`--type-scalar` resolves to `--accent-blue`, and so on), so you can retint either the accent or the `--type-*` token directly:
65+
66+
```css
67+
[data-theme='dark'] {
68+
--type-scalar: 75% 0.15 200; /* recolor scalar type names */
69+
}
70+
```
71+
72+
If you're building your own plugin that renders type names and want it to match, `@graphiql/react` exports a `typeCategory(type)` helper that maps any GraphQL type to `'scalar' | 'enum' | 'input' | 'composite'` (unwrapping list and non-null wrappers). Apply the corresponding `--type-*` token to your markup; the attribute and class names GraphiQL uses internally are not part of the public API.
73+
74+
The Monaco query editor is not schema-aware — it can't tell a scalar from an object by name alone — so type names in the query text itself keep a single color. This categorization applies only to the schema-driven plugin UIs.
75+
5276
### Retheming example
5377

5478
To retint the accent color and canvas background for dark mode:

packages/graphiql-plugin-doc-explorer/src/components/__tests__/type-link.spec.tsx

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { describe, it, expect } from 'vitest';
22
import { FC, useEffect } from 'react';
33
import { fireEvent, render } from '@testing-library/react';
4-
import { GraphQLNonNull, GraphQLList, GraphQLString } from 'graphql';
4+
import {
5+
GraphQLNonNull,
6+
GraphQLList,
7+
GraphQLString,
8+
GraphQLEnumType,
9+
GraphQLObjectType,
10+
GraphQLInputObjectType,
11+
} from 'graphql';
512
import { docExplorerStore, useDocExplorer } from '../../context';
613
import { TypeLink } from '../type-link';
714
import { unwrapType } from './test-utils';
@@ -70,4 +77,46 @@ describe('TypeLink', () => {
7077
rerender(<TypeLinkWithContext type={GraphQLString} />);
7178
expect(container).toHaveTextContent('String');
7279
});
80+
81+
const enumT = new GraphQLEnumType({
82+
name: 'Episode',
83+
values: { NEWHOPE: {} },
84+
});
85+
const objectT = new GraphQLObjectType({
86+
name: 'Droid',
87+
fields: { id: { type: GraphQLString } },
88+
});
89+
const inputT = new GraphQLInputObjectType({
90+
name: 'ReviewInput',
91+
fields: { stars: { type: GraphQLString } },
92+
});
93+
94+
it('tags a scalar type with data-type-kind="scalar"', () => {
95+
const { container } = render(<TypeLinkWithContext type={GraphQLString} />);
96+
expect(container.querySelector('a')).toHaveAttribute(
97+
'data-type-kind',
98+
'scalar',
99+
);
100+
});
101+
it('tags an enum type with data-type-kind="enum"', () => {
102+
const { container } = render(<TypeLinkWithContext type={enumT} />);
103+
expect(container.querySelector('a')).toHaveAttribute(
104+
'data-type-kind',
105+
'enum',
106+
);
107+
});
108+
it('tags an object type with data-type-kind="composite"', () => {
109+
const { container } = render(<TypeLinkWithContext type={objectT} />);
110+
expect(container.querySelector('a')).toHaveAttribute(
111+
'data-type-kind',
112+
'composite',
113+
);
114+
});
115+
it('tags an input object type with data-type-kind="input"', () => {
116+
const { container } = render(<TypeLinkWithContext type={inputT} />);
117+
expect(container.querySelector('a')).toHaveAttribute(
118+
'data-type-kind',
119+
'input',
120+
);
121+
});
73122
});

packages/graphiql-plugin-doc-explorer/src/components/arguments-list.css

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,7 @@
7878
}
7979

8080
.graphiql-doc-explorer-argument-type {
81-
color: oklch(var(--accent-orange));
82-
83-
& .graphiql-doc-explorer-type-name {
84-
color: oklch(var(--accent-orange));
85-
86-
&:hover {
87-
text-decoration: underline;
88-
}
89-
}
81+
color: oklch(var(--fg-default));
9082
}
9183

9284
.graphiql-doc-explorer-argument-default {

packages/graphiql-plugin-doc-explorer/src/components/field-card.css

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,7 @@
2626
.graphiql-doc-explorer-field-card-type {
2727
font-family: var(--font-family-mono);
2828
font-size: 14px;
29-
color: oklch(var(--accent-orange));
30-
31-
& .graphiql-doc-explorer-type-name {
32-
color: oklch(var(--accent-orange));
33-
34-
&:hover {
35-
text-decoration: underline;
36-
}
37-
}
29+
color: oklch(var(--fg-default));
3830
}
3931

4032
.graphiql-doc-explorer-field-card-description {

packages/graphiql-plugin-doc-explorer/src/components/fields-list.css

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -104,18 +104,10 @@
104104
color: oklch(var(--fg-disabled));
105105
}
106106

107-
/* Return type color — inherits from TypeLink */
107+
/* The type-name anchor colors itself by category (see type-link.css); this
108+
wrapper only styles the surrounding list/non-null punctuation ([, ], !). */
108109
.graphiql-doc-explorer-field-row-type {
109-
color: oklch(var(--accent-orange));
110-
111-
/* TypeLink anchors inside a field row get orange color */
112-
& .graphiql-doc-explorer-type-name {
113-
color: oklch(var(--accent-orange));
114-
115-
&:hover {
116-
text-decoration: underline;
117-
}
118-
}
110+
color: oklch(var(--fg-default));
119111
}
120112

121113
/* Optional description */

packages/graphiql-plugin-doc-explorer/src/components/schema-documentation.css

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,10 @@
5555
color: oklch(var(--fg-muted));
5656
}
5757

58-
/* Type name in root rows — orange like TypeLink */
58+
/* Root operation types are always objects (composite). Plain spans, not
59+
TypeLink anchors, so they need an explicit color. */
5960
.graphiql-doc-explorer-schema-root-row .graphiql-doc-explorer-type-name {
60-
color: oklch(var(--accent-orange));
61+
color: oklch(var(--type-composite));
6162
}
6263

6364
/* All-types rows */

packages/graphiql-plugin-doc-explorer/src/components/search-row.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
KeycapHint,
2121
debounce,
2222
KEY_MAP,
23+
typeCategory,
2324
} from '@graphiql/react';
2425
import { useDocExplorer, useDocExplorerActions } from '../context';
2526
import { useSearchResults } from './search';
@@ -163,7 +164,12 @@ export const SearchRow: FC = () => {
163164
};
164165

165166
const SearchType: FC<{ type: GraphQLNamedType }> = ({ type }) => (
166-
<span className="graphiql-doc-explorer-search-type">{type.name}</span>
167+
<span
168+
className="graphiql-doc-explorer-search-type"
169+
data-type-kind={typeCategory(type)}
170+
>
171+
{type.name}
172+
</span>
167173
);
168174

169175
type SearchFieldProps = {

packages/graphiql-plugin-doc-explorer/src/components/search.css

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,19 @@
8686
}
8787

8888
.graphiql-doc-explorer-search-type {
89-
color: oklch(var(--accent-orange));
89+
color: oklch(var(--type-composite));
90+
}
91+
92+
.graphiql-doc-explorer-search-type[data-type-kind='scalar'] {
93+
color: oklch(var(--type-scalar));
94+
}
95+
96+
.graphiql-doc-explorer-search-type[data-type-kind='enum'] {
97+
color: oklch(var(--type-enum));
98+
}
99+
100+
.graphiql-doc-explorer-search-type[data-type-kind='input'] {
101+
color: oklch(var(--type-input));
90102
}
91103

92104
.graphiql-doc-explorer-search-field {

packages/graphiql-plugin-doc-explorer/src/components/type-card.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767

6868
a.graphiql-doc-explorer-type-card-implements-link {
6969
font-family: var(--font-family-mono);
70-
color: oklch(var(--accent-orange));
70+
color: oklch(var(--type-composite));
7171
text-decoration: none;
7272

7373
&:hover {

0 commit comments

Comments
 (0)