Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion src/docs/pages/ThemePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ const ThemePage: FC = () => {
const theme = useTheme().theme.button;
</SyntaxHighlighter>
<SyntaxHighlighter language="tsx" style={dracula}>
const [mode, setMode, toggleMode] = useThemeMode(usePreferences);
const [mode, setMode, toggleMode] = useThemeMode();
</SyntaxHighlighter>
</Card>
</div>
Expand Down
18 changes: 0 additions & 18 deletions src/lib/components/DarkThemeToggle/DarkThemeToggle.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,4 @@ describe('Dark theme toggle', () => {
expect(screen.queryByLabelText('Currently light mode')).not.toBeInTheDocument();
expect(screen.queryByLabelText('Currently dark mode')).toBeInTheDocument();
});

it('should toggle the theme with `usePreferences` is false', async () => {
const user = userEvent.setup();
render(
<Flowbite theme={{ usePreferences: false }}>
<DarkThemeToggle />
</Flowbite>,
);

expect(screen.queryByLabelText('Currently light mode')).toBeInTheDocument();
expect(screen.queryByLabelText('Currently dark mode')).not.toBeInTheDocument();

await user.tab();
await user.keyboard('[Space]');

expect(screen.queryByLabelText('Currently light mode')).not.toBeInTheDocument();
expect(screen.queryByLabelText('Currently dark mode')).toBeInTheDocument();
});
});
32 changes: 14 additions & 18 deletions src/lib/components/Flowbite/Flowbite.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { act, render } from '@testing-library/react';
import { afterEach, describe, expect, it } from 'vitest';
import { describe, expect, it } from 'vitest';
import { mergeDeep } from '../../helpers/mergeDeep';
import defaultTheme from '../../theme/default';
import { Flowbite, useTheme } from '../Flowbite';
import { ThemeContextProps } from './ThemeContext';

afterEach(() => {
localStorage.removeItem('theme');
});

describe('Components / Flowbite', () => {
describe('hook / useTheme', () => {
it('should return default values', () => {
Expand Down Expand Up @@ -49,19 +45,6 @@ describe('Components / Flowbite', () => {
expect(theme).toEqual(mergedTheme);
});

it('should return darkmode', () => {
render(
<Flowbite theme={{ dark: true }}>
<TestComponent />
</Flowbite>,
);

const { mode } = context;

expect(mode).toBe('dark');
expect(documentEl()).toHaveClass('dark');
});

it('should toggle mode', () => {
render(
<Flowbite>
Expand All @@ -83,6 +66,19 @@ describe('Components / Flowbite', () => {
expect(mode2).toBe('dark');
expect(documentEl()).toHaveClass('dark');
});

it('should return darkmode', () => {
render(
<Flowbite theme={{ dark: true }}>
<TestComponent />
</Flowbite>,
);

const { mode } = context;

expect(mode).toBe('dark');
expect(documentEl()).toHaveClass('dark');
});
});
});

Expand Down
13 changes: 10 additions & 3 deletions src/lib/components/Flowbite/Flowbite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { ThemeContext, useTheme, useThemeMode } from './ThemeContext';
export interface ThemeProps {
dark?: boolean;
theme?: DeepPartial<FlowbiteTheme>;
usePreferences?: boolean;
}

interface FlowbiteProps extends HTMLAttributes<HTMLDivElement> {
Expand All @@ -19,8 +18,8 @@ interface FlowbiteProps extends HTMLAttributes<HTMLDivElement> {
}

export const Flowbite: FC<FlowbiteProps> = ({ children, theme = {} }) => {
const { theme: customTheme = {}, dark, usePreferences = true } = theme;
const [mode, setMode, toggleMode] = useThemeMode(usePreferences);
const { theme: customTheme = {}, dark } = theme;
const [mode, setMode, toggleMode] = useThemeMode();

const mergedTheme = mergeDeep(defaultTheme, customTheme);

Expand All @@ -33,6 +32,14 @@ export const Flowbite: FC<FlowbiteProps> = ({ children, theme = {} }) => {
if (windowExists()) {
document.documentElement.classList.add('dark');
}
} else if (dark === false) {
if (setMode != null) {
setMode('light');
}

if (windowExists()) {
document.documentElement.classList.remove('dark');
}
}
}, [dark, setMode]);

Expand Down
23 changes: 11 additions & 12 deletions src/lib/components/Flowbite/ThemeContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,17 @@ export function useTheme(): ThemeContextProps {
return useContext(ThemeContext);
}

export const useThemeMode = (
usePreferences: boolean,
): [Mode, React.Dispatch<React.SetStateAction<Mode>>, () => void] => {
const [mode, setModeState] = useState<Mode>('light');
const savePreference = (mode: Mode) => localStorage.setItem('theme', mode);
const getPreference = (): Mode => (localStorage.getItem('theme') as Mode) || getPrefersColorScheme();
export const useThemeMode = (): [Mode, React.Dispatch<React.SetStateAction<Mode>>, () => void] => {
const userPreferenceIsDark = () => window.matchMedia?.('(prefers-color-scheme: dark)').matches;
const getPrefersColorScheme = (): Mode => (userPreferenceIsDark() ? 'dark' : 'light');
const toggleMode = () => {
const _toggleMode = () => {
const newMode = mode === 'dark' ? 'light' : 'dark';
setMode(newMode);
setModeState(newMode);
};
const { mode: _mode, toggleMode = _toggleMode } = useContext(ThemeContext);
const [mode, setModeState] = useState<Mode>(_mode ? _mode : getPrefersColorScheme());
const setMode = (mode: Mode) => {
savePreference(mode);
if (!windowExists()) {
return;
}
Expand All @@ -56,10 +52,13 @@ export const useThemeMode = (

document.documentElement.classList.remove('dark');
};
if (usePreferences) {
useEffect(() => setModeState(getPreference()), []);
useEffect(() => setMode(mode), [mode]);
}

useEffect(() => {
if (_mode) {
setMode(_mode);
setModeState(_mode);
}
}, [_mode]);

return [mode, setModeState, toggleMode];
};