diff --git a/src/app/App.test.tsx b/src/app/App.test.tsx index 2f15a31f..02be2edc 100644 --- a/src/app/App.test.tsx +++ b/src/app/App.test.tsx @@ -21,7 +21,10 @@ afterEach(() => { }); it.each([false, true])('should render', (darkMode) => { - localStorage.setItem('usehooks-ts-dark-mode', String(darkMode)); + localStorage.setItem( + 'usehooks-ts-ternary-dark-mode', + JSON.stringify(darkMode ? 'dark' : 'light'), + ); testRender(); }); diff --git a/src/app/App.tsx b/src/app/App.tsx index c049f48d..9337d94f 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -5,7 +5,7 @@ import { Classes } from '@blueprintjs/core'; import React, { useEffect, useState } from 'react'; import { useDispatch } from 'react-redux'; import SplitterLayout from 'react-splitter-layout'; -import { useDarkMode, useLocalStorage } from 'usehooks-ts'; +import { useLocalStorage, useTernaryDarkMode } from 'usehooks-ts'; import Editor, { EditorType } from '../editor/Editor'; import Explorer from '../explorer/Explorer'; import { settingsToggleShowDocs } from '../settings/actions'; @@ -131,7 +131,7 @@ type AppProps = { }; const App: React.VoidFunctionComponent = ({ onEditorChanged }) => { - const { isDarkMode } = useDarkMode(); + const { isDarkMode } = useTernaryDarkMode(); const { isSettingShowDocsEnabled } = useSettingIsShowDocsEnabled(); const [isDragging, setIsDragging] = useState(false); const dispatch = useDispatch(); diff --git a/src/editor/Editor.tsx b/src/editor/Editor.tsx index 20884feb..4c48d6af 100644 --- a/src/editor/Editor.tsx +++ b/src/editor/Editor.tsx @@ -9,7 +9,7 @@ import xcodeTheme from 'monaco-themes/themes/Xcode_default.json'; import React, { useState } from 'react'; import MonacoEditor, { monaco } from 'react-monaco-editor'; import { useDispatch } from 'react-redux'; -import { useDarkMode } from 'usehooks-ts'; +import { useTernaryDarkMode } from 'usehooks-ts'; import { IDisposable } from 'xterm'; import { fileStorageWriteFile } from '../fileStorage/actions'; import { compile } from '../mpy/actions'; @@ -141,7 +141,7 @@ const Editor: React.VoidFunctionComponent = ({ onEditorChanged }) = const dispatch = useDispatch(); const [editor, setEditor] = useState(null); - const { isDarkMode } = useDarkMode(); + const { isDarkMode } = useTernaryDarkMode(); const [i18n] = useI18n({ id: 'editor', translations: { en }, fallback: en }); diff --git a/src/settings/SettingsDrawer.test.tsx b/src/settings/SettingsDrawer.test.tsx index a28c4c47..dbf20faa 100644 --- a/src/settings/SettingsDrawer.test.tsx +++ b/src/settings/SettingsDrawer.test.tsx @@ -39,6 +39,25 @@ describe('showDocs setting switch', () => { }); }); +describe('darkMode setting switch', () => { + it('should toggle setting', async () => { + const [settings] = testRender( + undefined} />, + ); + + const darkMode = settings.getByLabelText('Dark mode'); + expect(darkMode).not.toBeChecked(); + expect(localStorage.getItem('usehooks-ts-ternary-dark-mode')).toBe(null); + + userEvent.click(darkMode); + expect(darkMode).toBeChecked(); + expect(localStorage.getItem('usehooks-ts-ternary-dark-mode')).toBe('"dark"'); + + userEvent.click(darkMode); + expect(darkMode).not.toBeChecked(); + expect(localStorage.getItem('usehooks-ts-ternary-dark-mode')).toBe('"light"'); + }); +}); describe('flashCurrentProgram setting switch', () => { it('should toggle the setting', () => { const [settings] = testRender( diff --git a/src/settings/SettingsDrawer.tsx b/src/settings/SettingsDrawer.tsx index 84bdb0cc..2d614746 100644 --- a/src/settings/SettingsDrawer.tsx +++ b/src/settings/SettingsDrawer.tsx @@ -21,7 +21,7 @@ import { Tooltip2 } from '@blueprintjs/popover2'; import { useI18n } from '@shopify/react-i18n'; import React, { useMemo, useState } from 'react'; import { useDispatch } from 'react-redux'; -import { useDarkMode } from 'usehooks-ts'; +import { useTernaryDarkMode } from 'usehooks-ts'; import AboutDialog from '../about/AboutDialog'; import { appCheckForUpdate, appReload, appShowInstallPrompt } from '../app/actions'; import { @@ -59,7 +59,7 @@ const SettingsDrawer: React.VoidFunctionComponent = ({ toggleIsSettingShowDocsEnabled, } = useSettingIsShowDocsEnabled(); const [isAboutDialogOpen, setIsAboutDialogOpen] = useState(false); - const { isDarkMode, toggle: toggleDarkMode } = useDarkMode(); + const { isDarkMode, setTernaryDarkMode } = useTernaryDarkMode(); const [isFlashCurrentProgramEnabled, setIsFlashCurrentProgramEnabled] = useSettingFlashCurrentProgram(); @@ -153,7 +153,13 @@ const SettingsDrawer: React.VoidFunctionComponent = ({ SettingsStringId.AppearanceDarkModeLabel, )} checked={isDarkMode} - onChange={toggleDarkMode} + onChange={(e) => + setTernaryDarkMode( + (e.target as HTMLInputElement).checked + ? 'dark' + : 'light', + ) + } /> diff --git a/src/terminal/Terminal.tsx b/src/terminal/Terminal.tsx index fd7db5b1..09e1f025 100644 --- a/src/terminal/Terminal.tsx +++ b/src/terminal/Terminal.tsx @@ -6,7 +6,7 @@ import { ContextMenu2, ContextMenu2ContentProps } from '@blueprintjs/popover2'; import { useI18n } from '@shopify/react-i18n'; import React, { useContext, useEffect, useMemo, useRef } from 'react'; import { useDispatch } from 'react-redux'; -import { useDarkMode } from 'usehooks-ts'; +import { useTernaryDarkMode } from 'usehooks-ts'; import { Terminal as XTerm } from 'xterm'; import { FitAddon } from 'xterm-addon-fit'; import { isMacOS } from '../utils/os'; @@ -100,7 +100,7 @@ function createContextMenu( const Terminal: React.FC = (_props) => { const { xterm, fitAddon } = useMemo(createXTerm, [createXTerm]); const terminalRef = useRef(null); - const { isDarkMode } = useDarkMode(); + const { isDarkMode } = useTernaryDarkMode(); const dispatch = useDispatch(); const terminalStream = useContext(TerminalContext);