Skip to content

GraphiQL 5 feedback (papercuts) #4023

Open
@benjie

Description

@benjie

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:

Image


<GraphiQL.Footer /> overlaps with scrollable area:

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions