From 8bc533dedee49e578495d3632edc843cdb3c9093 Mon Sep 17 00:00:00 2001 From: Joel Anton Date: Wed, 15 May 2024 14:28:59 -0700 Subject: [PATCH] feat: Color scheme util --- .../src/color-scheme/getColorScheme.ts | 31 +++++++++++++++++++ .../color-scheme/getColorSchemeHtmlElement.ts | 14 +++++++++ libs/design-system/src/color-scheme/index.ts | 1 + .../src/color-scheme/useColorScheme.ts | 8 +++-- 4 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 libs/design-system/src/color-scheme/getColorScheme.ts create mode 100644 libs/design-system/src/color-scheme/getColorSchemeHtmlElement.ts diff --git a/libs/design-system/src/color-scheme/getColorScheme.ts b/libs/design-system/src/color-scheme/getColorScheme.ts new file mode 100644 index 00000000000..25a20f25cd4 --- /dev/null +++ b/libs/design-system/src/color-scheme/getColorScheme.ts @@ -0,0 +1,31 @@ +import { ColorScheme } from './ColorScheme'; +import { getColorSchemeHtmlElement } from './getColorSchemeHtmlElement'; + +const DEFAULT_COLOR_SCHEME: ColorScheme = 'light'; + +/** + * Gets the user's preferred color scheme according to their browser settings. + * @returns ColorScheme + */ +export const getBrowserColorScheme = (): ColorScheme => { + return window?.matchMedia?.(`(prefers-color-scheme: dark)`)?.matches ? 'dark' : DEFAULT_COLOR_SCHEME; +}; + +/** + * Get the current color scheme of the application based on the application html. + * @returns ColorScheme + */ +export const getCurrentColorScheme = (): ColorScheme => { + const htmlElem = getColorSchemeHtmlElement(); + + // fallback to browser preferences if there isn't an html element + if (!htmlElem?.classList) { + return getBrowserColorScheme(); + } + + return htmlElem.classList.contains('dark') + ? 'dark' + : htmlElem.classList.contains('light') + ? 'light' + : DEFAULT_COLOR_SCHEME; +}; diff --git a/libs/design-system/src/color-scheme/getColorSchemeHtmlElement.ts b/libs/design-system/src/color-scheme/getColorSchemeHtmlElement.ts new file mode 100644 index 00000000000..d6d719eb244 --- /dev/null +++ b/libs/design-system/src/color-scheme/getColorSchemeHtmlElement.ts @@ -0,0 +1,14 @@ +/** Get the innermost element that serves as the basis for our theme */ +export const getColorSchemeHtmlElement = (): HTMLHtmlElement | null => { + /** + * Avoid issues with multiple `html` elements (like in Storybook) by getting all html elements + * and taking the innermost one + */ + const htmlElements = document.querySelectorAll('html'); + + if (!htmlElements?.length) { + return null; + } + + return htmlElements.item(htmlElements.length - 1); +}; diff --git a/libs/design-system/src/color-scheme/index.ts b/libs/design-system/src/color-scheme/index.ts index 7841a642b54..23f2f63bd47 100644 --- a/libs/design-system/src/color-scheme/index.ts +++ b/libs/design-system/src/color-scheme/index.ts @@ -1,3 +1,4 @@ export * from './ColorScheme'; export * from './mapThemeStatusToColorScheme'; export * from './useColorScheme'; +export * from './getColorScheme'; diff --git a/libs/design-system/src/color-scheme/useColorScheme.ts b/libs/design-system/src/color-scheme/useColorScheme.ts index 6953303214c..820a9f3397d 100644 --- a/libs/design-system/src/color-scheme/useColorScheme.ts +++ b/libs/design-system/src/color-scheme/useColorScheme.ts @@ -3,6 +3,7 @@ import { useLocalThemePreference, ColorSchemePreferenceEnum } from '@novu/shared import { useColorScheme as useMantineColorScheme } from '@mantine/hooks'; import { ColorScheme } from './ColorScheme'; import { mapThemeStatusToColorScheme } from './mapThemeStatusToColorScheme'; +import { getColorSchemeHtmlElement } from './getColorSchemeHtmlElement'; /** * Handle behavior for changing ColorSchemes or ThemeStatuses @@ -14,9 +15,10 @@ export const useColorScheme = () => { const setColorScheme = useCallback( (newColorScheme: ColorScheme) => { - // avoid issues with multiple `html` elements (like in Storybook) - const htmlElements = document.querySelectorAll('html'); - const htmlElem = htmlElements.item(htmlElements.length - 1); + const htmlElem = getColorSchemeHtmlElement(); + if (!htmlElem) { + return; + } htmlElem.className = newColorScheme; _setColorScheme(newColorScheme);