Skip to content

Commit

Permalink
fix(docs): remove the theme provider (#2137)
Browse files Browse the repository at this point in the history
  • Loading branch information
sstraatemans authored May 22, 2024
1 parent 32d0b9a commit cfb7c5b
Show file tree
Hide file tree
Showing 14 changed files with 346 additions and 50 deletions.
5 changes: 5 additions & 0 deletions .changeset/late-lamps-poke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@kadena/react-ui": minor
---

Added a hook to toggle and keep theme state, removing the necessity of a theme provider context
Original file line number Diff line number Diff line change
@@ -1,27 +1,16 @@
import { useTheme } from 'next-themes';
import type { ITheme } from '@kadena/react-ui';
import { Themes, useTheme } from '@kadena/react-ui';
import type { ComponentPropsWithRef, FC } from 'react';
import React, { useEffect, useState } from 'react';
import React from 'react';

interface IProps extends ComponentPropsWithRef<'svg'> {
overwriteTheme?: 'light' | 'dark';
overwriteTheme?: ITheme;
}

export const DocsLogo: FC<IProps> = ({ overwriteTheme, ...props }) => {
const { theme } = useTheme() ?? 'dark';
const [innerTheme, setInnerTheme] = useState<string | undefined>(
overwriteTheme,
);

//fixes the logo color when the theme is loaded
useEffect(() => {
if (overwriteTheme) {
setInnerTheme(overwriteTheme);
} else {
setInnerTheme(theme);
}
}, [theme, overwriteTheme]);
const { theme } = useTheme({ overwriteTheme });

if (innerTheme === 'dark') {
if (theme === Themes.dark) {
return (
<svg
width="216"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
NavHeaderLink,
NavHeaderLinkList,
Stack,
Themes,
} from '@kadena/react-ui';
import classNames from 'classnames';
import Link from 'next/link';
Expand Down Expand Up @@ -44,7 +45,7 @@ export const Header: FC<IProps> = ({ menuItems, layout = 'full' }) => {
<NavHeader
logo={
<Link href="/" aria-label="Go to the home page">
<DocsLogo overwriteTheme="dark" height={32} />
<DocsLogo overwriteTheme={Themes.dark} height={32} />
</Link>
}
activeHref={pathname}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
import { EVENT_NAMES, analyticsEvent } from '@/utils/analytics';
import { MonoContrast } from '@kadena/react-icons';
import { NavHeaderButton } from '@kadena/react-ui';
import { NavHeaderButton, Themes, useTheme } from '@kadena/react-ui';
import classNames from 'classnames';
import { useTheme } from 'next-themes';
import type { FC } from 'react';
import React, { useEffect, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import { baseIcon, reversedIcon, socialsClass } from './styles.css';

export const ThemeToggle: FC = () => {
const [isMounted, setIsMounted] = useState<boolean>(false);
const [isRotated, rotateIcon] = useState<boolean>(false);

const { theme, setTheme } = useTheme();

useEffect(() => {
setIsMounted(true);
}, []);

const toggleTheme = (): void => {
const newTheme = theme === 'dark' ? 'light' : 'dark';
console.log(isRotated);

useEffect(() => {
rotateIcon(!isRotated);
}, [theme, rotateIcon]);

const toggleTheme = useCallback((): void => {
const newTheme = theme === Themes.dark ? Themes.light : Themes.dark;

setTheme(newTheme);
analyticsEvent(EVENT_NAMES['click:change_theme'], {
theme: newTheme,
});
};
}, [setTheme, theme]);

if (!isMounted) return null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const headerClass = style([
display: 'flex',
alignItems: 'center',
marginBlockStart: 'xl',
color: 'text.base.default',
}),
{
selectors: {
Expand Down
30 changes: 9 additions & 21 deletions packages/apps/docs/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ import { MenuProvider } from '@/hooks/useMenu/MenuProvider';
import { getLayout } from '@/utils/getLayout';
import type { IPageMeta, IPageProps } from '@kadena/docs-tools';
import { RouterProvider } from '@kadena/react-ui';
import { darkThemeClass } from '@kadena/react-ui/styles';
import { MDXProvider } from '@mdx-js/react';
import { ThemeProvider } from 'next-themes';
import type { AppProps } from 'next/app';
import Head from 'next/head';
import { useRouter } from 'next/router';
Expand Down Expand Up @@ -107,25 +105,15 @@ export const MyApp = ({
<link rel="apple-touch-icon" href="/assets/favicons/icon@192.png?1" />
</Head>
<MDXProvider components={markDownComponents}>
<ThemeProvider
attribute="class"
enableSystem={true}
defaultTheme="light"
value={{
light: 'light',
dark: darkThemeClass,
}}
>
<RouterProvider navigate={router.push}>
<MenuProvider>
<Header menuItems={props.headerMenuItems} />
<CookieConsent />
<Layout {...props}>
<Component {...props} />
</Layout>
</MenuProvider>
</RouterProvider>
</ThemeProvider>
<RouterProvider navigate={router.push}>
<MenuProvider>
<Header menuItems={props.headerMenuItems} />
<CookieConsent />
<Layout {...props}>
<Component {...props} />
</Layout>
</MenuProvider>
</RouterProvider>
</MDXProvider>
<Analytics />
</>
Expand Down
1 change: 1 addition & 0 deletions packages/libs/react-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
"@storybook/react-webpack5": "^8.0.5",
"@storybook/theming": "^8.0.5",
"@testing-library/react": "~14.0.0",
"@testing-library/react-hooks": "^8.0.1",
"@testing-library/user-event": "~14.5.1",
"@types/lodash.get": "^4.4.9",
"@types/lodash.mapvalues": "^4.6.7",
Expand Down
4 changes: 4 additions & 0 deletions packages/libs/react-ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,7 @@ export type {

// re-exports from 'react-aria'
export { RouterProvider } from 'react-aria';

export { useTheme } from './utils';
export { Themes } from './utils/useTheme/utils/constants';
export type { ITheme } from './utils/useTheme/utils/constants';
103 changes: 103 additions & 0 deletions packages/libs/react-ui/src/utils/__tests__/useTheme.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { renderHook } from '@testing-library/react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { useTheme } from '../useTheme';
import { Themes, storageKey } from '../useTheme/utils/constants';

const mocks = vi.hoisted(() => {
return {
getSystemTheme: vi.fn(),
};
});
describe('useTheme', () => {
beforeEach(() => {
vi.mock('../useTheme/utils/getSystemTheme', () => ({
getSystemTheme: mocks.getSystemTheme,
}));
});

afterEach(() => {
window.localStorage.removeItem(storageKey);
vi.resetAllMocks();
});

it('should set the state of the system (dark) when there is no localstorage set', () => {
mocks.getSystemTheme.mockReturnValue(Themes.dark);
const { result } = renderHook(() => useTheme());
expect(result.current.theme).toEqual(Themes.dark);
});

it('should set the state of the system (light) when there is no localstorage set', () => {
mocks.getSystemTheme.mockReturnValue(Themes.light);
const { result } = renderHook(() => useTheme());
expect(result.current.theme).toEqual(Themes.light);
});

it('should set the state of the localstorage value (light), if available', () => {
window.localStorage.setItem(storageKey, Themes.light);

const { result } = renderHook(() => useTheme());
expect(result.current.theme).toEqual(Themes.light);
});

it('should set the state of the localstorage value (light), if available', () => {
window.localStorage.setItem(storageKey, Themes.dark);

const { result } = renderHook(() => useTheme());
expect(result.current.theme).toEqual(Themes.dark);
});

it('should lock the theme when it is given as a prop (dark)', () => {
window.localStorage.setItem(storageKey, Themes.light);

expect(localStorage.getItem(storageKey)).toEqual(Themes.light);

const { result } = renderHook(() => useTheme({ lockedTheme: Themes.dark }));
expect(result.current.theme).toEqual(Themes.dark);
expect(localStorage.getItem(storageKey)).toEqual(Themes.dark);
});

it('should overwrite the theme when given as prop', () => {
window.localStorage.setItem(storageKey, Themes.light);

const { result } = renderHook(() => useTheme());

expect(result.current.theme).toEqual(Themes.light);

const { result: result2 } = renderHook(() =>
useTheme({ overwriteTheme: Themes.dark }),
);

expect(result2.current.theme).toEqual(Themes.dark);
});
it('should overwrite the theme when given as prop and the overwrite is set as well', () => {
expect(localStorage.getItem(storageKey)).toEqual(null);

const { result } = renderHook(() =>
useTheme({ overwriteTheme: Themes.light, lockedTheme: Themes.dark }),
);

expect(localStorage.getItem(storageKey)).toEqual(Themes.dark);
expect(result.current.theme).toEqual(Themes.light);
});
it('should switch state when the setTheme is called', () => {
window.localStorage.setItem(storageKey, Themes.light);
const { result, rerender } = renderHook(() => useTheme());
expect(result.current.theme).toEqual(Themes.light);

result.current.setTheme(Themes.dark);
rerender();
expect(result.current.theme).toEqual(Themes.dark);
});

it('should switch state when the setTheme is called, but the overwrite should still hold', () => {
window.localStorage.setItem(storageKey, Themes.light);
const { result, rerender } = renderHook(() =>
useTheme({ overwriteTheme: Themes.light }),
);
expect(result.current.theme).toEqual(Themes.light);

result.current.setTheme(Themes.dark);
rerender();
expect(result.current.theme).toEqual(Themes.light);
});
});
1 change: 1 addition & 0 deletions packages/libs/react-ui/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './object';
export * from './testId';
export * from './useAsyncFn';
export * from './useMountedState';
export * from './useTheme';
Loading

0 comments on commit cfb7c5b

Please sign in to comment.