Add utility to set + read theme
This commit is contained in:
parent
aa8968808a
commit
a8b3bf0ccd
1 changed files with 150 additions and 2 deletions
69
src/react/useDocumentTheme.ts
Normal file
69
src/react/useDocumentTheme.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
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.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
Loading…
Reference in a new issue