File size: 1,898 Bytes
e1cc3bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import { useEffect, useState } from "react";
import { getDocumentTheme } from "../styles";
import { McpUiTheme } from "../types";

/**
 * React hook that provides the current document theme reactively.
 *
 * Uses a `MutationObserver` to watch for changes to the `data-theme` attribute
 * or `class` on `document.documentElement`. When the theme changes (e.g., from
 * host context updates), the hook automatically re-renders your component with
 * the new theme value.
 *
 * The `MutationObserver` is automatically disconnected when the component unmounts.
 *
 * @returns The current theme ("light" or "dark")
 *
 * @example Conditionally render based on theme
 * ```tsx
 * import { useDocumentTheme } from '@modelcontextprotocol/ext-apps/react';
 *
 * function MyApp() {
 *   const theme = useDocumentTheme();
 *
 *   return (
 *     <div>
 *       {theme === 'dark' ? <DarkIcon /> : <LightIcon />}
 *     </div>
 *   );
 * }
 * ```
 *
 * @example Use with theme-aware styling
 * ```tsx
 * function ThemedButton() {
 *   const theme = useDocumentTheme();
 *
 *   return (
 *     <button style={{
 *       background: theme === 'dark' ? '#333' : '#fff',
 *       color: theme === 'dark' ? '#fff' : '#333',
 *     }}>
 *       Click me
 *     </button>
 *   );
 * }
 * ```
 *
 * @see {@link getDocumentTheme} for the underlying function
 * @see {@link applyDocumentTheme} to set the theme
 */
export function useDocumentTheme(): McpUiTheme {
  const [theme, setTheme] = useState<McpUiTheme>(getDocumentTheme);

  useEffect(() => {
    const observer = new MutationObserver(() => {
      setTheme(getDocumentTheme());
    });

    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["data-theme", "class"],
      characterData: false,
      childList: false,
      subtree: false,
    });

    return () => observer.disconnect();
  }, []);

  return theme;
}