From 1de7e11a0adc442ba87bf5c58f9e6f3fcb377ac9 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Sat, 6 Nov 2021 13:28:35 -0400 Subject: [PATCH] Integrate color scheme preference into ui library (#950) --- eslintrc.ts.react.base.json | 1 + eslintrc.ts.react.jest.base.json | 1 + extension/src/app/containers/App.tsx | 4 +- .../src/browser/extension/devpanel/index.tsx | 18 +------ .../src/browser/extension/window/index.tsx | 11 +--- extension/test/app/containers/App.spec.js | 14 ++++++ package.json | 1 + packages/react-dock/demo/package.json | 1 + packages/react-dock/package.json | 1 + .../react-json-tree/examples/package.json | 1 + packages/react-json-tree/package.json | 1 + packages/redux-devtools-app/jest.config.js | 2 +- packages/redux-devtools-app/package.json | 1 + .../redux-devtools-app/src/actions/index.ts | 49 +++--------------- .../src/components/Settings/Themes.tsx | 11 ++-- .../src/constants/actionTypes.ts | 2 - packages/redux-devtools-app/src/index.tsx | 19 +------ .../redux-devtools-app/src/reducers/theme.ts | 44 +++------------- .../src/utils/media-queries.ts | 13 ----- .../test/__mocks__/styleMock.js | 1 - .../test/__mocks__/styleMock.ts | 1 + packages/redux-devtools-app/test/app.spec.tsx | 14 ++++++ .../redux-devtools-chart-monitor/package.json | 1 + .../redux-devtools-dock-monitor/package.json | 1 + .../demo/package.json | 1 + .../demo/src/index.tsx | 6 ++- .../package.json | 1 + .../package.json | 1 + .../demo/package.json | 1 + .../package.json | 1 + .../redux-devtools-log-monitor/package.json | 1 + packages/redux-devtools-remote/package.json | 1 - .../demo/package.json | 1 + .../package.json | 1 + .../examples/todomvc/package.json | 1 + .../package.json | 1 + .../redux-devtools-ui/.storybook/preview.tsx | 7 ++- packages/redux-devtools-ui/package.json | 1 + .../redux-devtools-ui/src/Container/index.tsx | 28 ++++++++--- packages/redux-devtools-ui/src/utils/theme.ts | 50 ++++++++++++++++--- .../tests/Container.test.tsx | 20 +++++++- .../__snapshots__/Container.test.tsx.snap | 2 +- .../examples/counter/package.json | 1 + .../examples/todomvc/package.json | 1 + packages/redux-devtools/package.json | 1 + yarn.lock | 23 ++++++++- 46 files changed, 194 insertions(+), 170 deletions(-) delete mode 100644 packages/redux-devtools-app/src/utils/media-queries.ts delete mode 100644 packages/redux-devtools-app/test/__mocks__/styleMock.js create mode 100644 packages/redux-devtools-app/test/__mocks__/styleMock.ts diff --git a/eslintrc.ts.react.base.json b/eslintrc.ts.react.base.json index a90bc962..648c186c 100644 --- a/eslintrc.ts.react.base.json +++ b/eslintrc.ts.react.base.json @@ -12,6 +12,7 @@ "plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended-requiring-type-checking", "plugin:react/recommended", + "plugin:react-hooks/recommended", "prettier" ], "settings": { diff --git a/eslintrc.ts.react.jest.base.json b/eslintrc.ts.react.jest.base.json index 1bd3ebba..ebc4e66f 100644 --- a/eslintrc.ts.react.jest.base.json +++ b/eslintrc.ts.react.jest.base.json @@ -6,6 +6,7 @@ "plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended-requiring-type-checking", "plugin:react/recommended", + "plugin:react-hooks/recommended", "plugin:jest/recommended", "plugin:jest/style", "prettier" diff --git a/extension/src/app/containers/App.tsx b/extension/src/app/containers/App.tsx index e19dddb3..e9b46b87 100644 --- a/extension/src/app/containers/App.tsx +++ b/extension/src/app/containers/App.tsx @@ -62,12 +62,10 @@ class App extends Component { function mapStateToProps(state: StoreState) { const instances = state.instances; const id = getActiveInstance(instances); - const { themeColorPreference, ...themeData } = state.theme; - return { options: instances.options[id], section: state.section, - theme: themeData, + theme: state.theme, notification: state.notification, }; } diff --git a/extension/src/browser/extension/devpanel/index.tsx b/extension/src/browser/extension/devpanel/index.tsx index 80ea8249..658612b6 100644 --- a/extension/src/browser/extension/devpanel/index.tsx +++ b/extension/src/browser/extension/devpanel/index.tsx @@ -8,10 +8,7 @@ import configureStore from '../../../app/stores/panelStore'; import '../../views/devpanel.pug'; import { Action, Store } from 'redux'; -import { - applyMediaFeaturesPreferences, - StoreAction, -} from '@redux-devtools/app/lib/actions'; +import { StoreAction } from '@redux-devtools/app/lib/actions'; import { PanelMessage } from '../../../app/middlewares/api'; import { StoreStateWithoutSocket } from '../../../app/reducers/panel'; import { PersistGate } from 'redux-persist/integration/react'; @@ -36,20 +33,9 @@ function renderDevTools() { unmountComponentAtNode(node!); clearTimeout(naTimeout); ({ store, persistor } = configureStore(position, bgConnection)); - - const onBeforeLift = () => { - if (store) { - store.dispatch(applyMediaFeaturesPreferences()); - } - }; - render( - + , diff --git a/extension/src/browser/extension/window/index.tsx b/extension/src/browser/extension/window/index.tsx index bc527588..a49aa01a 100644 --- a/extension/src/browser/extension/window/index.tsx +++ b/extension/src/browser/extension/window/index.tsx @@ -8,7 +8,6 @@ import configureStore from '../../../app/stores/windowStore'; import { MonitorMessage } from '../../../app/middlewares/api'; import '../../views/window.pug'; -import { applyMediaFeaturesPreferences } from '@redux-devtools/app/lib/actions'; const position = location.hash; @@ -26,17 +25,9 @@ chrome.runtime.getBackgroundPage((window) => { bg.onMessage.addListener(update); update(); - const onBeforeLift = () => { - localStore.dispatch(applyMediaFeaturesPreferences()); - }; - render( - + , diff --git a/extension/test/app/containers/App.spec.js b/extension/test/app/containers/App.spec.js index ffff097e..971789d7 100644 --- a/extension/test/app/containers/App.spec.js +++ b/extension/test/app/containers/App.spec.js @@ -4,6 +4,20 @@ import { Provider } from 'react-redux'; import configureStore from '../../../src/app/stores/windowStore'; import App from '../../../src/app/containers/App'; +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(), + })), +}); + const { store } = configureStore(store); describe('App container', () => { diff --git a/package.json b/package.json index 55aaa0c8..b5a06fb8 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-jest": "^25.2.2", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "jest": "^27.3.1", "lerna": "^4.0.0", "prettier": "2.4.1", diff --git a/packages/react-dock/demo/package.json b/packages/react-dock/demo/package.json index ced58486..8ce78c38 100644 --- a/packages/react-dock/demo/package.json +++ b/packages/react-dock/demo/package.json @@ -35,6 +35,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "fork-ts-checker-webpack-plugin": "^6.4.0", "html-webpack-plugin": "^5.5.0", "ts-node": "^10.4.0", diff --git a/packages/react-dock/package.json b/packages/react-dock/package.json index b8fd895a..0e4a8290 100644 --- a/packages/react-dock/package.json +++ b/packages/react-dock/package.json @@ -57,6 +57,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-jest": "^25.2.2", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "jest": "^27.3.1", "react": "^17.0.2", "react-test-renderer": "^17.0.2", diff --git a/packages/react-json-tree/examples/package.json b/packages/react-json-tree/examples/package.json index def957ec..10f80b40 100644 --- a/packages/react-json-tree/examples/package.json +++ b/packages/react-json-tree/examples/package.json @@ -41,6 +41,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "fork-ts-checker-webpack-plugin": "^6.4.0", "html-webpack-plugin": "^5.5.0", "ts-node": "^10.4.0", diff --git a/packages/react-json-tree/package.json b/packages/react-json-tree/package.json index 71b21958..95228ccf 100644 --- a/packages/react-json-tree/package.json +++ b/packages/react-json-tree/package.json @@ -65,6 +65,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-jest": "^25.2.2", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "jest": "^27.3.1", "react": "^17.0.2", "react-test-renderer": "^17.0.2", diff --git a/packages/redux-devtools-app/jest.config.js b/packages/redux-devtools-app/jest.config.js index 7e5b0b28..a1f53444 100644 --- a/packages/redux-devtools-app/jest.config.js +++ b/packages/redux-devtools-app/jest.config.js @@ -3,6 +3,6 @@ module.exports = { setupFilesAfterEnv: ['/test/setup.ts'], testEnvironment: 'jsdom', moduleNameMapper: { - '\\.css$': '/test/__mocks__/styleMock.js', + '\\.css$': '/test/__mocks__/styleMock.ts', }, }; diff --git a/packages/redux-devtools-app/package.json b/packages/redux-devtools-app/package.json index 19aa1e67..ef8e9971 100644 --- a/packages/redux-devtools-app/package.json +++ b/packages/redux-devtools-app/package.json @@ -91,6 +91,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-jest": "^25.2.2", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "file-loader": "^6.2.0", "fork-ts-checker-webpack-plugin": "^6.4.0", "html-loader": "^3.0.0", diff --git a/packages/redux-devtools-app/src/actions/index.ts b/packages/redux-devtools-app/src/actions/index.ts index 67733714..9611a447 100644 --- a/packages/redux-devtools-app/src/actions/index.ts +++ b/packages/redux-devtools-app/src/actions/index.ts @@ -3,7 +3,6 @@ import { AuthStates, States } from 'socketcluster-client/lib/scclientsocket'; import { CHANGE_SECTION, CHANGE_THEME, - APPLY_MEDIA_FEATURES_PREFERENCES, SELECT_INSTANCE, SELECT_MONITOR, UPDATE_MONITOR_STATE, @@ -45,10 +44,9 @@ import { import { Action } from 'redux'; import { Features, State } from '../reducers/instances'; import { MonitorStateMonitorState } from '../reducers/monitor'; -import { LiftedAction, LiftedState } from '@redux-devtools/core'; +import { LiftedAction } from '@redux-devtools/core'; import { Data } from '../reducers/reports'; -import { prefersDarkColorScheme } from '../utils/media-queries'; -import { ThemeColorPreference } from '../reducers/theme'; +import { LiftedState } from '@redux-devtools/core'; let monitorReducer: ( monitorProps: unknown, @@ -68,53 +66,19 @@ export function changeSection(section: string): ChangeSectionAction { interface ChangeThemeFormData { readonly theme: Theme; readonly scheme: Scheme; - readonly themeColorPreference: ThemeColorPreference; + readonly colorPreference: 'auto' | 'light' | 'dark'; } -export interface ChangeThemeData { +interface ChangeThemeData { readonly formData: ChangeThemeFormData; } export interface ChangeThemeAction { readonly type: typeof CHANGE_THEME; readonly theme: Theme; readonly scheme: Scheme; - readonly dark: boolean; - readonly themeColorPreference: ThemeColorPreference; + readonly colorPreference: 'auto' | 'light' | 'dark'; } - -export interface ApplyMediaFeaturesPreferencesAction { - readonly type: typeof APPLY_MEDIA_FEATURES_PREFERENCES; - readonly prefersDarkColorScheme: boolean; -} - export function changeTheme(data: ChangeThemeData): ChangeThemeAction { - const { themeColorPreference } = data.formData; - let dark: boolean; - - switch (themeColorPreference) { - case 'light': - dark = false; - break; - case 'dark': - dark = true; - break; - default: - dark = prefersDarkColorScheme(); - } - - return { type: CHANGE_THEME, ...data.formData, dark }; -} - -/** - * @see https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries#media_features - */ -export function applyMediaFeaturesPreferences( - payload?: Partial> -): ApplyMediaFeaturesPreferencesAction { - return { - prefersDarkColorScheme: prefersDarkColorScheme(), - ...payload, - type: APPLY_MEDIA_FEATURES_PREFERENCES, - }; + return { type: CHANGE_THEME, ...data.formData }; } export interface InitMonitorAction { @@ -600,7 +564,6 @@ export interface ErrorAction { export type StoreActionWithoutUpdateStateOrLiftedAction = | ChangeSectionAction | ChangeThemeAction - | ApplyMediaFeaturesPreferencesAction | MonitorActionAction | SelectInstanceAction | SelectMonitorAction diff --git a/packages/redux-devtools-app/src/components/Settings/Themes.tsx b/packages/redux-devtools-app/src/components/Settings/Themes.tsx index 5854b53a..f4665719 100644 --- a/packages/redux-devtools-app/src/components/Settings/Themes.tsx +++ b/packages/redux-devtools-app/src/components/Settings/Themes.tsx @@ -4,10 +4,6 @@ import { Container, Form } from '@redux-devtools/ui'; import { listSchemes, listThemes } from '@redux-devtools/ui/lib/utils/theme'; import { changeTheme } from '../../actions'; import { StoreState } from '../../reducers'; -import { - defaultThemeColorPreference, - themeColorPreferences, -} from '../../reducers/theme'; type StateProps = ReturnType; type DispatchProps = ResolveThunks; @@ -19,8 +15,7 @@ export class Themes extends Component { const formData = { theme: theme.theme, scheme: theme.scheme, - themeColorPreference: - theme.themeColorPreference ?? defaultThemeColorPreference, + colorPreference: theme.colorPreference, }; return ( @@ -38,10 +33,10 @@ export class Themes extends Component { type: 'string', enum: listSchemes(), }, - themeColorPreference: { + colorPreference: { title: 'theme color', type: 'string', - enum: themeColorPreferences as unknown as string[], + enum: ['auto', 'light', 'dark'], }, }, }} diff --git a/packages/redux-devtools-app/src/constants/actionTypes.ts b/packages/redux-devtools-app/src/constants/actionTypes.ts index fa9e0ee7..98b1aa38 100644 --- a/packages/redux-devtools-app/src/constants/actionTypes.ts +++ b/packages/redux-devtools-app/src/constants/actionTypes.ts @@ -1,7 +1,5 @@ export const CHANGE_SECTION = 'main/CHANGE_SECTION'; export const CHANGE_THEME = 'main/CHANGE_THEME'; -export const APPLY_MEDIA_FEATURES_PREFERENCES = - 'main/APPLY_MEDIA_FEATURES_PREFERENCES'; export const UPDATE_STATE = 'devTools/UPDATE_STATE'; export const SET_STATE = 'devTools/SET_STATE'; diff --git a/packages/redux-devtools-app/src/index.tsx b/packages/redux-devtools-app/src/index.tsx index 6d2d8b81..abb0fc56 100644 --- a/packages/redux-devtools-app/src/index.tsx +++ b/packages/redux-devtools-app/src/index.tsx @@ -7,7 +7,7 @@ import configureStore from './store/configureStore'; import { CONNECT_REQUEST } from './constants/socketActionTypes'; import App from './containers/App'; import { StoreState } from './reducers'; -import { StoreAction, applyMediaFeaturesPreferences } from './actions'; +import { StoreAction } from './actions'; class Root extends Component { store?: Store; @@ -27,26 +27,11 @@ class Root extends Component { this.persistor = persistor; } - /** - * @hidden - * @private - */ - private _checkMediaFeaturesPreferences = () => { - if (this.store) { - this.store.dispatch(applyMediaFeaturesPreferences()); - } - }; - render() { if (!this.store) return null; - return ( - + diff --git a/packages/redux-devtools-app/src/reducers/theme.ts b/packages/redux-devtools-app/src/reducers/theme.ts index c801dcb8..f4f10e58 100644 --- a/packages/redux-devtools-app/src/reducers/theme.ts +++ b/packages/redux-devtools-app/src/reducers/theme.ts @@ -1,33 +1,18 @@ -import { Theme, Scheme } from '@redux-devtools/ui'; -import { - CHANGE_THEME, - APPLY_MEDIA_FEATURES_PREFERENCES, -} from '../constants/actionTypes'; +import { Scheme, Theme } from '@redux-devtools/ui'; +import { CHANGE_THEME } from '../constants/actionTypes'; import { StoreAction } from '../actions'; -export const defaultThemeColorPreference = 'auto'; - -export const themeColorPreferences = [ - defaultThemeColorPreference, - 'light', - 'dark', -] as const; - -export type ThemeColorPreference = typeof themeColorPreferences[number]; - export interface ThemeState { readonly theme: Theme; readonly scheme: Scheme; - readonly light: boolean; - readonly themeColorPreference?: ThemeColorPreference; + readonly colorPreference: 'auto' | 'light' | 'dark'; } export default function theme( state: ThemeState = { - theme: 'default' as const, - scheme: 'default' as const, - light: true, - themeColorPreference: defaultThemeColorPreference, + theme: 'default', + scheme: 'default', + colorPreference: 'auto', }, action: StoreAction ) { @@ -35,23 +20,8 @@ export default function theme( return { theme: action.theme, scheme: action.scheme, - light: !action.dark, - themeColorPreference: action.themeColorPreference, + colorPreference: action.colorPreference, }; } - - if ( - action.type === APPLY_MEDIA_FEATURES_PREFERENCES && - (!state.themeColorPreference || - state.themeColorPreference === defaultThemeColorPreference) - ) { - return { - ...state, - themeColorPreference: - state.themeColorPreference ?? defaultThemeColorPreference, - light: !action.prefersDarkColorScheme, - }; - } - return state; } diff --git a/packages/redux-devtools-app/src/utils/media-queries.ts b/packages/redux-devtools-app/src/utils/media-queries.ts deleted file mode 100644 index a965492c..00000000 --- a/packages/redux-devtools-app/src/utils/media-queries.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme - */ -export function prefersDarkColorScheme(): boolean { - if ( - typeof window !== 'undefined' && - typeof window.matchMedia === 'function' - ) { - return window.matchMedia('(prefers-color-scheme: dark)').matches; - } - - return false; -} diff --git a/packages/redux-devtools-app/test/__mocks__/styleMock.js b/packages/redux-devtools-app/test/__mocks__/styleMock.js deleted file mode 100644 index f053ebf7..00000000 --- a/packages/redux-devtools-app/test/__mocks__/styleMock.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {}; diff --git a/packages/redux-devtools-app/test/__mocks__/styleMock.ts b/packages/redux-devtools-app/test/__mocks__/styleMock.ts new file mode 100644 index 00000000..ff8b4c56 --- /dev/null +++ b/packages/redux-devtools-app/test/__mocks__/styleMock.ts @@ -0,0 +1 @@ +export default {}; diff --git a/packages/redux-devtools-app/test/app.spec.tsx b/packages/redux-devtools-app/test/app.spec.tsx index 615fb5b2..c5e7f14a 100644 --- a/packages/redux-devtools-app/test/app.spec.tsx +++ b/packages/redux-devtools-app/test/app.spec.tsx @@ -9,6 +9,20 @@ import rootReducer from '../src/reducers'; import { DATA_TYPE_KEY } from '../src/constants/dataTypes'; import stringifyJSON from '../src/utils/stringifyJSON'; +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(), + })), +}); + const store = createStore(rootReducer, applyMiddleware(exportState, api)); describe('App container', () => { diff --git a/packages/redux-devtools-chart-monitor/package.json b/packages/redux-devtools-chart-monitor/package.json index 089626ba..d2e3e84d 100644 --- a/packages/redux-devtools-chart-monitor/package.json +++ b/packages/redux-devtools-chart-monitor/package.json @@ -56,6 +56,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "react": "^17.0.2", "redux": "^4.1.2", "rimraf": "^3.0.2", diff --git a/packages/redux-devtools-dock-monitor/package.json b/packages/redux-devtools-dock-monitor/package.json index 974f5727..bf490a95 100644 --- a/packages/redux-devtools-dock-monitor/package.json +++ b/packages/redux-devtools-dock-monitor/package.json @@ -57,6 +57,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "react": "^17.0.2", "redux": "^4.1.2", "rimraf": "^3.0.2", diff --git a/packages/redux-devtools-inspector-monitor-test-tab/demo/package.json b/packages/redux-devtools-inspector-monitor-test-tab/demo/package.json index 341aff27..59dcaeac 100644 --- a/packages/redux-devtools-inspector-monitor-test-tab/demo/package.json +++ b/packages/redux-devtools-inspector-monitor-test-tab/demo/package.json @@ -48,6 +48,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "fork-ts-checker-webpack-plugin": "^6.4.0", "html-webpack-plugin": "^5.5.0", "style-loader": "^3.3.1", diff --git a/packages/redux-devtools-inspector-monitor-test-tab/demo/src/index.tsx b/packages/redux-devtools-inspector-monitor-test-tab/demo/src/index.tsx index 71a4700c..675ba777 100644 --- a/packages/redux-devtools-inspector-monitor-test-tab/demo/src/index.tsx +++ b/packages/redux-devtools-inspector-monitor-test-tab/demo/src/index.tsx @@ -58,7 +58,11 @@ render( diff --git a/packages/redux-devtools-inspector-monitor-test-tab/package.json b/packages/redux-devtools-inspector-monitor-test-tab/package.json index 9fd978a4..dbbfd003 100644 --- a/packages/redux-devtools-inspector-monitor-test-tab/package.json +++ b/packages/redux-devtools-inspector-monitor-test-tab/package.json @@ -73,6 +73,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-jest": "^25.2.2", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "jest": "^27.3.1", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/packages/redux-devtools-inspector-monitor-trace-tab/package.json b/packages/redux-devtools-inspector-monitor-trace-tab/package.json index b4f9f496..4261ef78 100644 --- a/packages/redux-devtools-inspector-monitor-trace-tab/package.json +++ b/packages/redux-devtools-inspector-monitor-trace-tab/package.json @@ -57,6 +57,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-jest": "^25.2.2", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "jest": "^27.3.1", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/packages/redux-devtools-inspector-monitor/demo/package.json b/packages/redux-devtools-inspector-monitor/demo/package.json index e06c8e52..063f171f 100644 --- a/packages/redux-devtools-inspector-monitor/demo/package.json +++ b/packages/redux-devtools-inspector-monitor/demo/package.json @@ -48,6 +48,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "fork-ts-checker-webpack-plugin": "^6.4.0", "html-webpack-plugin": "^5.5.0", "ts-node": "^10.4.0", diff --git a/packages/redux-devtools-inspector-monitor/package.json b/packages/redux-devtools-inspector-monitor/package.json index 670e22f1..a3b7cb83 100644 --- a/packages/redux-devtools-inspector-monitor/package.json +++ b/packages/redux-devtools-inspector-monitor/package.json @@ -70,6 +70,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "react": "^17.0.2", "redux": "^4.1.2", "rimraf": "^3.0.2", diff --git a/packages/redux-devtools-log-monitor/package.json b/packages/redux-devtools-log-monitor/package.json index fe731374..3dbe2cc6 100644 --- a/packages/redux-devtools-log-monitor/package.json +++ b/packages/redux-devtools-log-monitor/package.json @@ -59,6 +59,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "react": "^17.0.2", "redux": "^4.1.2", "rimraf": "^3.0.2", diff --git a/packages/redux-devtools-remote/package.json b/packages/redux-devtools-remote/package.json index ecbd40c0..70889247 100644 --- a/packages/redux-devtools-remote/package.json +++ b/packages/redux-devtools-remote/package.json @@ -57,7 +57,6 @@ "@typescript-eslint/parser": "^5.2.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", - "eslint-plugin-react": "^7.26.1", "redux": "^4.1.2", "rimraf": "^3.0.2", "typescript": "~4.4.4" diff --git a/packages/redux-devtools-rtk-query-monitor/demo/package.json b/packages/redux-devtools-rtk-query-monitor/demo/package.json index 7c4b4479..114e7532 100644 --- a/packages/redux-devtools-rtk-query-monitor/demo/package.json +++ b/packages/redux-devtools-rtk-query-monitor/demo/package.json @@ -49,6 +49,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "fork-ts-checker-webpack-plugin": "^6.4.0", "html-webpack-plugin": "^5.5.0", "style-loader": "^3.3.1", diff --git a/packages/redux-devtools-rtk-query-monitor/package.json b/packages/redux-devtools-rtk-query-monitor/package.json index 27c796de..fbf7a588 100644 --- a/packages/redux-devtools-rtk-query-monitor/package.json +++ b/packages/redux-devtools-rtk-query-monitor/package.json @@ -69,6 +69,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "react": "^17.0.2", "redux": "^4.1.2", "rimraf": "^3.0.2", diff --git a/packages/redux-devtools-slider-monitor/examples/todomvc/package.json b/packages/redux-devtools-slider-monitor/examples/todomvc/package.json index a53ec912..db664203 100644 --- a/packages/redux-devtools-slider-monitor/examples/todomvc/package.json +++ b/packages/redux-devtools-slider-monitor/examples/todomvc/package.json @@ -47,6 +47,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "fork-ts-checker-webpack-plugin": "^6.4.0", "html-webpack-plugin": "^5.5.0", "style-loader": "^3.3.1", diff --git a/packages/redux-devtools-slider-monitor/package.json b/packages/redux-devtools-slider-monitor/package.json index 7bd26d49..9808e9d7 100644 --- a/packages/redux-devtools-slider-monitor/package.json +++ b/packages/redux-devtools-slider-monitor/package.json @@ -48,6 +48,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "react": "^17.0.2", "redux": "^4.1.2", "rimraf": "^3.0.2", diff --git a/packages/redux-devtools-ui/.storybook/preview.tsx b/packages/redux-devtools-ui/.storybook/preview.tsx index a117e8cf..7128b553 100644 --- a/packages/redux-devtools-ui/.storybook/preview.tsx +++ b/packages/redux-devtools-ui/.storybook/preview.tsx @@ -13,6 +13,7 @@ export const globalTypes = { defaultValue: 'default', toolbar: { items: listThemes(), + showName: true, }, }, scheme: { @@ -21,6 +22,7 @@ export const globalTypes = { defaultValue: 'default', toolbar: { items: listSchemes(), + showName: true, }, }, color: { @@ -28,7 +30,8 @@ export const globalTypes = { description: 'Global color for components', defaultValue: 'light', toolbar: { - items: ['light', 'dark'], + items: ['auto', 'light', 'dark'], + showName: true, }, }, }; @@ -38,7 +41,7 @@ const withThemeProvider = (Story, context) => ( themeData={{ theme: context.globals.theme, scheme: context.globals.scheme, - light: context.globals.color === 'light', + colorPreference: context.globals.color, }} > diff --git a/packages/redux-devtools-ui/package.json b/packages/redux-devtools-ui/package.json index f1dde6f4..63ba24da 100644 --- a/packages/redux-devtools-ui/package.json +++ b/packages/redux-devtools-ui/package.json @@ -73,6 +73,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-jest": "^25.2.2", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "jest": "^27.3.1", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/packages/redux-devtools-ui/src/Container/index.tsx b/packages/redux-devtools-ui/src/Container/index.tsx index cdc05248..f5b106ef 100644 --- a/packages/redux-devtools-ui/src/Container/index.tsx +++ b/packages/redux-devtools-ui/src/Container/index.tsx @@ -1,10 +1,28 @@ import React from 'react'; import PropTypes from 'prop-types'; import { ThemeProvider } from 'styled-components'; -import { getTheme, ThemeData } from '../utils/theme'; +import { useTheme, ThemeData } from '../utils/theme'; import { MainContainerWrapper, ContainerWrapper } from './styles'; import { Theme } from '../themes/default'; +interface ContainerFromThemeDataProps { + children?: React.ReactNode; + themeData: ThemeData; + className?: string; +} + +const ContainerFromThemeData: React.FunctionComponent = + ({ themeData, className, children }) => { + const theme = useTheme(themeData); + return ( + + + {children} + + + ); + }; + interface Props { children?: React.ReactNode; themeData?: ThemeData; @@ -27,11 +45,9 @@ const Container: React.FunctionComponent = ({ } return ( - - - {children} - - + + {children} + ); }; diff --git a/packages/redux-devtools-ui/src/utils/theme.ts b/packages/redux-devtools-ui/src/utils/theme.ts index b0180cb7..74e27934 100644 --- a/packages/redux-devtools-ui/src/utils/theme.ts +++ b/packages/redux-devtools-ui/src/utils/theme.ts @@ -1,3 +1,4 @@ +import { useEffect, useMemo, useState } from 'react'; import * as themes from '../themes'; import { nicinabox as defaultDarkScheme } from 'redux-devtools-themes'; import * as baseSchemes from 'base16'; @@ -15,7 +16,7 @@ export type Scheme = keyof typeof schemes; export interface ThemeData { theme: keyof typeof themes; scheme: keyof typeof schemes; - light: boolean; + colorPreference: 'auto' | 'light' | 'dark'; } export interface ThemeFromProvider extends ThemeBase { @@ -23,11 +24,11 @@ export interface ThemeFromProvider extends ThemeBase { light: boolean; } -export const getTheme = ({ - theme: type, - scheme, - light, -}: ThemeData): ThemeFromProvider => { +const getTheme = ( + type: keyof typeof themes, + scheme: keyof typeof schemes, + light: boolean +): ThemeFromProvider => { let colors; if (scheme === 'default') { colors = light ? schemes.default : defaultDarkScheme; @@ -47,3 +48,40 @@ export const getTheme = ({ return theme; }; + +export const useTheme = ({ + theme: type, + scheme, + colorPreference, +}: ThemeData): ThemeFromProvider => { + const [prefersDarkColorScheme, setPrefersDarkColorScheme] = useState( + window.matchMedia('(prefers-color-scheme: dark)').matches + ); + + useEffect(() => { + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + + const handleChange = ({ matches }: MediaQueryListEvent) => { + if (matches && !prefersDarkColorScheme) { + setPrefersDarkColorScheme(true); + } + + if (!matches && prefersDarkColorScheme) { + setPrefersDarkColorScheme(false); + } + }; + + mediaQuery.addEventListener('change', handleChange); + return () => mediaQuery.removeEventListener('change', handleChange); + }, [prefersDarkColorScheme]); + + const light = useMemo( + () => + colorPreference === 'auto' + ? !prefersDarkColorScheme + : colorPreference === 'light', + [colorPreference, prefersDarkColorScheme] + ); + + return getTheme(type, scheme, light); +}; diff --git a/packages/redux-devtools-ui/tests/Container.test.tsx b/packages/redux-devtools-ui/tests/Container.test.tsx index fb8bb28f..50d699e8 100644 --- a/packages/redux-devtools-ui/tests/Container.test.tsx +++ b/packages/redux-devtools-ui/tests/Container.test.tsx @@ -2,11 +2,29 @@ import React from 'react'; import { render } from '@testing-library/react'; import { Container } from '../src'; +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(), + })), +}); + describe('Container', function () { it('renders correctly', () => { const { container } = render( Text diff --git a/packages/redux-devtools-ui/tests/__snapshots__/Container.test.tsx.snap b/packages/redux-devtools-ui/tests/__snapshots__/Container.test.tsx.snap index 78ccdb1d..4b1b22a3 100644 --- a/packages/redux-devtools-ui/tests/__snapshots__/Container.test.tsx.snap +++ b/packages/redux-devtools-ui/tests/__snapshots__/Container.test.tsx.snap @@ -2,7 +2,7 @@ exports[`Container renders correctly 1`] = `
Text
diff --git a/packages/redux-devtools/examples/counter/package.json b/packages/redux-devtools/examples/counter/package.json index f77579d8..3cea04c4 100644 --- a/packages/redux-devtools/examples/counter/package.json +++ b/packages/redux-devtools/examples/counter/package.json @@ -48,6 +48,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "fork-ts-checker-webpack-plugin": "^6.4.0", "html-webpack-plugin": "^5.5.0", "ts-node": "^10.4.0", diff --git a/packages/redux-devtools/examples/todomvc/package.json b/packages/redux-devtools/examples/todomvc/package.json index b1107324..802489fb 100644 --- a/packages/redux-devtools/examples/todomvc/package.json +++ b/packages/redux-devtools/examples/todomvc/package.json @@ -62,6 +62,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "fork-ts-checker-webpack-plugin": "^6.4.0", "html-webpack-plugin": "^5.5.0", "style-loader": "^3.3.1", diff --git a/packages/redux-devtools/package.json b/packages/redux-devtools/package.json index dd8bde21..82d5b03d 100644 --- a/packages/redux-devtools/package.json +++ b/packages/redux-devtools/package.json @@ -60,6 +60,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-jest": "^25.2.2", "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", "jest": "^27.3.1", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/yarn.lock b/yarn.lock index 6442ada4..18a45d46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4576,6 +4576,7 @@ __metadata: eslint-config-prettier: ^8.3.0 eslint-plugin-jest: ^25.2.2 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 file-loader: ^6.2.0 fork-ts-checker-webpack-plugin: ^6.4.0 html-loader: ^3.0.0 @@ -4634,6 +4635,7 @@ __metadata: eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 prop-types: ^15.7.2 react: ^17.0.2 redux: ^4.1.2 @@ -4730,6 +4732,7 @@ __metadata: eslint-config-prettier: ^8.3.0 eslint-plugin-jest: ^25.2.2 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 jest: ^27.3.1 lodash: ^4.17.21 prop-types: ^15.7.2 @@ -4765,6 +4768,7 @@ __metadata: eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 parse-key: ^0.2.1 prop-types: ^15.7.2 react: ^17.0.2 @@ -4829,6 +4833,7 @@ __metadata: eslint-config-prettier: ^8.3.0 eslint-plugin-jest: ^25.2.2 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 javascript-stringify: ^2.1.0 jest: ^27.3.1 jsan: ^3.1.13 @@ -4879,6 +4884,7 @@ __metadata: eslint-config-prettier: ^8.3.0 eslint-plugin-jest: ^25.2.2 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 html-entities: ^2.3.2 jest: ^27.3.1 path-browserify: ^1.0.1 @@ -4927,6 +4933,7 @@ __metadata: eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 hex-rgba: ^1.0.2 immutable: ^4.0.0 javascript-stringify: ^2.1.0 @@ -4998,6 +5005,7 @@ __metadata: eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 lodash.debounce: ^4.0.8 prop-types: ^15.7.2 react: ^17.0.2 @@ -5030,7 +5038,6 @@ __metadata: "@typescript-eslint/parser": ^5.2.0 eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 - eslint-plugin-react: ^7.26.1 jsan: ^3.1.13 querystring: ^0.2.1 redux: ^4.1.2 @@ -5065,6 +5072,7 @@ __metadata: eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 hex-rgba: ^1.0.2 immutable: ^4.0.0 jss: ^10.8.2 @@ -5132,6 +5140,7 @@ __metadata: eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 prop-types: ^15.7.2 react: ^17.0.2 redux: ^4.1.2 @@ -5182,6 +5191,7 @@ __metadata: eslint-config-prettier: ^8.3.0 eslint-plugin-jest: ^25.2.2 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 jest: ^27.3.1 prop-types: ^15.7.2 react: ^17.0.2 @@ -11807,6 +11817,7 @@ __metadata: eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 fork-ts-checker-webpack-plugin: ^6.4.0 html-webpack-plugin: ^5.5.0 prop-types: ^15.7.2 @@ -16700,6 +16711,7 @@ fsevents@^1.2.7: eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 fork-ts-checker-webpack-plugin: ^6.4.0 history: ^4.10.1 html-webpack-plugin: ^5.5.0 @@ -23744,6 +23756,7 @@ fsevents@^1.2.7: eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 fork-ts-checker-webpack-plugin: ^6.4.0 html-webpack-plugin: ^5.5.0 react: ^17.0.2 @@ -23782,6 +23795,7 @@ fsevents@^1.2.7: eslint-config-prettier: ^8.3.0 eslint-plugin-jest: ^25.2.2 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 jest: ^27.3.1 lodash.debounce: ^4.0.8 prop-types: ^15.7.2 @@ -23947,6 +23961,7 @@ fsevents@^1.2.7: eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 fork-ts-checker-webpack-plugin: ^6.4.0 html-webpack-plugin: ^5.5.0 immutable: ^4.0.0 @@ -23984,6 +23999,7 @@ fsevents@^1.2.7: eslint-config-prettier: ^8.3.0 eslint-plugin-jest: ^25.2.2 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 jest: ^27.3.1 prop-types: ^15.7.2 react: ^17.0.2 @@ -25352,6 +25368,7 @@ resolve@^2.0.0-next.3: eslint-config-prettier: ^8.3.0 eslint-plugin-jest: ^25.2.2 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 jest: ^27.3.1 lerna: ^4.0.0 prettier: 2.4.1 @@ -25400,6 +25417,7 @@ resolve@^2.0.0-next.3: eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 fork-ts-checker-webpack-plugin: ^6.4.0 framer-motion: ^4.1.17 html-webpack-plugin: ^5.5.0 @@ -26171,6 +26189,7 @@ resolve@^2.0.0-next.3: eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 fork-ts-checker-webpack-plugin: ^6.4.0 html-webpack-plugin: ^5.5.0 prop-types: ^15.7.2 @@ -27670,6 +27689,7 @@ resolve@^2.0.0-next.3: eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 fork-ts-checker-webpack-plugin: ^6.4.0 history: ^4.10.1 html-webpack-plugin: ^5.5.0 @@ -27949,6 +27969,7 @@ resolve@^2.0.0-next.3: eslint: ^7.32.0 eslint-config-prettier: ^8.3.0 eslint-plugin-react: ^7.26.1 + eslint-plugin-react-hooks: ^4.2.0 fork-ts-checker-webpack-plugin: ^6.4.0 html-webpack-plugin: ^5.5.0 prop-types: ^15.7.2