@@ -521,19 +628,6 @@ export function ThemeProvider({
/**
* Hook to access theme context
- *
- * @example
- * ```tsx
- * function MyComponent() {
- * const { mode, setMode, tokens, pluginId } = useTheme();
- *
- * return (
- *
- * );
- * }
- * ```
*/
export function useTheme(): ThemeContextValue {
const context = useContext(ThemeContext);
@@ -546,16 +640,29 @@ export function useTheme(): ThemeContextValue {
}
/**
- * Hook to check if component is within a ThemeProvider
+ * Hook to check if component is within a ThemeProvider.
+ * If not, falls back to the most recently registered global theme,
+ * or the default light theme if none exists.
*/
-export function useThemeOptional(): ThemeContextValue | null {
- return useContext(ThemeContext);
-}
+export function useThemeOptional(): ThemeContextValue {
+ const context = useContext(ThemeContext);
+ const [fallbackContext, setFallbackContext] = useState(
+ () => getGlobalTheme() ?? DEFAULT_CONTEXT,
+ );
-/**
- * Pre-computed default light CSS variables for use in portals outside ThemeProvider.
- */
-export const defaultCssVariables: Record =
- tokensToCssVariables(defaultLightTokens);
+ useEffect(() => {
+ // If we have a local context, we don't need the global fallback.
+ if (context) return;
+
+ // Sync immediately in case a provider registered between render and effect,
+ // then subscribe to subsequent global theme changes.
+ setFallbackContext(getGlobalTheme() ?? DEFAULT_CONTEXT);
+ return subscribeToGlobalTheme((newContext) => {
+ setFallbackContext(newContext ?? DEFAULT_CONTEXT);
+ });
+ }, [context]);
+
+ return context ?? fallbackContext;
+}
export default ThemeProvider;