Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .changeset/slick-clubs-lay.md
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/query-devtools': patch
---

improves accessibility of devtools
127 changes: 61 additions & 66 deletions packages/query-devtools/src/Devtools.tsx
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1000,7 +1000,7 @@ export const ContentView: Component<ContentViewProps> = (props) => {
'tsqd-action-open-pip', 'tsqd-action-open-pip',
)} )}
aria-label="Open in picture-in-picture mode" aria-label="Open in picture-in-picture mode"
title={`Open in picture-in-picture mode`} title="Open in picture-in-picture mode"
> >
<PiPIcon /> <PiPIcon />
</button> </button>
Expand All @@ -1013,6 +1013,8 @@ export const ContentView: Component<ContentViewProps> = (props) => {
'tsqd-actions-btn', 'tsqd-actions-btn',
'tsqd-action-settings', 'tsqd-action-settings',
)} )}
aria-label="Open settings menu"
title="Open settings menu"
Comment on lines +1016 to +1017
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This menu item has no visible text, so adding label and title to account for this for screen readers

> >
<Settings /> <Settings />
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
Expand Down Expand Up @@ -1061,11 +1063,15 @@ export const ContentView: Component<ContentViewProps> = (props) => {
'tsqd-settings-submenu', 'tsqd-settings-submenu',
)} )}
> >
<DropdownMenu.Item <DropdownMenu.RadioGroup
onSelect={() => { aria-label="Position settings"
setDevtoolsPosition('top') value={props.localStore.position}
}} onChange={(value) =>
as="button" setDevtoolsPosition(value as DevtoolsPosition)
}
>
<DropdownMenu.RadioItem
value="top"
class={cx( class={cx(
styles().settingsSubButton, styles().settingsSubButton,
'tsqd-settings-menu-position-btn', 'tsqd-settings-menu-position-btn',
Expand All @@ -1074,12 +1080,9 @@ export const ContentView: Component<ContentViewProps> = (props) => {
> >
<span>Top</span> <span>Top</span>
<ArrowUp /> <ArrowUp />
</DropdownMenu.Item> </DropdownMenu.RadioItem>
<DropdownMenu.Item <DropdownMenu.RadioItem
onSelect={() => { value="bottom"
setDevtoolsPosition('bottom')
}}
as="button"
class={cx( class={cx(
styles().settingsSubButton, styles().settingsSubButton,
'tsqd-settings-menu-position-btn', 'tsqd-settings-menu-position-btn',
Expand All @@ -1088,12 +1091,9 @@ export const ContentView: Component<ContentViewProps> = (props) => {
> >
<span>Bottom</span> <span>Bottom</span>
<ArrowDown /> <ArrowDown />
</DropdownMenu.Item> </DropdownMenu.RadioItem>
<DropdownMenu.Item <DropdownMenu.RadioItem
onSelect={() => { value="left"
setDevtoolsPosition('left')
}}
as="button"
class={cx( class={cx(
styles().settingsSubButton, styles().settingsSubButton,
'tsqd-settings-menu-position-btn', 'tsqd-settings-menu-position-btn',
Expand All @@ -1102,12 +1102,9 @@ export const ContentView: Component<ContentViewProps> = (props) => {
> >
<span>Left</span> <span>Left</span>
<ArrowLeft /> <ArrowLeft />
</DropdownMenu.Item> </DropdownMenu.RadioItem>
<DropdownMenu.Item <DropdownMenu.RadioItem
onSelect={() => { value="right"
setDevtoolsPosition('right')
}}
as="button"
class={cx( class={cx(
styles().settingsSubButton, styles().settingsSubButton,
'tsqd-settings-menu-position-btn', 'tsqd-settings-menu-position-btn',
Expand All @@ -1116,7 +1113,8 @@ export const ContentView: Component<ContentViewProps> = (props) => {
> >
<span>Right</span> <span>Right</span>
<ArrowRight /> <ArrowRight />
</DropdownMenu.Item> </DropdownMenu.RadioItem>
</DropdownMenu.RadioGroup>
</DropdownMenu.SubContent> </DropdownMenu.SubContent>
</DropdownMenu.Portal> </DropdownMenu.Portal>
</DropdownMenu.Sub> </DropdownMenu.Sub>
Expand Down Expand Up @@ -1146,54 +1144,47 @@ export const ContentView: Component<ContentViewProps> = (props) => {
'tsqd-settings-submenu', 'tsqd-settings-submenu',
)} )}
> >
<DropdownMenu.Item <DropdownMenu.RadioGroup
onSelect={() => { value={props.localStore.theme_preference}
props.setLocalStore('theme_preference', 'light') onChange={(value) => {
props.setLocalStore('theme_preference', value)
}} }}
as="button" aria-label="Theme preference"
>
<DropdownMenu.RadioItem
value="light"
class={cx( class={cx(
styles().settingsSubButton, styles().settingsSubButton,
props.localStore.theme_preference === 'light' &&
styles().themeSelectedButton,
'tsqd-settings-menu-position-btn', 'tsqd-settings-menu-position-btn',
'tsqd-settings-menu-position-btn-top', 'tsqd-settings-menu-position-btn-top',
)} )}
> >
<span>Light</span> <span>Light</span>
<Sun /> <Sun />
</DropdownMenu.Item> </DropdownMenu.RadioItem>
<DropdownMenu.Item <DropdownMenu.RadioItem
onSelect={() => { value="dark"
props.setLocalStore('theme_preference', 'dark')
}}
as="button"
class={cx( class={cx(
styles().settingsSubButton, styles().settingsSubButton,
props.localStore.theme_preference === 'dark' &&
styles().themeSelectedButton,
'tsqd-settings-menu-position-btn', 'tsqd-settings-menu-position-btn',
'tsqd-settings-menu-position-btn-bottom', 'tsqd-settings-menu-position-btn-bottom',
)} )}
> >
<span>Dark</span> <span>Dark</span>
<Moon /> <Moon />
</DropdownMenu.Item> </DropdownMenu.RadioItem>
<DropdownMenu.Item <DropdownMenu.RadioItem
onSelect={() => { value="system"
props.setLocalStore('theme_preference', 'system')
}}
as="button"
class={cx( class={cx(
styles().settingsSubButton, styles().settingsSubButton,
props.localStore.theme_preference === 'system' &&
styles().themeSelectedButton,
'tsqd-settings-menu-position-btn', 'tsqd-settings-menu-position-btn',
'tsqd-settings-menu-position-btn-left', 'tsqd-settings-menu-position-btn-left',
)} )}
> >
<span>System</span> <span>System</span>
<Monitor /> <Monitor />
</DropdownMenu.Item> </DropdownMenu.RadioItem>
</DropdownMenu.RadioGroup>
</DropdownMenu.SubContent> </DropdownMenu.SubContent>
</DropdownMenu.Portal> </DropdownMenu.Portal>
</DropdownMenu.Sub> </DropdownMenu.Sub>
Expand Down Expand Up @@ -1221,16 +1212,18 @@ export const ContentView: Component<ContentViewProps> = (props) => {
styles().settingsMenu, styles().settingsMenu,
'tsqd-settings-submenu', 'tsqd-settings-submenu',
)} )}
aria-label="Hide disabled queries setting"
> >
<DropdownMenu.Item <DropdownMenu.RadioGroup
onSelect={() => { value={props.localStore.hideDisabledQueries}
props.setLocalStore('hideDisabledQueries', 'false') onChange={(value) =>
}} props.setLocalStore('hideDisabledQueries', value)
as="button" }
>
<DropdownMenu.RadioItem
value="false"
class={cx( class={cx(
styles().settingsSubButton, styles().settingsSubButton,
props.localStore.hideDisabledQueries !== 'true' &&
styles().themeSelectedButton,
'tsqd-settings-menu-position-btn', 'tsqd-settings-menu-position-btn',
'tsqd-settings-menu-position-btn-show', 'tsqd-settings-menu-position-btn-show',
)} )}
Expand All @@ -1243,16 +1236,11 @@ export const ContentView: Component<ContentViewProps> = (props) => {
> >
<CheckCircle /> <CheckCircle />
</Show> </Show>
</DropdownMenu.Item> </DropdownMenu.RadioItem>
<DropdownMenu.Item <DropdownMenu.RadioItem
onSelect={() => { value="true"
props.setLocalStore('hideDisabledQueries', 'true')
}}
as="button"
class={cx( class={cx(
styles().settingsSubButton, styles().settingsSubButton,
props.localStore.hideDisabledQueries === 'true' &&
styles().themeSelectedButton,
'tsqd-settings-menu-position-btn', 'tsqd-settings-menu-position-btn',
'tsqd-settings-menu-position-btn-hide', 'tsqd-settings-menu-position-btn-hide',
)} )}
Expand All @@ -1265,7 +1253,8 @@ export const ContentView: Component<ContentViewProps> = (props) => {
> >
<CheckCircle /> <CheckCircle />
</Show> </Show>
</DropdownMenu.Item> </DropdownMenu.RadioItem>
</DropdownMenu.RadioGroup>
</DropdownMenu.SubContent> </DropdownMenu.SubContent>
</DropdownMenu.Portal> </DropdownMenu.Portal>
</DropdownMenu.Sub> </DropdownMenu.Sub>
Expand Down Expand Up @@ -1961,6 +1950,9 @@ const QueryDetails = () => {
styles().detailsBody, styles().detailsBody,
'tsqd-query-details-summary-container', 'tsqd-query-details-summary-container',
)} )}
role="status"
aria-live="polite"
aria-atomic="true"
> >
<div class="tsqd-query-details-summary"> <div class="tsqd-query-details-summary">
<pre> <pre>
Expand Down Expand Up @@ -2372,6 +2364,9 @@ const MutationDetails = () => {
styles().detailsBody, styles().detailsBody,
'tsqd-query-details-summary-container', 'tsqd-query-details-summary-container',
)} )}
role="status"
aria-live="polite"
aria-atomic="true"
> >
<div class="tsqd-query-details-summary"> <div class="tsqd-query-details-summary">
<pre> <pre>
Expand Down Expand Up @@ -3521,8 +3516,7 @@ const stylesFactory = (
outline-offset: 2px; outline-offset: 2px;
outline: 2px solid ${colors.blue[800]}; outline: 2px solid ${colors.blue[800]};
} }
`, &[data-checked] {
themeSelectedButton: css`
background-color: ${t(colors.purple[100], colors.purple[900])}; background-color: ${t(colors.purple[100], colors.purple[900])};
color: ${t(colors.purple[700], colors.purple[300])}; color: ${t(colors.purple[700], colors.purple[300])};
& svg { & svg {
Expand All @@ -3531,6 +3525,7 @@ const stylesFactory = (
&:hover { &:hover {
background-color: ${t(colors.purple[100], colors.purple[900])}; background-color: ${t(colors.purple[100], colors.purple[900])};
} }
}
`, `,
viewToggle: css` viewToggle: css`
border-radius: ${tokens.border.radius.sm}; border-radius: ${tokens.border.radius.sm};
Expand Down
18 changes: 16 additions & 2 deletions packages/query-devtools/src/Explorer.tsx
Original file line number Original file line Diff line number Diff line change
@@ -1,6 +1,14 @@
import { serialize, stringify } from 'superjson' import { serialize, stringify } from 'superjson'
import { clsx as cx } from 'clsx' import { clsx as cx } from 'clsx'
import { Index, Match, Show, Switch, createMemo, createSignal } from 'solid-js' import {
Index,
Match,
Show,
Switch,
createMemo,
createSignal,
createUniqueId,
} from 'solid-js'
import { Key } from '@solid-primitives/keyed' import { Key } from '@solid-primitives/keyed'
import * as goober from 'goober' import * as goober from 'goober'
import { tokens } from './theme' import { tokens } from './theme'
Expand Down Expand Up @@ -325,13 +333,16 @@ export default function Explorer(props: ExplorerProps) {


const currentDataPath = props.dataPath ?? [] const currentDataPath = props.dataPath ?? []


const inputId = createUniqueId()

return ( return (
<div class={styles().entry}> <div class={styles().entry}>
<Show when={subEntryPages().length}> <Show when={subEntryPages().length}>
<div class={styles().expanderButtonContainer}> <div class={styles().expanderButtonContainer}>
<button <button
class={styles().expanderButton} class={styles().expanderButton}
onClick={() => toggleExpanded()} onClick={() => toggleExpanded()}
aria-expanded={expanded() ? 'true' : 'false'}
> >
<Expander expanded={expanded()} /> <span>{props.label}</span>{' '} <Expander expanded={expanded()} /> <span>{props.label}</span>{' '}
<span class={styles().info}> <span class={styles().info}>
Expand Down Expand Up @@ -446,7 +457,9 @@ export default function Explorer(props: ExplorerProps) {
</Show> </Show>
<Show when={subEntryPages().length === 0}> <Show when={subEntryPages().length === 0}>
<div class={styles().row}> <div class={styles().row}>
<span class={styles().label}>{props.label}:</span> <label for={inputId} class={styles().label}>
{props.label}:
</label>
<Show <Show
when={ when={
props.editable && props.editable &&
Expand All @@ -467,6 +480,7 @@ export default function Explorer(props: ExplorerProps) {
} }
> >
<input <input
id={inputId}
type={type() === 'number' ? 'number' : 'text'} type={type() === 'number' ? 'number' : 'text'}
class={cx(styles().value, styles().editableInput)} class={cx(styles().value, styles().editableInput)}
value={props.value as string | number} value={props.value as string | number}
Expand Down
Loading