Description
I'm migrating Ruru to GraphiQL V5 and thought I'd share feedback as I went along. This feedback seems very critical but it's not, V5 is great! It's just the papercuts faced whilst migrating.
(This issue is still being updated.)
<GraphiQL.Toolbar>
shouldn't require a callback as the only child, passing react components should be fine if you already have the callbacks you need. For example, if you have:
const { copyQuery, mergeQuery, prettifyEditors } = useGraphiQLActions();
You should be able to do:
<GraphiQL.Toolbar>
<ToolbarButton
onClick={prettifyEditors}
label="Prettify (Shift-Ctrl-P)"
>
<PrettifyIcon
className="graphiql-toolbar-icon"
aria-hidden="true"
/>
</ToolbarButton>
<ToolbarButton
onSelect={mergeQuery}
label="Merge Query (Shift-Ctrl-M)"
>
<MergeIcon className="graphiql-toolbar-icon" aria-hidden="true" />
</ToolbarButton>
<ToolbarButton
onClick={copyQuery}
label="Copy query (Shift-Ctrl-C)"
>
<CopyIcon className="graphiql-toolbar-icon" aria-hidden="true" />
</ToolbarButton>
Currently it unnecessarily requires much more nested code:
<GraphiQL.Toolbar>
{() => (
<>
<ToolbarButton
onClick={prettify}
label="Prettify Query (Shift-Ctrl-P)"
>
<PrettifyIcon
className="graphiql-toolbar-icon"
aria-hidden="true"
/>
</ToolbarButton>
<ToolbarButton
onSelect={mergeQuery}
label="Merge Query (Shift-Ctrl-M)"
>
<MergeIcon
className="graphiql-toolbar-icon"
aria-hidden="true"
/>
</ToolbarButton>
<ToolbarButton
onClick={copyQuery}
label="Copy query (Shift-Ctrl-C)"
>
<CopyIcon
className="graphiql-toolbar-icon"
aria-hidden="true"
/>
</ToolbarButton>
Seems unnecessarily breaking.
useGraphiQL
hook is not obvious and has no description; took me a little poking to realise the function you passes was effectively a selector. Now it seems super useful!
GraphiQLProps is not exported (see #4022)
usePrettifyEditors
could be supported but deprecated easily to make migration easier. (Similar for other related hooks.)
useSchemaContext
isn't mentioned in the migration guide (I think?). I worked out I could do useGraphiQL(t => t.schema)
to get the schema, and const { introspect } = useGraphiQLActions()
to get the introspect function, but it took some digging.
Adding
"./style.css": "./dist/style.css",
+ "./graphiql.css": "./dist/style.css",
to package.json would remove a minor breaking change without adding maintenance burden or increasing bundle size.
This code:
function logOnceWebWorkerWarning(err) {
if (!_platform_js__WEBPACK_IMPORTED_MODULE_4__.isWeb) {
// running tests
return;
}
if (!webWorkerWarningLogged) {
webWorkerWarningLogged = true;
console.warn('Could not create web worker(s). Falling back to loading web worker code in main thread, which might cause UI freezes. Please see https://github.com/microsoft/monaco-editor#faq');
}
console.warn(err.message);
}
outputs:
⚠️ Could not create web worker(s). Falling back to loading web worker code in main thread, which might cause UI freezes. Please see https://github.com/microsoft/monaco-editor#faq [simpleWorker.js:40:17](webpack://RuruBundle/node_modules/monaco-editor/esm/vs/base/common/worker/simpleWorker.js?)
⚠️ undefined [simpleWorker.js:42:13](webpack://RuruBundle/node_modules/monaco-editor/esm/vs/base/common/worker/simpleWorker.js?)
The undefined
is sub-optimal, perhaps change the last line to:
console.warn(err.message ?? err);
I have:
<GraphiQL.Toolbar>
{() => (
<>
<ToolbarMenu
label="Options"
button={
<ToolbarButton label="Options">
<SettingsIcon
className="graphiql-toolbar-icon"
aria-hidden="true"
/>
</ToolbarButton>
}
>
<ToolbarMenu.Item
title="View the SQL statements that this query invokes"
onSelect={() => storage.toggle("explain")}
>
<span>
{storage.get("explain") === "true" ? check : nocheck}
Explain (if supported)
</span>
</ToolbarMenu.Item>
And React is complaining:
In HTML, <button> cannot be a descendant of <button>.
This will cause a hydration error.
...
<Primitive.div.Slot ref={function}>
<Primitive.div.SlotClone ref={function}>
<Primitive.button aria-describedby={undefined} data-state="closed" asChild={true} ref={function} ...>
<Primitive.button.Slot aria-describedby={undefined} data-state="closed" onPointerMove={function handleEvent} ...>
<Primitive.button.SlotClone aria-describedby={undefined} data-state="closed" ...>
<DropdownMenuButton className="graphiql-u..." aria-label="Options" aria-describedby={undefined} ...>
<DropdownMenuTrigger asChild={true}>
<MenuAnchor asChild={true} __scopeMenu={{Menu:[...], ...}}>
<PopperAnchor __scopePopper={{Menu:[...], ...}} asChild={true} ref={null}>
<Primitive.div asChild={true} ref={function}>
<Primitive.div.Slot ref={function}>
<Primitive.div.SlotClone ref={function}>
<Primitive.button type="button" id="radix-«rg»" aria-haspopup="menu" aria-expanded={false} ...>
<Primitive.button.Slot type="button" id="radix-«rg»" aria-haspopup="menu" ...>
<Primitive.button.SlotClone type="button" id="radix-«rg»" aria-haspopup="menu" ...>
> <button
> className="graphiql-un-styled graphiql-un-styled graphiql-toolbar-menu"
> aria-label="Options"
> aria-describedby={undefined}
> data-state="closed"
> onPointerMove={function handleEvent}
> onPointerLeave={function handleEvent}
> onPointerDown={function}
> onFocus={function handleEvent}
> onBlur={function handleEvent}
> onClick={function handleEvent}
> ref={function}
> type="button"
> id="radix-«rg»"
> aria-haspopup="menu"
> aria-expanded={false}
> aria-controls={undefined}
> data-disabled={undefined}
> disabled={false}
> onKeyDown={function handleEvent}
> >
...
<Primitive.button.Slot aria-describedby={undefined} data-state="closed" ...>
<Primitive.button.SlotClone aria-describedby={undefined} data-state="closed" ...>
<UnStyledButton ref={function} type="button" className="graphiql-t..." ...>
> <button
> type="button"
> className="graphiql-un-styled graphiql-toolbar-button"
> onClick={function}
> aria-label="Options"
> aria-invalid={undefined}
> aria-describedby={undefined}
> data-state="closed"
> onPointerMove={function handleEvent}
> onPointerLeave={function handleEvent}
> onPointerDown={function handleEvent}
> onFocus={function handleEvent}
> onBlur={function handleEvent}
> ref={function}
> >
Removing the <ToolbarButton label="Options">
wrapper around <SettingsIcon.../>
fixes the warning, but the settings icon now renders offset:
<GraphiQL.Footer />
overlaps with scrollable area: