// // Copyright 2022 DXOS.org // import { createKeyborg } from 'keyborg'; import React, { createContext, type PropsWithChildren, useEffect, useMemo } from 'react'; import { type Density, type Elevation, type ThemeFunction } from '@dxos/react-ui-types'; import { TranslationsProvider, type TranslationsProviderProps } from './TranslationsProvider'; import { type SafeAreaPadding, useSafeArea } from '../../hooks'; import { hasIosKeyboard } from '../../util'; import { DensityProvider } from '../DensityProvider'; import { ElevationProvider } from '../ElevationProvider'; export type ThemeMode = 'light' | 'dark'; export type ThemeContextValue = { tx: ThemeFunction; themeMode: ThemeMode; hasIosKeyboard: boolean; safeAreaPadding?: SafeAreaPadding; noCache?: boolean; }; /** * @internal */ export const ThemeContext = createContext(undefined); export type ThemeProviderProps = Omit & Partial> & PropsWithChildren<{ rootDensity?: Density; rootElevation?: Elevation; }>; export const ThemeProvider = ({ children, fallback = null, resourceExtensions, appNs, tx = (_path, defaultClassName, _styleProps, ..._options) => defaultClassName, themeMode = 'dark', rootDensity = 'fine', ...rest }: ThemeProviderProps) => { useEffect(() => { if (document.defaultView) { const kb = createKeyborg(document.defaultView); kb.subscribe(handleInputModalityChange); return () => kb.unsubscribe(handleInputModalityChange); } }, []); const safeAreaPadding = useSafeArea(); const contextValue = useMemo( () => ({ tx, themeMode, hasIosKeyboard: hasIosKeyboard(), safeAreaPadding, ...rest }), [tx, themeMode, safeAreaPadding, rest], ); return ( {children} ); }; const handleInputModalityChange = (isUsingKeyboard: boolean) => { if (isUsingKeyboard) { document.body.setAttribute('data-is-keyboard', 'true'); } else { document.body.removeAttribute('data-is-keyboard'); } };