From 04c87f44ad2232314ad656e6ce3a94fa64c42880 Mon Sep 17 00:00:00 2001 From: Cody Olsen Date: Fri, 13 Dec 2024 20:14:21 +0100 Subject: [PATCH] fix: improve color scheme store perf --- package.json | 2 +- .../sanity/src/core/studio/colorScheme.tsx | 51 ++++--------------- .../src/core/studio/colorSchemeStore.ts | 39 ++++++++++++++ 3 files changed, 51 insertions(+), 41 deletions(-) create mode 100644 packages/sanity/src/core/studio/colorSchemeStore.ts diff --git a/package.json b/package.json index d4f0647e844..f86b98bd3ec 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "check:deps": "pnpm --recursive --parallel exec depcheck", "check:format": "prettier . --check", "check:lint": "turbo run lint --continue -- --quiet", - "check:react-compiler": "eslint --cache --no-inline-config --no-eslintrc --ext .cjs,.mjs,.js,.jsx,.ts,.tsx --parser @typescript-eslint/parser --plugin react-compiler --rule 'react-compiler/react-compiler: [warn]' --ignore-path .eslintignore.react-compiler --max-warnings 77 .", + "check:react-compiler": "eslint --cache --no-inline-config --no-eslintrc --ext .cjs,.mjs,.js,.jsx,.ts,.tsx --parser @typescript-eslint/parser --plugin react-compiler --rule 'react-compiler/react-compiler: [warn]' --ignore-path .eslintignore.react-compiler --max-warnings 76 .", "report:react-compiler-bailout": "eslint --cache --no-inline-config --no-eslintrc --ext .cjs,.mjs,.js,.jsx,.ts,.tsx --parser @typescript-eslint/parser --plugin react-compiler --rule 'react-compiler/react-compiler: [error,{__unstable_donotuse_reportAllBailouts:true}]' --ignore-path .eslintignore.react-compiler -f ./scripts/reactCompilerBailouts.cjs . || true", "check:test": "run-s test -- --silent", "check:types": "tsc && turbo run check:types --filter='./packages/*' --filter='./packages/@sanity/*'", diff --git a/packages/sanity/src/core/studio/colorScheme.tsx b/packages/sanity/src/core/studio/colorScheme.tsx index c9ebcef0b37..c37fd87902d 100644 --- a/packages/sanity/src/core/studio/colorScheme.tsx +++ b/packages/sanity/src/core/studio/colorScheme.tsx @@ -12,6 +12,7 @@ import {ColorSchemeSetValueContext, ColorSchemeValueContext} from 'sanity/_singl import {type TFunction} from '../i18n' import {type StudioThemeColorSchemeKey} from '../theme/types' +import {getSnapshot, setSnapshot, subscribe} from './colorSchemeStore' /** @internal */ function useSystemScheme(): ThemeColorSchemeKey { @@ -78,33 +79,13 @@ export function ColorSchemeLocalStorageProvider({ children, onSchemeChange, }: Pick) { - const store = useMemo(() => { - let snapshot: StudioThemeColorSchemeKey - const subscribers = new Set<() => void>() - - return { - subscribe: (onStoreChange: () => void) => { - if (!snapshot) { - snapshot = getScheme(localStorage.getItem(LOCAL_STORAGE_KEY)) || 'system' - } - subscribers.add(onStoreChange) - return () => { - subscribers.delete(onStoreChange) - } - }, - getSnapshot: () => snapshot, - setSnapshot: (nextScheme: StudioThemeColorSchemeKey) => { - snapshot = getScheme(nextScheme) - for (const subscription of subscribers) { - subscription() - } - }, - // Only called during server-side rendering, and hydration if using hydrateRoot - // https://beta.reactjs.org/apis/react/useSyncExternalStore#adding-support-for-server-rendering - getServerSnapshot: () => 'system', - } - }, []) - const scheme = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getServerSnapshot) + const scheme = useSyncExternalStore( + subscribe, + getSnapshot, + // Only called during server-side rendering, and hydration if using hydrateRoot + // https://beta.reactjs.org/apis/react/useSyncExternalStore#adding-support-for-server-rendering + () => 'system', + ) useEffect(() => { if (typeof onSchemeChange === 'function') { @@ -114,7 +95,7 @@ export function ColorSchemeLocalStorageProvider({ }, [onSchemeChange, scheme]) return ( - + {children} @@ -122,16 +103,6 @@ export function ColorSchemeLocalStorageProvider({ ) } -function getScheme(scheme: unknown): StudioThemeColorSchemeKey { - switch (scheme) { - case 'dark': - case 'light': - return scheme - default: - return 'system' - } -} - /** * If the `scheme` prop is provided we don't need to setup any logic to handle localStorage * @internal @@ -210,7 +181,7 @@ export function useColorSchemeOptions( ) { const scheme = useColorSchemeInternalValue() - return useMemo(() => { + return useMemo(() => { return [ { title: t('user-menu.color-scheme.system-title'), @@ -236,6 +207,6 @@ export function useColorSchemeOptions( onSelect: () => setScheme('light'), icon: SunIcon, }, - ] satisfies ColorSchemeOption[] + ] }, [scheme, setScheme, t]) } diff --git a/packages/sanity/src/core/studio/colorSchemeStore.ts b/packages/sanity/src/core/studio/colorSchemeStore.ts new file mode 100644 index 00000000000..e3e56cf4514 --- /dev/null +++ b/packages/sanity/src/core/studio/colorSchemeStore.ts @@ -0,0 +1,39 @@ +import {type StudioThemeColorSchemeKey} from '../theme/types' + +function getScheme(scheme: unknown): StudioThemeColorSchemeKey { + switch (scheme) { + case 'dark': + case 'light': + return scheme + default: + return 'system' + } +} + +/** @internal */ +export const LOCAL_STORAGE_KEY = 'sanityStudio:ui:colorScheme' + +let snapshot: StudioThemeColorSchemeKey +const subscribers = new Set<() => void>() + +/** @internal */ +export const subscribe = (onStoreChange: () => void) => { + if (!snapshot) { + snapshot = getScheme(localStorage.getItem(LOCAL_STORAGE_KEY)) || 'system' + } + subscribers.add(onStoreChange) + return (): void => { + subscribers.delete(onStoreChange) + } +} +/** @internal */ +export function getSnapshot(): StudioThemeColorSchemeKey { + return snapshot +} +/** @internal */ +export function setSnapshot(nextScheme: StudioThemeColorSchemeKey): void { + snapshot = getScheme(nextScheme) + for (const subscription of subscribers) { + subscription() + } +}