diff --git a/packages/client/src/components/theme/index.tsx b/packages/client/src/components/theme/index.tsx index 272a6c03..88f3e9f4 100644 --- a/packages/client/src/components/theme/index.tsx +++ b/packages/client/src/components/theme/index.tsx @@ -1,11 +1,11 @@ import { IconMoon, IconSun } from '@douyinfe/semi-icons'; import { Button } from '@douyinfe/semi-ui'; import { Tooltip } from 'components/tooltip'; -import { useTheme } from 'hooks/use-theme'; +import { Theme as ThemeState } from 'hooks/use-theme'; import React from 'react'; export const Theme = () => { - const { theme, toggle } = useTheme(); + const { theme, toggle } = ThemeState.useHook(); const Icon = theme === 'dark' ? IconSun : IconMoon; const text = theme === 'dark' ? '切换到亮色模式' : '切换到深色模式'; diff --git a/packages/client/src/hooks/create-global-hook.tsx b/packages/client/src/hooks/create-global-hook.tsx new file mode 100644 index 00000000..bdbc9c96 --- /dev/null +++ b/packages/client/src/hooks/create-global-hook.tsx @@ -0,0 +1,33 @@ +import React, { createContext, useContext } from 'react'; + +const EMPTY = Symbol(); + +export interface ContainerProviderProps { + initialState?: State; + children: React.ReactNode; +} + +interface GlobalHook { + Provider: React.ComponentType>; + useHook: () => Value; +} + +export function createGlobalHook(hook): GlobalHook { + const Context = createContext(EMPTY); + + function Provider(props) { + const value = hook(props.initialState); + + return {props.children}; + } + + function useHook() { + const value = useContext(Context); + if (value === EMPTY) { + throw new Error('You forget to wrap component with'); + } + return value; + } + + return { Provider, useHook }; +} diff --git a/packages/client/src/hooks/use-theme.tsx b/packages/client/src/hooks/use-theme.tsx index 93cf5432..573d9382 100644 --- a/packages/client/src/hooks/use-theme.tsx +++ b/packages/client/src/hooks/use-theme.tsx @@ -1,15 +1,17 @@ import { useCallback, useEffect, useState } from 'react'; -export enum Theme { +import { createGlobalHook } from './create-global-hook'; + +export enum ThemeEnum { 'dark' = 'dark', 'light' = 'light', } -export const useTheme = () => { - const [theme, setTheme] = useState(Theme.light); +const useThemeHook = () => { + const [theme, setTheme] = useState(ThemeEnum.light); const toggle = useCallback(() => { - const nextTheme = theme === 'dark' ? Theme.light : Theme.dark; + const nextTheme = theme === 'dark' ? ThemeEnum.light : ThemeEnum.dark; setTheme(nextTheme); }, [theme]); @@ -30,14 +32,18 @@ export const useTheme = () => { function matchMode(e) { if (e.matches) { - setTheme(Theme.dark); + setTheme(ThemeEnum.dark); } else { - setTheme(Theme.light); + setTheme(ThemeEnum.light); } } matchMode(mql); mql.addEventListener('change', matchMode); + + return () => { + mql.removeEventListener('change', matchMode); + }; }, []); return { @@ -45,3 +51,5 @@ export const useTheme = () => { toggle, }; }; + +export const Theme = createGlobalHook<{ theme: ThemeEnum; toggle: () => void }>(useThemeHook); diff --git a/packages/client/src/pages/_app.tsx b/packages/client/src/pages/_app.tsx index f6a81ec1..af6aa997 100644 --- a/packages/client/src/pages/_app.tsx +++ b/packages/client/src/pages/_app.tsx @@ -3,20 +3,20 @@ import 'viewerjs/dist/viewer.css'; import 'styles/globals.scss'; import 'tiptap/core/styles/index.scss'; -import { useTheme } from 'hooks/use-theme'; +import { Theme } from 'hooks/use-theme'; import type { AppProps } from 'next/app'; import Head from 'next/head'; import React from 'react'; function MyApp({ Component, pageProps }: AppProps) { - useTheme(); - return ( <> - + + + ); } diff --git a/packages/client/src/tiptap/core/wrappers/callout/index.tsx b/packages/client/src/tiptap/core/wrappers/callout/index.tsx index 97e3b274..684fc364 100644 --- a/packages/client/src/tiptap/core/wrappers/callout/index.tsx +++ b/packages/client/src/tiptap/core/wrappers/callout/index.tsx @@ -2,7 +2,7 @@ import { NodeViewContent, NodeViewWrapper } from '@tiptap/react'; import cls from 'classnames'; import { EmojiPicker } from 'components/emoji-picker'; import { convertColorToRGBA } from 'helpers/color'; -import { Theme, useTheme } from 'hooks/use-theme'; +import { Theme, ThemeEnum } from 'hooks/use-theme'; import { useCallback, useMemo } from 'react'; import styles from './index.module.scss'; @@ -10,10 +10,10 @@ import styles from './index.module.scss'; export const CalloutWrapper = ({ editor, node, updateAttributes }) => { const { isEditable } = editor; const { emoji, textColor, borderColor, backgroundColor } = node.attrs; - const { theme } = useTheme(); + const { theme } = Theme.useHook(); const backgroundColorOpacity = useMemo(() => { if (!backgroundColor) return backgroundColor; - if (theme === Theme.dark) return convertColorToRGBA(backgroundColor, 0.85); + if (theme === ThemeEnum.dark) return convertColorToRGBA(backgroundColor, 0.75); return backgroundColor; }, [backgroundColor, theme]);