useHandleAppTheme.ts 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import { THEME } from "@excalidraw/excalidraw";
  2. import { EVENT, CODES, KEYS } from "@excalidraw/common";
  3. import { useEffect, useLayoutEffect, useState } from "react";
  4. import type { Theme } from "@excalidraw/element/types";
  5. import { STORAGE_KEYS } from "./app_constants";
  6. const getDarkThemeMediaQuery = (): MediaQueryList | undefined =>
  7. window.matchMedia?.("(prefers-color-scheme: dark)");
  8. export const useHandleAppTheme = () => {
  9. const [appTheme, setAppTheme] = useState<Theme | "system">(() => {
  10. return (
  11. (localStorage.getItem(STORAGE_KEYS.LOCAL_STORAGE_THEME) as
  12. | Theme
  13. | "system"
  14. | null) || THEME.LIGHT
  15. );
  16. });
  17. const [editorTheme, setEditorTheme] = useState<Theme>(THEME.LIGHT);
  18. useEffect(() => {
  19. const mediaQuery = getDarkThemeMediaQuery();
  20. const handleChange = (e: MediaQueryListEvent) => {
  21. setEditorTheme(e.matches ? THEME.DARK : THEME.LIGHT);
  22. };
  23. if (appTheme === "system") {
  24. mediaQuery?.addEventListener("change", handleChange);
  25. }
  26. const handleKeydown = (event: KeyboardEvent) => {
  27. if (
  28. !event[KEYS.CTRL_OR_CMD] &&
  29. event.altKey &&
  30. event.shiftKey &&
  31. event.code === CODES.D
  32. ) {
  33. event.preventDefault();
  34. event.stopImmediatePropagation();
  35. setAppTheme(editorTheme === THEME.DARK ? THEME.LIGHT : THEME.DARK);
  36. }
  37. };
  38. document.addEventListener(EVENT.KEYDOWN, handleKeydown, { capture: true });
  39. return () => {
  40. mediaQuery?.removeEventListener("change", handleChange);
  41. document.removeEventListener(EVENT.KEYDOWN, handleKeydown, {
  42. capture: true,
  43. });
  44. };
  45. }, [appTheme, editorTheme, setAppTheme]);
  46. useLayoutEffect(() => {
  47. localStorage.setItem(STORAGE_KEYS.LOCAL_STORAGE_THEME, appTheme);
  48. if (appTheme === "system") {
  49. setEditorTheme(
  50. getDarkThemeMediaQuery()?.matches ? THEME.DARK : THEME.LIGHT,
  51. );
  52. } else {
  53. setEditorTheme(appTheme);
  54. }
  55. }, [appTheme]);
  56. return { editorTheme, appTheme, setAppTheme };
  57. };