Skip to content

Commit

Permalink
feat: useTheme add onChange callback
Browse files Browse the repository at this point in the history
  • Loading branch information
ianzone committed Aug 12, 2024
1 parent 87f8076 commit 2aabd37
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 22 deletions.
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module.exports = {
testPathIgnorePatterns: ['/.history/'],
modulePathIgnorePatterns: ['<rootDir>/package.json'],
resetMocks: false,
setupFiles: ['./jest.setup.js', 'jest-localstorage-mock'],
setupFiles: ['./jest.setup.js', 'jest-localstorage-mock', './match-media-mock.js'],
setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'],
transform: {
'^.+\\.tsx?$': ['ts-jest', { tsconfig: 'tsconfig.json' }],
Expand Down
13 changes: 13 additions & 0 deletions match-media-mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
16 changes: 1 addition & 15 deletions packages/hooks/src/useTheme/__test__/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});

import { act, renderHook } from '@testing-library/react';
import { useTheme } from '../index';
import useTheme from '../index';

describe('useTheme', () => {
test('themeMode init', () => {
Expand Down
21 changes: 15 additions & 6 deletions packages/hooks/src/useTheme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,27 @@ export enum ThemeMode {

export type ThemeModeType = `${ThemeMode}`;

export type ThemeType = 'light' | 'dark';

const matchMedia = window.matchMedia('(prefers-color-scheme: dark)');

function useCurrentTheme() {
const [theme, setTheme] = useState<'light' | 'dark'>(() => {
return matchMedia.matches ? ThemeMode.DARK : ThemeMode.LIGHT;
type Callback = (theme: ThemeType) => void;

function useCurrentTheme(callback: Callback = () => {}) {
const [theme, setTheme] = useState<ThemeType>(() => {
const init = matchMedia.matches ? ThemeMode.DARK : ThemeMode.LIGHT;
callback(init);
return init;
});

useEffect(() => {
const onThemeChange: MediaQueryList['onchange'] = (event) => {
if (event.matches) {
setTheme(ThemeMode.DARK);
callback(ThemeMode.DARK);
} else {
setTheme(ThemeMode.LIGHT);
callback(ThemeMode.LIGHT);
}
};

Expand All @@ -30,17 +38,18 @@ function useCurrentTheme() {
return () => {
matchMedia.removeEventListener('change', onThemeChange);
};
}, []);
}, [callback]);

return theme;
}

type Options = {
localStorageKey?: string;
onChange?: Callback;
};

export default function useTheme(options: Options = {}) {
const { localStorageKey } = options;
const { localStorageKey, onChange } = options;

const [themeMode, setThemeMode] = useState<ThemeModeType>(() => {
const preferredThemeMode =
Expand All @@ -57,7 +66,7 @@ export default function useTheme(options: Options = {}) {
}
};

const currentTheme = useCurrentTheme();
const currentTheme = useCurrentTheme(onChange);
const theme = themeMode === ThemeMode.SYSTEM ? currentTheme : themeMode;

return {
Expand Down

0 comments on commit 2aabd37

Please sign in to comment.