From 2bdd2f9f381cb085a71c842ac3b47610e7cbf046 Mon Sep 17 00:00:00 2001 From: Jonathan Sheely Date: Tue, 29 Nov 2022 18:50:20 -0500 Subject: [PATCH 1/3] Add undefined check to override boolean validation --- src/mantine-hooks/src/use-color-scheme/use-color-scheme.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mantine-hooks/src/use-color-scheme/use-color-scheme.ts b/src/mantine-hooks/src/use-color-scheme/use-color-scheme.ts index 1bf21544ab6..d0b25f10680 100644 --- a/src/mantine-hooks/src/use-color-scheme/use-color-scheme.ts +++ b/src/mantine-hooks/src/use-color-scheme/use-color-scheme.ts @@ -1,7 +1,7 @@ import { useMediaQuery, UseMediaQueryOptions } from '../use-media-query/use-media-query'; export function useColorScheme(initialValue?: 'dark' | 'light', options?: UseMediaQueryOptions) { - return useMediaQuery('(prefers-color-scheme: dark)', initialValue === 'dark', options) + return useMediaQuery('(prefers-color-scheme: dark)', initialValue === undefined ? undefined : initialValue === 'dark', options) ? 'dark' : 'light'; } From 646f1eb8df6d1da241f4dcabae12f13e92eab94f Mon Sep 17 00:00:00 2001 From: Jonathan Sheely Date: Wed, 30 Nov 2022 11:34:23 -0500 Subject: [PATCH 2/3] Removed initialValue. Fetch directly from query --- .../use-color-scheme.story.tsx | 28 +++++++++++++++++++ .../use-color-scheme.test.tsx | 22 +++++++++++++++ .../src/use-color-scheme/use-color-scheme.ts | 6 ++-- .../src/use-media-query/use-media-query.ts | 5 +--- 4 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 src/mantine-hooks/src/use-color-scheme/use-color-scheme.story.tsx create mode 100644 src/mantine-hooks/src/use-color-scheme/use-color-scheme.test.tsx diff --git a/src/mantine-hooks/src/use-color-scheme/use-color-scheme.story.tsx b/src/mantine-hooks/src/use-color-scheme/use-color-scheme.story.tsx new file mode 100644 index 00000000000..02593e809ba --- /dev/null +++ b/src/mantine-hooks/src/use-color-scheme/use-color-scheme.story.tsx @@ -0,0 +1,28 @@ +import React, { useEffect, useState } from 'react'; +import { storiesOf } from '@storybook/react'; +import { useColorScheme } from './use-color-scheme'; + +const Demo = () => { + const colorScheme = useColorScheme(undefined, { + getInitialValueInEffect: false, + }); + const [history, setHistory] = useState([]); + + useEffect(() => { + setHistory((current) => [...current, colorScheme]); + }, [colorScheme, setHistory]); + + return ( +
+ {history.map((mode, i) => ( +
Color Scheme: {mode}
+ ))} +
+ ); +}; + +storiesOf('Hooks/use-color-scheme', module).add('General usage', () => ( +
+ +
+)); diff --git a/src/mantine-hooks/src/use-color-scheme/use-color-scheme.test.tsx b/src/mantine-hooks/src/use-color-scheme/use-color-scheme.test.tsx new file mode 100644 index 00000000000..1fa13cc4744 --- /dev/null +++ b/src/mantine-hooks/src/use-color-scheme/use-color-scheme.test.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +// import { renderHook } from '@testing-library/react-hooks'; +import { render } from '@testing-library/react'; +import { useColorScheme } from './use-color-scheme'; + +describe('@maintine/hooks/use-color-scheme', () => { + let trace = jest.fn<(colorScheme: string) => void, string[]>(); + beforeEach(() => { + trace = jest.fn(); + }); + function WrapperComponent() { + const colorScheme = useColorScheme(); + trace(colorScheme); + return <>{colorScheme}; + } + + it('correctly returns initial state without useEffect', async () => { + render(); + expect(trace).toHaveBeenCalledTimes(1); + expect(trace.mock.calls[0][0]).toBe('light'); + }); +}); diff --git a/src/mantine-hooks/src/use-color-scheme/use-color-scheme.ts b/src/mantine-hooks/src/use-color-scheme/use-color-scheme.ts index d0b25f10680..39815035d5a 100644 --- a/src/mantine-hooks/src/use-color-scheme/use-color-scheme.ts +++ b/src/mantine-hooks/src/use-color-scheme/use-color-scheme.ts @@ -1,7 +1,7 @@ -import { useMediaQuery, UseMediaQueryOptions } from '../use-media-query/use-media-query'; +import { useMediaQuery } from '../use-media-query/use-media-query'; -export function useColorScheme(initialValue?: 'dark' | 'light', options?: UseMediaQueryOptions) { - return useMediaQuery('(prefers-color-scheme: dark)', initialValue === undefined ? undefined : initialValue === 'dark', options) +export function useColorScheme() { + return useMediaQuery('(prefers-color-scheme: dark)') ? 'dark' : 'light'; } diff --git a/src/mantine-hooks/src/use-media-query/use-media-query.ts b/src/mantine-hooks/src/use-media-query/use-media-query.ts index 923eaf485da..16119f2306a 100644 --- a/src/mantine-hooks/src/use-media-query/use-media-query.ts +++ b/src/mantine-hooks/src/use-media-query/use-media-query.ts @@ -35,12 +35,9 @@ function getInitialValue(query: string, initialValue?: boolean) { export function useMediaQuery( query: string, initialValue?: boolean, - { getInitialValueInEffect }: UseMediaQueryOptions = { - getInitialValueInEffect: true, - } ) { const [matches, setMatches] = useState( - getInitialValueInEffect ? false : getInitialValue(query, initialValue) + getInitialValue(query, initialValue) ); const queryRef = useRef(); From f62e8f7b45d3683c76525e1d32f88c342ea27760 Mon Sep 17 00:00:00 2001 From: Jonathan Sheely Date: Wed, 30 Nov 2022 12:07:33 -0500 Subject: [PATCH 3/3] Updated tests and reset initialValue --- .../use-color-scheme.test.tsx | 55 ++++++++++++++++++- .../src/use-color-scheme/use-color-scheme.ts | 6 +- .../src/use-media-query/use-media-query.ts | 5 +- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/mantine-hooks/src/use-color-scheme/use-color-scheme.test.tsx b/src/mantine-hooks/src/use-color-scheme/use-color-scheme.test.tsx index 1fa13cc4744..6771b44dd56 100644 --- a/src/mantine-hooks/src/use-color-scheme/use-color-scheme.test.tsx +++ b/src/mantine-hooks/src/use-color-scheme/use-color-scheme.test.tsx @@ -5,18 +5,67 @@ import { useColorScheme } from './use-color-scheme'; describe('@maintine/hooks/use-color-scheme', () => { let trace = jest.fn<(colorScheme: string) => void, string[]>(); + const mockmatchMedia = jest.fn().mockImplementation(() => ({ + matches: true, + media: '', + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + })); + const retainMatchMedia = window.matchMedia; beforeEach(() => { trace = jest.fn(); + window.matchMedia = retainMatchMedia; }); - function WrapperComponent() { - const colorScheme = useColorScheme(); + function WrapperComponent({ + initialValue, + getInitialValueInEffect = true, + }: { + initialValue?: 'light' | 'dark'; + getInitialValueInEffect?: boolean; + }) { + const colorScheme = useColorScheme(initialValue, { + getInitialValueInEffect, + }); trace(colorScheme); return <>{colorScheme}; } - it('correctly returns initial state without useEffect', async () => { + it('correctly returns initial dark state without useEffect', async () => { + render(); + expect(trace).toHaveBeenCalledTimes(2); + expect(trace.mock.calls[0][0]).toBe('dark'); + expect(trace.mock.calls[1][0]).toBe('light'); + }); + it('correctly returns initial dark state state without useEffect', async () => { + window.matchMedia = mockmatchMedia; + render(); + expect(trace).toHaveBeenCalledTimes(1); + expect(trace.mock.calls[0][0]).toBe('dark'); + }); + + it('correctly returns initial light state with useEffect', async () => { + render(); + expect(trace).toHaveBeenCalledTimes(2); + expect(trace.mock.calls[0][0]).toBe('dark'); + expect(trace.mock.calls[1][0]).toBe('light'); + }); + it('correctly returns initial dark state with useEffect', async () => { + window.matchMedia = mockmatchMedia; + render(); + expect(trace).toHaveBeenCalledTimes(1); + expect(trace.mock.calls[0][0]).toBe('dark'); + }); + it('correctly returns initial light state with deafult props', async () => { render(); expect(trace).toHaveBeenCalledTimes(1); expect(trace.mock.calls[0][0]).toBe('light'); }); + it('correctly returns initial dark state with deafult props', async () => { + window.matchMedia = mockmatchMedia; + render(); + expect(trace).toHaveBeenCalledTimes(2); + expect(trace.mock.calls[0][0]).toBe('light'); + expect(trace.mock.calls[1][0]).toBe('dark'); + }); }); diff --git a/src/mantine-hooks/src/use-color-scheme/use-color-scheme.ts b/src/mantine-hooks/src/use-color-scheme/use-color-scheme.ts index 39815035d5a..1bf21544ab6 100644 --- a/src/mantine-hooks/src/use-color-scheme/use-color-scheme.ts +++ b/src/mantine-hooks/src/use-color-scheme/use-color-scheme.ts @@ -1,7 +1,7 @@ -import { useMediaQuery } from '../use-media-query/use-media-query'; +import { useMediaQuery, UseMediaQueryOptions } from '../use-media-query/use-media-query'; -export function useColorScheme() { - return useMediaQuery('(prefers-color-scheme: dark)') +export function useColorScheme(initialValue?: 'dark' | 'light', options?: UseMediaQueryOptions) { + return useMediaQuery('(prefers-color-scheme: dark)', initialValue === 'dark', options) ? 'dark' : 'light'; } diff --git a/src/mantine-hooks/src/use-media-query/use-media-query.ts b/src/mantine-hooks/src/use-media-query/use-media-query.ts index 16119f2306a..88f04b4abc4 100644 --- a/src/mantine-hooks/src/use-media-query/use-media-query.ts +++ b/src/mantine-hooks/src/use-media-query/use-media-query.ts @@ -35,9 +35,12 @@ function getInitialValue(query: string, initialValue?: boolean) { export function useMediaQuery( query: string, initialValue?: boolean, + { getInitialValueInEffect }: UseMediaQueryOptions = { + getInitialValueInEffect: true, + } ) { const [matches, setMatches] = useState( - getInitialValue(query, initialValue) + getInitialValueInEffect ? initialValue : getInitialValue(query, initialValue) ); const queryRef = useRef();