diff --git a/.changeset/olive-ducks-move.md b/.changeset/olive-ducks-move.md new file mode 100644 index 0000000000..272a602f90 --- /dev/null +++ b/.changeset/olive-ducks-move.md @@ -0,0 +1,8 @@ +--- +'@tanstack/react-query-devtools': minor +'@tanstack/solid-query-devtools': minor +'@tanstack/vue-query-devtools': minor +'@tanstack/query-devtools': minor +--- + +feat(devtools): allow passing a theme via prop diff --git a/packages/query-devtools/src/DevtoolsComponent.tsx b/packages/query-devtools/src/DevtoolsComponent.tsx index 45d93204e0..069d79c87a 100644 --- a/packages/query-devtools/src/DevtoolsComponent.tsx +++ b/packages/query-devtools/src/DevtoolsComponent.tsx @@ -4,6 +4,7 @@ import { Devtools } from './Devtools' import { getPreferredColorScheme } from './utils' import { THEME_PREFERENCE } from './constants' import { PiPProvider, QueryDevtoolsContext, ThemeContext } from './contexts' +import type { Theme } from './contexts' import type { DevtoolsComponentType } from './Devtools' const DevtoolsComponent: DevtoolsComponentType = (props) => { @@ -14,10 +15,9 @@ const DevtoolsComponent: DevtoolsComponentType = (props) => { const colorScheme = getPreferredColorScheme() const theme = createMemo(() => { - const preference = (localStore.theme_preference || THEME_PREFERENCE) as - | 'system' - | 'dark' - | 'light' + const preference = (props.theme || + localStore.theme_preference || + THEME_PREFERENCE) as Theme if (preference !== 'system') return preference return colorScheme() }) diff --git a/packages/query-devtools/src/DevtoolsPanelComponent.tsx b/packages/query-devtools/src/DevtoolsPanelComponent.tsx index eb3d19e4d9..cae641b44a 100644 --- a/packages/query-devtools/src/DevtoolsPanelComponent.tsx +++ b/packages/query-devtools/src/DevtoolsPanelComponent.tsx @@ -4,6 +4,7 @@ import { ContentView, ParentPanel } from './Devtools' import { getPreferredColorScheme } from './utils' import { THEME_PREFERENCE } from './constants' import { PiPProvider, QueryDevtoolsContext, ThemeContext } from './contexts' +import type { Theme } from './contexts' import type { DevtoolsComponentType } from './Devtools' const DevtoolsPanelComponent: DevtoolsComponentType = (props) => { @@ -14,10 +15,9 @@ const DevtoolsPanelComponent: DevtoolsComponentType = (props) => { const colorScheme = getPreferredColorScheme() const theme = createMemo(() => { - const preference = (localStore.theme_preference || THEME_PREFERENCE) as - | 'system' - | 'dark' - | 'light' + const preference = (props.theme || + localStore.theme_preference || + THEME_PREFERENCE) as Theme if (preference !== 'system') return preference return colorScheme() }) diff --git a/packages/query-devtools/src/TanstackQueryDevtools.tsx b/packages/query-devtools/src/TanstackQueryDevtools.tsx index 2fee7ac00a..f8928d5d47 100644 --- a/packages/query-devtools/src/TanstackQueryDevtools.tsx +++ b/packages/query-devtools/src/TanstackQueryDevtools.tsx @@ -11,6 +11,7 @@ import type { DevtoolsErrorType, DevtoolsPosition, QueryDevtoolsProps, + Theme, } from './contexts' import type { Signal } from 'solid-js' @@ -33,6 +34,7 @@ class TanstackQueryDevtools { #errorTypes: Signal | undefined> #hideDisabledQueries: Signal #Component: DevtoolsComponentType | undefined + #theme: Signal #dispose?: () => void constructor(config: TanstackQueryDevtoolsConfig) { @@ -48,6 +50,7 @@ class TanstackQueryDevtools { styleNonce, shadowDOMTarget, hideDisabledQueries, + theme, } = config this.#client = createSignal(client) this.#queryFlavor = queryFlavor @@ -60,6 +63,7 @@ class TanstackQueryDevtools { this.#initialIsOpen = createSignal(initialIsOpen) this.#errorTypes = createSignal(errorTypes) this.#hideDisabledQueries = createSignal(hideDisabledQueries) + this.#theme = createSignal(theme) } setButtonPosition(position: DevtoolsButtonPosition) { @@ -82,6 +86,10 @@ class TanstackQueryDevtools { this.#client[1](client) } + setTheme(theme?: Theme) { + this.#theme[1](theme) + } + mount(el: T) { if (this.#isMounted) { throw new Error('Devtools is already mounted') @@ -93,6 +101,7 @@ class TanstackQueryDevtools { const [errors] = this.#errorTypes const [hideDisabledQueries] = this.#hideDisabledQueries const [queryClient] = this.#client + const [theme] = this.#theme let Devtools: DevtoolsComponentType if (this.#Component) { @@ -128,6 +137,9 @@ class TanstackQueryDevtools { get hideDisabledQueries() { return hideDisabledQueries() }, + get theme() { + return theme() + }, }} /> ) diff --git a/packages/query-devtools/src/TanstackQueryDevtoolsPanel.tsx b/packages/query-devtools/src/TanstackQueryDevtoolsPanel.tsx index 8b72850acd..699a64dbc1 100644 --- a/packages/query-devtools/src/TanstackQueryDevtoolsPanel.tsx +++ b/packages/query-devtools/src/TanstackQueryDevtoolsPanel.tsx @@ -11,6 +11,7 @@ import type { DevtoolsErrorType, DevtoolsPosition, QueryDevtoolsProps, + Theme, } from './contexts' import type { Signal } from 'solid-js' @@ -35,6 +36,7 @@ class TanstackQueryDevtoolsPanel { #hideDisabledQueries: Signal #onClose: Signal<(() => unknown) | undefined> #Component: DevtoolsComponentType | undefined + #theme: Signal #dispose?: () => void constructor(config: TanstackQueryDevtoolsPanelConfig) { @@ -51,6 +53,7 @@ class TanstackQueryDevtoolsPanel { shadowDOMTarget, onClose, hideDisabledQueries, + theme, } = config this.#client = createSignal(client) this.#queryFlavor = queryFlavor @@ -64,6 +67,7 @@ class TanstackQueryDevtoolsPanel { this.#errorTypes = createSignal(errorTypes) this.#hideDisabledQueries = createSignal(hideDisabledQueries) this.#onClose = createSignal(onClose) + this.#theme = createSignal(theme) } setButtonPosition(position: DevtoolsButtonPosition) { @@ -90,6 +94,10 @@ class TanstackQueryDevtoolsPanel { this.#onClose[1](() => onClose) } + setTheme(theme?: Theme) { + this.#theme[1](theme) + } + mount(el: T) { if (this.#isMounted) { throw new Error('Devtools is already mounted') @@ -102,6 +110,7 @@ class TanstackQueryDevtoolsPanel { const [hideDisabledQueries] = this.#hideDisabledQueries const [queryClient] = this.#client const [onClose] = this.#onClose + const [theme] = this.#theme let Devtools: DevtoolsComponentType if (this.#Component) { @@ -140,6 +149,9 @@ class TanstackQueryDevtoolsPanel { get onClose() { return onClose() }, + get theme() { + return theme() + }, }} /> ) diff --git a/packages/query-devtools/src/contexts/QueryDevtoolsContext.ts b/packages/query-devtools/src/contexts/QueryDevtoolsContext.ts index 51b44b3bae..77969931cb 100644 --- a/packages/query-devtools/src/contexts/QueryDevtoolsContext.ts +++ b/packages/query-devtools/src/contexts/QueryDevtoolsContext.ts @@ -5,6 +5,7 @@ type XPosition = 'left' | 'right' type YPosition = 'top' | 'bottom' export type DevtoolsPosition = XPosition | YPosition export type DevtoolsButtonPosition = `${YPosition}-${XPosition}` | 'relative' +export type Theme = 'dark' | 'light' | 'system' export interface DevtoolsErrorType { /** @@ -30,6 +31,7 @@ export interface QueryDevtoolsProps { shadowDOMTarget?: ShadowRoot onClose?: () => unknown hideDisabledQueries?: boolean + theme?: Theme } export const QueryDevtoolsContext = createContext({ diff --git a/packages/query-devtools/src/index.ts b/packages/query-devtools/src/index.ts index 1cf3cedd17..4a163cb2d3 100644 --- a/packages/query-devtools/src/index.ts +++ b/packages/query-devtools/src/index.ts @@ -2,6 +2,7 @@ export type { DevtoolsButtonPosition, DevtoolsErrorType, DevtoolsPosition, + Theme, } from './contexts' export { TanstackQueryDevtools, diff --git a/packages/react-query-devtools/src/ReactQueryDevtools.tsx b/packages/react-query-devtools/src/ReactQueryDevtools.tsx index 7c6ebcd25e..959d5a739b 100644 --- a/packages/react-query-devtools/src/ReactQueryDevtools.tsx +++ b/packages/react-query-devtools/src/ReactQueryDevtools.tsx @@ -6,6 +6,7 @@ import type { DevtoolsButtonPosition, DevtoolsErrorType, DevtoolsPosition, + Theme, } from '@tanstack/query-devtools' import type { QueryClient } from '@tanstack/react-query' @@ -46,6 +47,11 @@ export interface DevtoolsOptions { * Set this to true to hide disabled queries from the devtools panel. */ hideDisabledQueries?: boolean + /** + * Set this to 'light', 'dark', or 'system' to change the theme of the devtools panel. + * Defaults to 'system'. + */ + theme?: Theme } export function ReactQueryDevtools( @@ -61,6 +67,7 @@ export function ReactQueryDevtools( styleNonce, shadowDOMTarget, hideDisabledQueries, + theme, } = props const [devtools] = React.useState( new TanstackQueryDevtools({ @@ -75,6 +82,7 @@ export function ReactQueryDevtools( styleNonce, shadowDOMTarget, hideDisabledQueries, + theme, }), ) @@ -102,6 +110,10 @@ export function ReactQueryDevtools( devtools.setErrorTypes(errorTypes || []) }, [errorTypes, devtools]) + React.useEffect(() => { + devtools.setTheme(theme) + }, [theme, devtools]) + React.useEffect(() => { if (ref.current) { devtools.mount(ref.current) diff --git a/packages/react-query-devtools/src/ReactQueryDevtoolsPanel.tsx b/packages/react-query-devtools/src/ReactQueryDevtoolsPanel.tsx index d1db23537f..8ff179ea3d 100644 --- a/packages/react-query-devtools/src/ReactQueryDevtoolsPanel.tsx +++ b/packages/react-query-devtools/src/ReactQueryDevtoolsPanel.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { onlineManager, useQueryClient } from '@tanstack/react-query' import { TanstackQueryDevtoolsPanel } from '@tanstack/query-devtools' -import type { DevtoolsErrorType } from '@tanstack/query-devtools' +import type { DevtoolsErrorType, Theme } from '@tanstack/query-devtools' import type { QueryClient } from '@tanstack/react-query' export interface DevtoolsPanelOptions { @@ -39,6 +39,11 @@ export interface DevtoolsPanelOptions { * Set this to true to hide disabled queries from the devtools panel. */ hideDisabledQueries?: boolean + /** + * Set this to 'light', 'dark', or 'system' to change the theme of the devtools panel. + * Defaults to 'system'. + */ + theme?: Theme } export function ReactQueryDevtoolsPanel( @@ -46,7 +51,13 @@ export function ReactQueryDevtoolsPanel( ): React.ReactElement | null { const queryClient = useQueryClient(props.client) const ref = React.useRef(null) - const { errorTypes, styleNonce, shadowDOMTarget, hideDisabledQueries } = props + const { + errorTypes, + styleNonce, + shadowDOMTarget, + hideDisabledQueries, + theme, + } = props const [devtools] = React.useState( new TanstackQueryDevtoolsPanel({ client: queryClient, @@ -61,6 +72,7 @@ export function ReactQueryDevtoolsPanel( shadowDOMTarget, onClose: props.onClose, hideDisabledQueries, + theme, }), ) @@ -76,6 +88,10 @@ export function ReactQueryDevtoolsPanel( devtools.setErrorTypes(errorTypes || []) }, [errorTypes, devtools]) + React.useEffect(() => { + devtools.setTheme(theme) + }, [theme, devtools]) + React.useEffect(() => { if (ref.current) { devtools.mount(ref.current) diff --git a/packages/solid-query-devtools/src/devtools.tsx b/packages/solid-query-devtools/src/devtools.tsx index a787ce8d76..079f8bf95d 100644 --- a/packages/solid-query-devtools/src/devtools.tsx +++ b/packages/solid-query-devtools/src/devtools.tsx @@ -5,6 +5,7 @@ import type { DevtoolsButtonPosition, DevtoolsErrorType, DevtoolsPosition, + Theme, } from '@tanstack/query-devtools' import type { QueryClient } from '@tanstack/solid-query' @@ -45,6 +46,11 @@ interface DevtoolsOptions { * Set this to true to hide disabled queries from the devtools panel. */ hideDisabledQueries?: boolean + /** + * Set this to 'light', 'dark', or 'system' to change the theme of the devtools panel. + * Defaults to 'system'. + */ + theme?: Theme } export default function SolidQueryDevtools(props: DevtoolsOptions) { @@ -63,6 +69,7 @@ export default function SolidQueryDevtools(props: DevtoolsOptions) { styleNonce: props.styleNonce, shadowDOMTarget: props.shadowDOMTarget, hideDisabledQueries: props.hideDisabledQueries, + theme: props.theme, }) createEffect(() => { @@ -91,6 +98,10 @@ export default function SolidQueryDevtools(props: DevtoolsOptions) { devtools.setErrorTypes(props.errorTypes || []) }) + createEffect(() => { + devtools.setTheme(props.theme || 'system') + }) + onMount(() => { devtools.mount(ref) onCleanup(() => devtools.unmount()) diff --git a/packages/solid-query-devtools/src/devtoolsPanel.tsx b/packages/solid-query-devtools/src/devtoolsPanel.tsx index 5ddc5319ac..1288b031e7 100644 --- a/packages/solid-query-devtools/src/devtoolsPanel.tsx +++ b/packages/solid-query-devtools/src/devtoolsPanel.tsx @@ -1,7 +1,7 @@ import { createEffect, createMemo, onCleanup, onMount } from 'solid-js' import { onlineManager, useQueryClient } from '@tanstack/solid-query' import { TanstackQueryDevtoolsPanel } from '@tanstack/query-devtools' -import type { DevtoolsErrorType } from '@tanstack/query-devtools' +import type { DevtoolsErrorType, Theme } from '@tanstack/query-devtools' import type { QueryClient } from '@tanstack/solid-query' import type { JSX } from 'solid-js' @@ -39,6 +39,11 @@ export interface DevtoolsPanelOptions { * Set this to true to hide disabled queries from the devtools panel. */ hideDisabledQueries?: boolean + /** + * Set this to 'light', 'dark', or 'system' to change the theme of the devtools panel. + * Defaults to 'system'. + */ + theme?: Theme } export default function SolidQueryDevtoolsPanel(props: DevtoolsPanelOptions) { @@ -59,6 +64,7 @@ export default function SolidQueryDevtoolsPanel(props: DevtoolsPanelOptions) { shadowDOMTarget, onClose: props.onClose, hideDisabledQueries, + theme: props.theme, }) createEffect(() => { devtools.setClient(client()) @@ -71,6 +77,10 @@ export default function SolidQueryDevtoolsPanel(props: DevtoolsPanelOptions) { devtools.setErrorTypes(props.errorTypes || []) }) + createEffect(() => { + devtools.setTheme(props.theme || 'system') + }) + onMount(() => { devtools.mount(ref) onCleanup(() => devtools.unmount()) diff --git a/packages/vue-query-devtools/src/devtools.vue b/packages/vue-query-devtools/src/devtools.vue index b995adb56c..d4e5482f9a 100644 --- a/packages/vue-query-devtools/src/devtools.vue +++ b/packages/vue-query-devtools/src/devtools.vue @@ -20,6 +20,7 @@ const devtools = new TanstackQueryDevtools({ styleNonce: props.styleNonce, shadowDOMTarget: props.shadowDOMTarget, hideDisabledQueries: props.hideDisabledQueries, + theme: props.theme, }) watchEffect(() => { @@ -27,6 +28,7 @@ watchEffect(() => { devtools.setPosition(props.position || 'bottom') devtools.setInitialIsOpen(props.initialIsOpen) devtools.setErrorTypes(props.errorTypes || []) + devtools.setTheme(props.theme || 'system') }) onMounted(() => { diff --git a/packages/vue-query-devtools/src/devtoolsPanel.vue b/packages/vue-query-devtools/src/devtoolsPanel.vue index 189f86330b..0443831240 100644 --- a/packages/vue-query-devtools/src/devtoolsPanel.vue +++ b/packages/vue-query-devtools/src/devtoolsPanel.vue @@ -28,11 +28,13 @@ const devtools = new TanstackQueryDevtoolsPanel({ shadowDOMTarget: props.shadowDOMTarget, hideDisabledQueries: props.hideDisabledQueries, onClose: props.onClose, + theme: props.theme, }) watchEffect(() => { devtools.setOnClose(props.onClose ?? (() => {})) devtools.setErrorTypes(props.errorTypes || []) + devtools.setTheme(props.theme) }) onMounted(() => { diff --git a/packages/vue-query-devtools/src/types.ts b/packages/vue-query-devtools/src/types.ts index 8007b06504..67dd9a2755 100644 --- a/packages/vue-query-devtools/src/types.ts +++ b/packages/vue-query-devtools/src/types.ts @@ -2,6 +2,7 @@ import type { DevtoolsButtonPosition, DevtoolsErrorType, DevtoolsPosition, + Theme, } from '@tanstack/query-devtools' import type { QueryClient } from '@tanstack/vue-query' @@ -42,6 +43,11 @@ export interface DevtoolsOptions { * Set this to true to hide disabled queries from the devtools panel. */ hideDisabledQueries?: boolean + /** + * Set this to 'light', 'dark', or 'system' to change the theme of the devtools panel. + * Defaults to 'system'. + */ + theme?: Theme } export interface DevtoolsPanelOptions { @@ -78,4 +84,9 @@ export interface DevtoolsPanelOptions { * Set this to true to hide disabled queries from the devtools panel. */ hideDisabledQueries?: boolean + /** + * Set this to 'light', 'dark', or 'system' to change the theme of the devtools panel. + * Defaults to 'system'. + */ + theme?: Theme }