@mcp-apps-kit/ui-react
Advanced tools
+1
-1
@@ -1,2 +0,2 @@ | ||
| 'use strict';var react=require('react'),ui=require('@mcp-apps-kit/ui'),jsxRuntime=require('react/jsx-runtime');var T=react.createContext(null);function D({children:e,client:t,forceAdapter:o,fallback:s,errorFallback:r}){let[n,i]=react.useState(t??null),[a,p]=react.useState(!t),[g,C]=react.useState(null);if(react.useEffect(()=>{if(t){i(t),p(false);return}(async()=>{try{let b=await ui.createClient({forceAdapter:o});i(b),p(!1);}catch(b){C(b instanceof Error?b:new Error(String(b))),p(false);}})();},[t,o]),g&&r)return jsxRuntime.jsx(r,{error:g,reset:()=>C(null)});if(a)return jsxRuntime.jsx(jsxRuntime.Fragment,{children:s??null});let S={client:n,isConnecting:a,error:g};return jsxRuntime.jsx(T.Provider,{value:S,children:e})}function l(){let e=react.useContext(T);if(!e)throw new Error("useAppsContext must be used within an AppsProvider");return e}function M(){let{client:e,isConnecting:t,error:o}=l();if(o)throw o;if(t||!e)throw new Error("Client not ready. Make sure AppsProvider has finished connecting.");return e}function I(){let{client:e}=l(),[t,o]=react.useState(void 0);return react.useEffect(()=>{if(!e)return;let s=e.toolOutput;return s&&Object.keys(s).length>0&&o(s),e.onToolResult(n=>{o(n);})},[e]),t}function U(){let{client:e}=l(),[t,o]=react.useState(e?.toolInput);return react.useEffect(()=>e?e.onToolInput(r=>{o(r);}):void 0,[e]),t}function f(){let{client:e}=l(),[t,o]=react.useState(e?.hostContext??{theme:"light",displayMode:"inline",availableDisplayModes:["inline"],viewport:{width:0,height:0},locale:"en-US",platform:"web"});return react.useEffect(()=>e?(o(e.hostContext),e.onHostContextChange(r=>{o(r);})):void 0,[e]),t}function P(e){let{client:t}=l(),[o,s]=react.useState(()=>t?t.getState()??e:e),r=react.useCallback(n=>{s(i=>{let a=typeof n=="function"?n(i):n;return t?.setState(a),a});},[t]);return [o,r]}function E(){let e=f();react.useEffect(()=>{let t=e.styles?.variables;if(!t)return;let o=document.documentElement;for(let[s,r]of Object.entries(t))o.style.setProperty(s,r);return ()=>{for(let s of Object.keys(t))o.style.removeProperty(s);}},[e.styles?.variables]);}function F(e="light",t="dark"){let o=f();react.useEffect(()=>{let{theme:s}=o,r=document.body;return r.classList.remove(e,t),r.classList.add(s==="dark"?t:e),()=>{r.classList.remove(e,t);}},[o.theme,e,t]);}function O(){let e=f(),{client:t}=l(),o=react.useCallback(async s=>{await t?.requestDisplayMode(s);},[t]);return {mode:e.displayMode,availableModes:e.availableDisplayModes,requestMode:o}}function L(){return f().safeAreaInsets??{top:0,right:0,bottom:0,left:0}}function V(e){let{client:t}=l();react.useEffect(()=>t?t.onToolCancelled(e):void 0,[t,e]);}function k(e){let{client:t}=l();react.useEffect(()=>t?t.onTeardown(e):void 0,[t,e]);}function z(e){let{client:t}=l();react.useEffect(()=>t?t.onToolInputPartial(e):void 0,[t,e]);}function q(){let{client:e}=l(),[t,o]=react.useState(e?.getHostCapabilities());return react.useEffect(()=>{e&&o(e.getHostCapabilities());},[e]),t}function N(){let{client:e}=l(),[t,o]=react.useState(e?.getHostVersion());return react.useEffect(()=>{e&&o(e.getHostVersion());},[e]),t}function j(){let{client:e}=l(),t=react.useRef(null);return react.useEffect(()=>{if(!e||typeof ResizeObserver>"u")return;let o=t.current;if(!o)return;let s=new ResizeObserver(n=>{for(let i of n){let{width:a,height:p}=i.contentRect;e.sendSizeChanged({width:Math.round(a),height:Math.round(p)});}});s.observe(o);let r=o.getBoundingClientRect();return e.sendSizeChanged({width:Math.round(r.width),height:Math.round(r.height)}),()=>s.disconnect()},[e]),t}function B(){let{client:e}=l(),[t,o]=react.useState({isSupported:false,isUploading:false,error:null,fileId:null});react.useEffect(()=>{o(r=>({...r,isSupported:!!e?.uploadFile}));},[e]);let s=react.useCallback(async r=>{if(!e?.uploadFile)return o(n=>({...n,error:new Error("File upload not supported on this platform")})),null;o(n=>({...n,isUploading:true,error:null}));try{let n=await e.uploadFile(r);return o(i=>({...i,isUploading:!1,fileId:n.fileId})),n}catch(n){let i=n instanceof Error?n:new Error(String(n));return o(a=>({...a,isUploading:false,error:i})),null}},[e]);return {...t,upload:s}}function W(){let{client:e}=l(),[t,o]=react.useState({isSupported:false,isLoading:false,error:null,downloadUrl:null});react.useEffect(()=>{o(r=>({...r,isSupported:!!e?.getFileDownloadUrl}));},[e]);let s=react.useCallback(async r=>{if(!e?.getFileDownloadUrl)return o(n=>({...n,error:new Error("File download not supported on this platform")})),null;o(n=>({...n,isLoading:true,error:null}));try{let n=await e.getFileDownloadUrl(r);return o(i=>({...i,isLoading:!1,downloadUrl:n.downloadUrl})),n.downloadUrl}catch(n){let i=n instanceof Error?n:new Error(String(n));return o(a=>({...a,isLoading:false,error:i})),null}},[e]);return {...t,getDownloadUrl:s}}function J(){let{client:e}=l(),t=react.useRef(null),[o,s]=react.useState(false);react.useEffect(()=>{s(!!e?.notifyIntrinsicHeight);},[e]);let r=react.useCallback(n=>{e?.notifyIntrinsicHeight?.(n);},[e]);return react.useEffect(()=>{if(!e?.notifyIntrinsicHeight||!t.current)return;let n=t.current,i=new ResizeObserver(a=>{for(let p of a){let g=p.contentRect.height;e.notifyIntrinsicHeight?.(g);}});return i.observe(n),e.notifyIntrinsicHeight(n.offsetHeight),()=>i.disconnect()},[e]),{isSupported:o,containerRef:t,notify:r}}function X(){return f().view}function G(){let{client:e}=l(),[t,o]=react.useState(false),[s,r]=react.useState(false);react.useEffect(()=>{o(!!e?.requestModal);},[e]);let n=react.useCallback(async i=>{if(!e?.requestModal)return null;r(true);try{return await e.requestModal(i)}finally{r(false);}},[e]);return {isSupported:t,isOpen:s,showModal:n}}function K(e){return l(),react.useEffect(()=>{e&&ui.clientDebugLogger.configure(e);},[e]),ui.clientDebugLogger}exports.AppsProvider=D;exports.useAppsClient=M;exports.useAppsContext=l;exports.useDebugLogger=K;exports.useDisplayMode=O;exports.useDocumentTheme=F;exports.useFileDownload=W;exports.useFileUpload=B;exports.useHostCapabilities=q;exports.useHostContext=f;exports.useHostStyleVariables=E;exports.useHostVersion=N;exports.useIntrinsicHeight=J;exports.useModal=G;exports.useOnTeardown=k;exports.useOnToolCancelled=V;exports.useOnToolInputPartial=z;exports.useSafeAreaInsets=L;exports.useSizeChangedNotifications=j;exports.useToolInput=U;exports.useToolResult=I;exports.useView=X;exports.useWidgetState=P;//# sourceMappingURL=index.cjs.map | ||
| 'use strict';var react=require('react'),ui=require('@mcp-apps-kit/ui'),jsxRuntime=require('react/jsx-runtime');var h=react.createContext(null);function M({children:e,client:t,forceAdapter:n,autoResize:o,fallback:r,errorFallback:s}){let[p,a]=react.useState(t??null),[f,d]=react.useState(!t),[l,y]=react.useState(null);if(react.useEffect(()=>{if(t){a(t),d(false);return}(async()=>{try{let m=await ui.createClient({forceAdapter:n,autoResize:o});a(m),d(!1);}catch(m){y(m instanceof Error?m:new Error(String(m))),d(false);}})();},[t,n]),l&&s)return jsxRuntime.jsx(s,{error:l,reset:()=>y(null)});if(f)return jsxRuntime.jsx(jsxRuntime.Fragment,{children:r??null});let v={client:p,isConnecting:f,error:l};return jsxRuntime.jsx(h.Provider,{value:v,children:e})}function i(){let e=react.useContext(h);if(!e)throw new Error("useAppsContext must be used within an AppsProvider");return e}var I={theme:"light",displayMode:"inline",availableDisplayModes:["inline"],viewport:{width:0,height:0},locale:"en-US",platform:"web"},O={top:0,right:0,bottom:0,left:0};function w(e,t){let n=new ResizeObserver(r=>{for(let s of r){let{width:p,height:a}=s.contentRect;t(Math.round(p),Math.round(a));}});n.observe(e);let o=e.getBoundingClientRect();return t(Math.round(o.width),Math.round(o.height)),n}function U(){let{client:e,isConnecting:t,error:n}=i();if(n)throw n;if(t||!e)throw new Error("Client not ready. Make sure AppsProvider has finished connecting.");return e}function P(){let{client:e}=i(),[t,n]=react.useState(void 0);return react.useEffect(()=>{if(!e)return;let o=e.toolOutput;return o&&Object.keys(o).length>0&&n(o),e.onToolResult(s=>{n(s);})},[e]),t}function F(){let{client:e}=i(),[t,n]=react.useState(e?.toolInput);return react.useEffect(()=>e?e.onToolInput(r=>{n(r);}):void 0,[e]),t}function b(){let{client:e}=i(),[t,n]=react.useState(e?.hostContext??I);return react.useEffect(()=>{if(e)return n(e.hostContext),e.onHostContextChange(n)},[e]),t}function L(e){let{client:t}=i(),[n,o]=react.useState(()=>t?t.getState()??e:e),r=react.useCallback(s=>{o(p=>{let a=typeof s=="function"?s(p):s;return t?.setState(a),a});},[t]);return [n,r]}function V(){let e=b();react.useEffect(()=>{let t=e.styles?.variables;if(!t)return;let n=document.documentElement;for(let[o,r]of Object.entries(t))n.style.setProperty(o,r);return ()=>{for(let o of Object.keys(t))n.style.removeProperty(o);}},[e.styles?.variables]);}function k(e="light",t="dark"){let n=b();react.useEffect(()=>{let{theme:o}=n,r=document.body;return r.classList.remove(e,t),r.classList.add(o==="dark"?t:e),()=>{r.classList.remove(e,t);}},[n.theme,e,t]);}function z(){let e=b(),{client:t}=i(),n=react.useCallback(async o=>{await t?.requestDisplayMode(o);},[t]);return {mode:e.displayMode,availableModes:e.availableDisplayModes,requestMode:n}}function N(){return b().safeAreaInsets??O}function q(e){let{client:t}=i(),n=react.useRef(e);react.useEffect(()=>{n.current=e;},[e]),react.useEffect(()=>{if(t)return t.onToolCancelled(o=>n.current(o))},[t]);}function j(e){let{client:t}=i(),n=react.useRef(e);react.useEffect(()=>{n.current=e;},[e]),react.useEffect(()=>{if(t)return t.onTeardown(o=>n.current(o))},[t]);}function X(e){let{client:t}=i(),n=react.useRef(e);react.useEffect(()=>{n.current=e;},[e]),react.useEffect(()=>{if(t)return t.onToolInputPartial(o=>n.current(o))},[t]);}function _(){let{client:e}=i(),[t,n]=react.useState(e?.getHostCapabilities());return react.useEffect(()=>{if(!e){n(void 0);return}return n(e.getHostCapabilities()),e.onHostContextChange(()=>n(e.getHostCapabilities()))},[e]),t}function B(){let{client:e}=i(),[t,n]=react.useState(()=>e?.getHostVersion());return react.useEffect(()=>{if(!e){n(void 0);return}n(e.getHostVersion());},[e]),t}function J(){let{client:e}=i(),t=react.useRef(null);return react.useEffect(()=>{let n=t.current;if(!e||!n||typeof ResizeObserver>"u")return;let o=w(n,(r,s)=>{e.sendSizeChanged({width:r,height:s});});return ()=>o.disconnect()},[e]),t}function W(){let{client:e}=i(),t=!!e?.uploadFile,[n,o]=react.useState(false),[r,s]=react.useState(null),[p,a]=react.useState(null),f=react.useCallback(async d=>{if(!e?.uploadFile)return s(new Error("File upload not supported on this platform")),null;o(true),s(null);try{let l=await e.uploadFile(d);return a(l.fileId),l}catch(l){return s(l instanceof Error?l:new Error(String(l))),null}finally{o(false);}},[e]);return {isSupported:t,isUploading:n,error:r,fileId:p,upload:f}}function G(){let{client:e}=i(),t=!!e?.getFileDownloadUrl,[n,o]=react.useState(false),[r,s]=react.useState(null),[p,a]=react.useState(null),f=react.useCallback(async d=>{if(!e?.getFileDownloadUrl)return s(new Error("File download not supported on this platform")),null;o(true),s(null);try{let l=await e.getFileDownloadUrl(d);return a(l.downloadUrl),l.downloadUrl}catch(l){return s(l instanceof Error?l:new Error(String(l))),null}finally{o(false);}},[e]);return {isSupported:t,isLoading:n,error:r,downloadUrl:p,getDownloadUrl:f}}function K(){let{client:e}=i(),t=react.useRef(null),n=!!e?.notifyIntrinsicHeight,o=react.useCallback(r=>{e?.notifyIntrinsicHeight?.(r);},[e]);return react.useEffect(()=>{let r=t.current;if(!e?.notifyIntrinsicHeight||!r||typeof ResizeObserver>"u")return;let s=w(r,(p,a)=>{e.notifyIntrinsicHeight?.(a);});return ()=>s.disconnect()},[e]),{isSupported:n,containerRef:t,notify:o}}function Q(){return b().view}function Y(){let{client:e}=i(),t=!!e?.requestModal,[n,o]=react.useState(false),r=react.useCallback(async s=>{if(!e?.requestModal)return null;o(true);try{return await e.requestModal(s)}finally{o(false);}},[e]);return {isSupported:t,isOpen:n,showModal:r}}function Z(e){return i(),react.useEffect(()=>{e&&ui.clientDebugLogger.configure(e);},[e]),ui.clientDebugLogger}exports.AppsProvider=M;exports.useAppsClient=U;exports.useAppsContext=i;exports.useDebugLogger=Z;exports.useDisplayMode=z;exports.useDocumentTheme=k;exports.useFileDownload=G;exports.useFileUpload=W;exports.useHostCapabilities=_;exports.useHostContext=b;exports.useHostStyleVariables=V;exports.useHostVersion=B;exports.useIntrinsicHeight=K;exports.useModal=Y;exports.useOnTeardown=j;exports.useOnToolCancelled=q;exports.useOnToolInputPartial=X;exports.useSafeAreaInsets=N;exports.useSizeChangedNotifications=J;exports.useToolInput=F;exports.useToolResult=P;exports.useView=Q;exports.useWidgetState=L;//# sourceMappingURL=index.cjs.map | ||
| //# sourceMappingURL=index.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/context.tsx","../src/hooks.ts"],"names":["AppsContext","createContext","AppsProvider","children","providedClient","_forceAdapter","fallback","ErrorFallback","client","setClient","useState","isConnecting","setIsConnecting","error","setError","useEffect","newClient","createClient","err","jsx","Fragment","contextValue","useAppsContext","context","useContext","useAppsClient","useToolResult","result","setResult","initialOutput","newResult","useToolInput","input","setInput","newInput","useHostContext","setContext","newContext","useWidgetState","defaultValue","state","setStateInternal","setState","useCallback","newState","prev","next","useHostStyleVariables","variables","root","key","value","useDocumentTheme","lightClass","darkClass","theme","body","useDisplayMode","requestMode","mode","useSafeAreaInsets","useOnToolCancelled","handler","useOnTeardown","useOnToolInputPartial","useHostCapabilities","capabilities","setCapabilities","useHostVersion","version","setVersion","useSizeChangedNotifications","containerRef","useRef","element","observer","entries","entry","width","height","rect","useFileUpload","upload","file","useFileDownload","getDownloadUrl","fileId","useIntrinsicHeight","isSupported","setIsSupported","notify","useView","useModal","isOpen","setIsOpen","showModal","options","useDebugLogger","config","clientDebugLogger"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * React context and provider for @mcp-apps-kit/ui-react\n */\n\nimport React, {\n createContext,\n useContext,\n useState,\n useEffect,\n type ReactNode,\n type ComponentType,\n} from \"react\";\nimport type { AppsClient, ToolDefs } from \"@mcp-apps-kit/ui\";\nimport { createClient } from \"@mcp-apps-kit/ui\";\n\n// =============================================================================\n// CONTEXT\n// =============================================================================\n\n// Internal context value - uses `unknown` for the client to allow any typed client\n// The actual type parameter is applied when consuming via hooks\ninterface AppsContextValueInternal {\n client: AppsClient | null;\n isConnecting: boolean;\n error: Error | null;\n}\n\n// Public interface with generic type parameter for typed access\ninterface AppsContextValue<T extends ToolDefs = ToolDefs> {\n client: AppsClient<T> | null;\n isConnecting: boolean;\n error: Error | null;\n}\n\nconst AppsContext = createContext<AppsContextValueInternal | null>(null);\n\n// =============================================================================\n// PROVIDER PROPS\n// =============================================================================\n\n/**\n * Props for AppsProvider\n */\nexport interface AppsProviderProps<T extends ToolDefs = ToolDefs> {\n /** Child components */\n children: ReactNode;\n\n /**\n * Pre-created client instance (optional)\n * If not provided, creates client automatically\n */\n client?: AppsClient<T>;\n\n /**\n * Force a specific protocol adapter\n */\n forceAdapter?: \"mcp\" | \"openai\" | \"mock\";\n\n /**\n * Fallback UI while client is connecting\n */\n fallback?: ReactNode;\n\n /**\n * Error boundary fallback\n */\n errorFallback?: ComponentType<{ error: Error; reset: () => void }>;\n}\n\n// =============================================================================\n// PROVIDER\n// =============================================================================\n\n/**\n * Context provider for mcp-apps-kit React integration\n *\n * Wraps your app and provides the client instance to all hooks.\n *\n * @example\n * ```tsx\n * function App() {\n * return (\n * <AppsProvider fallback={<Loading />}>\n * <MyWidget />\n * </AppsProvider>\n * );\n * }\n * ```\n */\nexport function AppsProvider<T extends ToolDefs = ToolDefs>({\n children,\n client: providedClient,\n forceAdapter: _forceAdapter,\n fallback,\n errorFallback: ErrorFallback,\n}: AppsProviderProps<T>): React.JSX.Element {\n const [client, setClient] = useState<AppsClient<T> | null>(providedClient ?? null);\n const [isConnecting, setIsConnecting] = useState(!providedClient);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n if (providedClient) {\n setClient(providedClient);\n setIsConnecting(false);\n return;\n }\n\n // Initialize client with auto-detection or forced adapter\n const initClient = async () => {\n try {\n const newClient = await createClient<T>({\n forceAdapter: _forceAdapter,\n });\n setClient(newClient);\n setIsConnecting(false);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setIsConnecting(false);\n }\n };\n\n void initClient();\n }, [providedClient, _forceAdapter]);\n\n if (error && ErrorFallback) {\n return <ErrorFallback error={error} reset={() => setError(null)} />;\n }\n\n // Don't render children until client is connected\n // This prevents hooks from throwing during initial connection\n if (isConnecting) {\n return <>{fallback ?? null}</>;\n }\n\n // Cast to internal type - the generic T is preserved at runtime,\n // and consumers use hooks with their own type parameter to get proper typing\n const contextValue: AppsContextValueInternal = {\n client: client as AppsClient | null,\n isConnecting,\n error,\n };\n\n return <AppsContext.Provider value={contextValue}>{children}</AppsContext.Provider>;\n}\n\n// =============================================================================\n// INTERNAL HOOK\n// =============================================================================\n\n/**\n * Internal hook to access the context\n * @internal\n */\nexport function useAppsContext<T extends ToolDefs = ToolDefs>(): AppsContextValue<T> {\n const context = useContext(AppsContext);\n if (!context) {\n throw new Error(\"useAppsContext must be used within an AppsProvider\");\n }\n return context as AppsContextValue<T>;\n}\n","/**\n * React hooks for @mcp-apps-kit/ui-react\n */\n\nimport React, { useState, useEffect, useCallback, useRef } from \"react\";\nimport type {\n AppsClient,\n HostContext,\n ToolDefs,\n ToolResult,\n ClientDebugConfig,\n ModalOptions,\n ModalResult,\n HostCapabilities,\n HostVersion,\n} from \"@mcp-apps-kit/ui\";\nimport { clientDebugLogger, type ClientDebugLogger } from \"@mcp-apps-kit/ui\";\nimport { useAppsContext } from \"./context\";\n\n// =============================================================================\n// CORE HOOKS\n// =============================================================================\n\n/**\n * Access the typed client instance\n *\n * @returns Client instance\n * @throws Error if used outside AppsProvider\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const client = useAppsClient<typeof app.tools>();\n *\n * const handleClick = async () => {\n * await client.callTool(\"myTool\", { arg: \"value\" });\n * };\n *\n * return <button onClick={handleClick}>Call Tool</button>;\n * }\n * ```\n */\nexport function useAppsClient<T extends ToolDefs = ToolDefs>(): AppsClient<T> {\n const { client, isConnecting, error } = useAppsContext<T>();\n\n if (error) {\n throw error;\n }\n\n if (isConnecting || !client) {\n throw new Error(\"Client not ready. Make sure AppsProvider has finished connecting.\");\n }\n\n return client;\n}\n\n/**\n * Access current tool result with automatic re-renders\n *\n * @returns Current tool result or undefined\n *\n * @example\n * ```tsx\n * function ResultDisplay() {\n * const result = useToolResult<typeof app.tools>();\n *\n * if (!result?.myTool) {\n * return <div>No results yet</div>;\n * }\n *\n * return <div>{result.myTool.message}</div>;\n * }\n * ```\n */\nexport function useToolResult<T extends ToolDefs = ToolDefs>(): ToolResult<T> | undefined {\n const { client } = useAppsContext<T>();\n const [result, setResult] = useState<ToolResult<T> | undefined>(undefined);\n\n useEffect(() => {\n if (!client) {\n return;\n }\n\n // Get initial tool output if available (wrapped with tool name)\n const initialOutput = client.toolOutput;\n if (initialOutput && Object.keys(initialOutput).length > 0) {\n setResult(initialOutput as ToolResult<T>);\n }\n\n // Subscribe to future tool result updates\n const unsubscribe = client.onToolResult((newResult) => {\n setResult(newResult as ToolResult<T>);\n });\n\n return unsubscribe;\n }, [client]);\n\n return result;\n}\n\n/**\n * Access current tool input\n *\n * @returns Current tool input or undefined\n *\n * @example\n * ```tsx\n * function InputDisplay() {\n * const input = useToolInput();\n * return <pre>{JSON.stringify(input, null, 2)}</pre>;\n * }\n * ```\n */\nexport function useToolInput(): Record<string, unknown> | undefined {\n const { client } = useAppsContext();\n const [input, setInput] = useState<Record<string, unknown> | undefined>(client?.toolInput);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.onToolInput((newInput) => {\n setInput(newInput);\n });\n\n return unsubscribe;\n }, [client]);\n\n return input;\n}\n\n/**\n * Access host context with automatic re-renders on changes\n *\n * @returns Current host context\n *\n * @example\n * ```tsx\n * function ThemedComponent() {\n * const context = useHostContext();\n *\n * return (\n * <div className={context.theme}>\n * Display: {context.displayMode}\n * </div>\n * );\n * }\n * ```\n */\nexport function useHostContext(): HostContext {\n const { client } = useAppsContext();\n const [context, setContext] = useState<HostContext>(\n client?.hostContext ?? {\n theme: \"light\",\n displayMode: \"inline\",\n availableDisplayModes: [\"inline\"],\n viewport: { width: 0, height: 0 },\n locale: \"en-US\",\n platform: \"web\",\n }\n );\n\n useEffect(() => {\n if (!client) return;\n\n setContext(client.hostContext);\n\n const unsubscribe = client.onHostContextChange((newContext) => {\n setContext(newContext);\n });\n\n return unsubscribe;\n }, [client]);\n\n return context;\n}\n\n/**\n * Persisted widget state with automatic sync\n *\n * Works like useState but persists across widget reloads.\n * On ChatGPT: Session-scoped persistence\n * On MCP Apps: Silent no-op (returns default, setState is ignored)\n *\n * @param defaultValue - Initial state value\n * @returns [state, setState] tuple\n *\n * @example\n * ```tsx\n * function Counter() {\n * const [count, setCount] = useWidgetState(0);\n *\n * return (\n * <button onClick={() => setCount(c => c + 1)}>\n * Count: {count}\n * </button>\n * );\n * }\n * ```\n */\nexport function useWidgetState<S>(defaultValue: S): [S, (newState: S | ((prev: S) => S)) => void] {\n const { client } = useAppsContext();\n\n const [state, setStateInternal] = useState<S>(() => {\n if (!client) return defaultValue;\n const stored = client.getState<S>();\n return stored ?? defaultValue;\n });\n\n const setState = useCallback(\n (newState: S | ((prev: S) => S)) => {\n setStateInternal((prev) => {\n const next = typeof newState === \"function\" ? (newState as (prev: S) => S)(prev) : newState;\n\n // Persist to client (silent no-op on MCP Apps)\n client?.setState(next);\n\n return next;\n });\n },\n [client]\n );\n\n return [state, setState];\n}\n\n// =============================================================================\n// UTILITY HOOKS\n// =============================================================================\n\n/**\n * Apply host CSS variables to document root\n *\n * Call this once in your root component to apply host theming.\n *\n * @example\n * ```tsx\n * function App() {\n * useHostStyleVariables();\n * return <MyWidget />;\n * }\n * ```\n */\nexport function useHostStyleVariables(): void {\n const context = useHostContext();\n\n useEffect(() => {\n const variables = context.styles?.variables;\n if (!variables) return;\n\n const root = document.documentElement;\n for (const [key, value] of Object.entries(variables)) {\n root.style.setProperty(key, value);\n }\n\n // Cleanup\n return () => {\n for (const key of Object.keys(variables)) {\n root.style.removeProperty(key);\n }\n };\n }, [context.styles?.variables]);\n}\n\n/**\n * Apply theme class to document body\n *\n * @param lightClass - Class name for light theme (default: \"light\")\n * @param darkClass - Class name for dark theme (default: \"dark\")\n *\n * @example\n * ```tsx\n * function App() {\n * useDocumentTheme(\"theme-light\", \"theme-dark\");\n * return <MyWidget />;\n * }\n * ```\n */\nexport function useDocumentTheme(lightClass = \"light\", darkClass = \"dark\"): void {\n const context = useHostContext();\n\n useEffect(() => {\n const { theme } = context;\n const body = document.body;\n\n body.classList.remove(lightClass, darkClass);\n body.classList.add(theme === \"dark\" ? darkClass : lightClass);\n\n return () => {\n body.classList.remove(lightClass, darkClass);\n };\n }, [context.theme, lightClass, darkClass]);\n}\n\n/**\n * Access and manage display mode\n *\n * @returns Display mode state and controls\n *\n * @example\n * ```tsx\n * function DisplayModeToggle() {\n * const { mode, availableModes, requestMode } = useDisplayMode();\n *\n * return (\n * <select value={mode} onChange={e => requestMode(e.target.value)}>\n * {availableModes.map(m => (\n * <option key={m} value={m}>{m}</option>\n * ))}\n * </select>\n * );\n * }\n * ```\n */\nexport function useDisplayMode(): {\n mode: string;\n availableModes: string[];\n requestMode: (mode: \"inline\" | \"fullscreen\" | \"pip\") => Promise<void>;\n} {\n const context = useHostContext();\n const { client } = useAppsContext();\n\n const requestMode = useCallback(\n async (mode: \"inline\" | \"fullscreen\" | \"pip\") => {\n await client?.requestDisplayMode(mode);\n },\n [client]\n );\n\n return {\n mode: context.displayMode,\n availableModes: context.availableDisplayModes,\n requestMode,\n };\n}\n\n/**\n * Access safe area insets for mobile layouts\n *\n * @returns Safe area insets or default zeros\n *\n * @example\n * ```tsx\n * function SafeContent() {\n * const insets = useSafeAreaInsets();\n *\n * return (\n * <div style={{ paddingTop: insets.top, paddingBottom: insets.bottom }}>\n * Content\n * </div>\n * );\n * }\n * ```\n */\nexport function useSafeAreaInsets(): {\n top: number;\n right: number;\n bottom: number;\n left: number;\n} {\n const context = useHostContext();\n\n return (\n context.safeAreaInsets ?? {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n }\n );\n}\n\n// =============================================================================\n// EVENT HOOKS\n// =============================================================================\n\n/**\n * Subscribe to tool cancellation\n *\n * @param handler - Callback when tool is cancelled\n *\n * @example\n * ```tsx\n * function CancellableOperation() {\n * const [cancelled, setCancelled] = useState(false);\n *\n * useOnToolCancelled((reason) => {\n * setCancelled(true);\n * console.log(\"Cancelled:\", reason);\n * });\n *\n * return cancelled ? <div>Cancelled</div> : <div>Running...</div>;\n * }\n * ```\n */\nexport function useOnToolCancelled(handler: (reason?: string) => void): void {\n const { client } = useAppsContext();\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.onToolCancelled(handler);\n return unsubscribe;\n }, [client, handler]);\n}\n\n/**\n * Subscribe to teardown events\n *\n * @param handler - Callback when widget is torn down\n *\n * @example\n * ```tsx\n * function CleanupComponent() {\n * useOnTeardown((reason) => {\n * console.log(\"Tearing down:\", reason);\n * // Cleanup resources\n * });\n *\n * return <div>Widget</div>;\n * }\n * ```\n */\nexport function useOnTeardown(handler: (reason?: string) => void): void {\n const { client } = useAppsContext();\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.onTeardown(handler);\n return unsubscribe;\n }, [client, handler]);\n}\n\n/**\n * Subscribe to partial/streaming tool input\n *\n * Called when the host sends partial tool arguments during streaming.\n * Useful for showing real-time input as the user types or as the model generates.\n *\n * @param handler - Callback for partial input\n *\n * @example\n * ```tsx\n * function StreamingInput() {\n * const [partialInput, setPartialInput] = useState<Record<string, unknown>>({});\n *\n * useOnToolInputPartial((input) => {\n * setPartialInput(input);\n * });\n *\n * return <pre>{JSON.stringify(partialInput, null, 2)}</pre>;\n * }\n * ```\n */\nexport function useOnToolInputPartial(handler: (input: Record<string, unknown>) => void): void {\n const { client } = useAppsContext();\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.onToolInputPartial(handler);\n return unsubscribe;\n }, [client, handler]);\n}\n\n// =============================================================================\n// HOST INFORMATION HOOKS\n// =============================================================================\n\n/**\n * Access host capabilities\n *\n * Returns the capabilities advertised by the host during handshake.\n * Use this to check if features like logging or server tools are supported.\n *\n * @returns Host capabilities or undefined if not yet connected\n *\n * @example\n * ```tsx\n * function CapabilitiesDisplay() {\n * const capabilities = useHostCapabilities();\n *\n * return (\n * <div>\n * <p>Logging: {capabilities?.logging ? \"Supported\" : \"Not supported\"}</p>\n * <p>Open Links: {capabilities?.openLinks ? \"Supported\" : \"Not supported\"}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useHostCapabilities(): HostCapabilities | undefined {\n const { client } = useAppsContext();\n const [capabilities, setCapabilities] = useState<HostCapabilities | undefined>(\n client?.getHostCapabilities()\n );\n\n useEffect(() => {\n if (!client) return;\n setCapabilities(client.getHostCapabilities());\n }, [client]);\n\n return capabilities;\n}\n\n/**\n * Access host version information\n *\n * Returns the name and version of the host application.\n *\n * @returns Host version info or undefined if not yet connected\n *\n * @example\n * ```tsx\n * function HostInfo() {\n * const hostVersion = useHostVersion();\n *\n * if (!hostVersion) return <div>Loading...</div>;\n *\n * return (\n * <div>\n * Running on {hostVersion.name} v{hostVersion.version}\n * </div>\n * );\n * }\n * ```\n */\nexport function useHostVersion(): HostVersion | undefined {\n const { client } = useAppsContext();\n const [version, setVersion] = useState<HostVersion | undefined>(client?.getHostVersion());\n\n useEffect(() => {\n if (!client) return;\n setVersion(client.getHostVersion());\n }, [client]);\n\n return version;\n}\n\n// =============================================================================\n// SIZE NOTIFICATION HOOKS\n// =============================================================================\n\n/**\n * Hook to set up automatic size change notifications\n *\n * Creates a ResizeObserver that automatically sends size changed\n * notifications to the host when the observed element resizes.\n *\n * @returns Ref to attach to the element to observe\n *\n * @example\n * ```tsx\n * function AutoSizeWidget() {\n * const containerRef = useSizeChangedNotifications();\n *\n * return (\n * <div ref={containerRef}>\n * <p>Content that may change size...</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useSizeChangedNotifications(): React.RefObject<HTMLElement | null> {\n const { client } = useAppsContext();\n const containerRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n if (!client || typeof ResizeObserver === \"undefined\") return;\n\n const element = containerRef.current;\n if (!element) return;\n\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect;\n void client.sendSizeChanged({\n width: Math.round(width),\n height: Math.round(height),\n });\n }\n });\n\n observer.observe(element);\n\n // Report initial size\n const rect = element.getBoundingClientRect();\n void client.sendSizeChanged({\n width: Math.round(rect.width),\n height: Math.round(rect.height),\n });\n\n return () => observer.disconnect();\n }, [client]);\n\n return containerRef;\n}\n\n// =============================================================================\n// FILE OPERATION HOOKS\n// =============================================================================\n\n/**\n * File upload result\n */\nexport interface FileUploadResult {\n /** Uploaded file ID */\n fileId: string;\n}\n\n/**\n * File upload state\n */\nexport interface UseFileUploadState {\n /** Whether file upload is supported on this platform */\n isSupported: boolean;\n /** Whether upload is in progress */\n isUploading: boolean;\n /** Upload error if any */\n error: Error | null;\n /** Last uploaded file ID */\n fileId: string | null;\n}\n\n/**\n * Hook for uploading files (ChatGPT only)\n *\n * Provides a function to upload files and tracks upload state.\n * On unsupported platforms, isSupported will be false.\n *\n * Supported file types: PNG, JPEG, WebP images\n *\n * @returns Upload function and state\n *\n * @example\n * ```tsx\n * function ImageUploader() {\n * const { upload, isSupported, isUploading, error, fileId } = useFileUpload();\n *\n * if (!isSupported) {\n * return <div>File upload not supported on this platform</div>;\n * }\n *\n * const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {\n * const file = e.target.files?.[0];\n * if (file) {\n * const result = await upload(file);\n * console.log(\"Uploaded:\", result?.fileId);\n * }\n * };\n *\n * return (\n * <div>\n * <input type=\"file\" accept=\"image/*\" onChange={handleFileChange} />\n * {isUploading && <span>Uploading...</span>}\n * {error && <span>Error: {error.message}</span>}\n * {fileId && <span>Uploaded: {fileId}</span>}\n * </div>\n * );\n * }\n * ```\n */\nexport function useFileUpload(): UseFileUploadState & {\n upload: (file: File) => Promise<FileUploadResult | null>;\n} {\n const { client } = useAppsContext();\n const [state, setState] = useState<UseFileUploadState>({\n isSupported: false,\n isUploading: false,\n error: null,\n fileId: null,\n });\n\n // Check if upload is supported\n useEffect(() => {\n setState((prev) => ({\n ...prev,\n isSupported: !!client?.uploadFile,\n }));\n }, [client]);\n\n const upload = useCallback(\n async (file: File): Promise<FileUploadResult | null> => {\n if (!client?.uploadFile) {\n setState((prev) => ({\n ...prev,\n error: new Error(\"File upload not supported on this platform\"),\n }));\n return null;\n }\n\n setState((prev) => ({ ...prev, isUploading: true, error: null }));\n\n try {\n const result = await client.uploadFile(file);\n setState((prev) => ({\n ...prev,\n isUploading: false,\n fileId: result.fileId,\n }));\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setState((prev) => ({\n ...prev,\n isUploading: false,\n error,\n }));\n return null;\n }\n },\n [client]\n );\n\n return { ...state, upload };\n}\n\n/**\n * Hook for getting file download URLs (ChatGPT only)\n *\n * Provides a function to get temporary download URLs for uploaded files.\n * On unsupported platforms, isSupported will be false.\n *\n * @returns Download URL function and state\n *\n * @example\n * ```tsx\n * function FileDownloader({ fileId }: { fileId: string }) {\n * const { getDownloadUrl, isSupported, isLoading, error, downloadUrl } = useFileDownload();\n *\n * useEffect(() => {\n * if (fileId && isSupported) {\n * getDownloadUrl(fileId);\n * }\n * }, [fileId, isSupported, getDownloadUrl]);\n *\n * if (!isSupported) return <div>Not supported</div>;\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (downloadUrl) return <img src={downloadUrl} alt=\"Uploaded file\" />;\n *\n * return null;\n * }\n * ```\n */\nexport function useFileDownload(): {\n isSupported: boolean;\n isLoading: boolean;\n error: Error | null;\n downloadUrl: string | null;\n getDownloadUrl: (fileId: string) => Promise<string | null>;\n} {\n const { client } = useAppsContext();\n const [state, setState] = useState<{\n isSupported: boolean;\n isLoading: boolean;\n error: Error | null;\n downloadUrl: string | null;\n }>({\n isSupported: false,\n isLoading: false,\n error: null,\n downloadUrl: null,\n });\n\n // Check if download URL is supported\n useEffect(() => {\n setState((prev) => ({\n ...prev,\n isSupported: !!client?.getFileDownloadUrl,\n }));\n }, [client]);\n\n const getDownloadUrl = useCallback(\n async (fileId: string): Promise<string | null> => {\n if (!client?.getFileDownloadUrl) {\n setState((prev) => ({\n ...prev,\n error: new Error(\"File download not supported on this platform\"),\n }));\n return null;\n }\n\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n\n try {\n const result = await client.getFileDownloadUrl(fileId);\n setState((prev) => ({\n ...prev,\n isLoading: false,\n downloadUrl: result.downloadUrl,\n }));\n return result.downloadUrl;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setState((prev) => ({\n ...prev,\n isLoading: false,\n error,\n }));\n return null;\n }\n },\n [client]\n );\n\n return { ...state, getDownloadUrl };\n}\n\n// =============================================================================\n// LAYOUT HOOKS\n// =============================================================================\n\n/**\n * Hook to notify host of widget's intrinsic height (ChatGPT only)\n *\n * Automatically reports height changes to prevent scroll clipping.\n * Returns a ref to attach to your root element for automatic height tracking,\n * or a manual notify function for custom height reporting.\n *\n * @returns Ref for auto-tracking and manual notify function\n *\n * @example\n * ```tsx\n * // Automatic height tracking\n * function AutoHeightWidget() {\n * const { containerRef, isSupported } = useIntrinsicHeight();\n *\n * return (\n * <div ref={containerRef}>\n * <p>Content that may change height...</p>\n * </div>\n * );\n * }\n *\n * // Manual height notification\n * function ManualHeightWidget() {\n * const { notify, isSupported } = useIntrinsicHeight();\n *\n * useEffect(() => {\n * // Notify after content loads\n * notify(500);\n * }, [notify]);\n *\n * return <div style={{ height: 500 }}>Fixed height content</div>;\n * }\n * ```\n */\nexport function useIntrinsicHeight(): {\n /** Whether intrinsic height notification is supported */\n isSupported: boolean;\n /** Ref to attach to container for automatic height tracking */\n containerRef: React.RefObject<HTMLElement | null>;\n /** Manually notify host of height */\n notify: (height: number) => void;\n} {\n const { client } = useAppsContext();\n const containerRef = useRef<HTMLElement | null>(null);\n const [isSupported, setIsSupported] = useState(false);\n\n // Check if supported\n useEffect(() => {\n setIsSupported(!!client?.notifyIntrinsicHeight);\n }, [client]);\n\n // Manual notify function\n const notify = useCallback(\n (height: number) => {\n client?.notifyIntrinsicHeight?.(height);\n },\n [client]\n );\n\n // Auto-track height with ResizeObserver\n useEffect(() => {\n if (!client?.notifyIntrinsicHeight || !containerRef.current) return;\n\n const element = containerRef.current;\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const height = entry.contentRect.height;\n client.notifyIntrinsicHeight?.(height);\n }\n });\n\n observer.observe(element);\n\n // Report initial height\n client.notifyIntrinsicHeight(element.offsetHeight);\n\n return () => observer.disconnect();\n }, [client]);\n\n return { isSupported, containerRef, notify };\n}\n\n/**\n * Hook to access the current view identifier (ChatGPT only)\n *\n * Useful for multi-view widgets that need to know which view is active.\n *\n * @returns Current view identifier or undefined\n *\n * @example\n * ```tsx\n * function MultiViewWidget() {\n * const view = useView();\n *\n * switch (view) {\n * case \"settings\":\n * return <SettingsView />;\n * case \"details\":\n * return <DetailsView />;\n * default:\n * return <MainView />;\n * }\n * }\n * ```\n */\nexport function useView(): string | undefined {\n const context = useHostContext();\n return context.view;\n}\n\n// =============================================================================\n// MODAL HOOKS\n// =============================================================================\n\n/**\n * Hook for showing host-owned modal dialogs (ChatGPT only)\n *\n * Spawns native ChatGPT modals for confirmations, inputs, etc.\n * On unsupported platforms, isSupported will be false.\n *\n * @returns Modal function and state\n *\n * @example\n * ```tsx\n * function DeleteButton() {\n * const { showModal, isSupported, isOpen } = useModal();\n *\n * const handleDelete = async () => {\n * const result = await showModal({\n * title: \"Confirm Delete\",\n * body: \"Are you sure you want to delete this item?\",\n * buttons: [\n * { label: \"Cancel\", variant: \"secondary\", value: \"cancel\" },\n * { label: \"Delete\", variant: \"destructive\", value: \"delete\" },\n * ],\n * });\n *\n * if (result?.action === \"delete\") {\n * // Perform delete\n * }\n * };\n *\n * if (!isSupported) {\n * return <button onClick={() => window.confirm(\"Delete?\")}>Delete</button>;\n * }\n *\n * return (\n * <button onClick={handleDelete} disabled={isOpen}>\n * Delete\n * </button>\n * );\n * }\n *\n * // Input modal example\n * function RenameButton() {\n * const { showModal } = useModal();\n *\n * const handleRename = async () => {\n * const result = await showModal({\n * title: \"Rename Item\",\n * input: {\n * type: \"text\",\n * placeholder: \"Enter new name\",\n * defaultValue: \"Current Name\",\n * },\n * buttons: [\n * { label: \"Cancel\", variant: \"secondary\", value: \"cancel\" },\n * { label: \"Rename\", variant: \"primary\", value: \"rename\" },\n * ],\n * });\n *\n * if (result?.action === \"rename\" && result.inputValue) {\n * console.log(\"New name:\", result.inputValue);\n * }\n * };\n *\n * return <button onClick={handleRename}>Rename</button>;\n * }\n * ```\n */\nexport function useModal(): {\n /** Whether modal API is supported */\n isSupported: boolean;\n /** Whether a modal is currently open */\n isOpen: boolean;\n /** Show a modal dialog */\n showModal: (options: ModalOptions) => Promise<ModalResult | null>;\n} {\n const { client } = useAppsContext();\n const [isSupported, setIsSupported] = useState(false);\n const [isOpen, setIsOpen] = useState(false);\n\n // Check if supported\n useEffect(() => {\n setIsSupported(!!client?.requestModal);\n }, [client]);\n\n const showModal = useCallback(\n async (options: ModalOptions): Promise<ModalResult | null> => {\n if (!client?.requestModal) {\n return null;\n }\n\n setIsOpen(true);\n try {\n const result = await client.requestModal(options);\n return result;\n } finally {\n setIsOpen(false);\n }\n },\n [client]\n );\n\n return { isSupported, isOpen, showModal };\n}\n\n// =============================================================================\n// DEBUG LOGGING HOOKS\n// =============================================================================\n\n/**\n * Access the debug logger with automatic adapter injection\n *\n * The adapter is automatically configured when AppsProvider connects.\n * Use this hook to access the logger and optionally configure it.\n *\n * @param config - Optional configuration to apply\n * @returns The configured client debug logger\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const logger = useDebugLogger({ enabled: true, level: \"debug\" });\n *\n * const handleClick = () => {\n * logger.info(\"Button clicked\", { timestamp: Date.now() });\n * };\n *\n * return <button onClick={handleClick}>Click me</button>;\n * }\n * ```\n */\nexport function useDebugLogger(config?: Partial<ClientDebugConfig>): ClientDebugLogger {\n // Verify we're inside AppsProvider (adapter is set by createClient)\n useAppsContext();\n\n // Apply configuration when it changes\n useEffect(() => {\n if (config) {\n clientDebugLogger.configure(config);\n }\n }, [config]);\n\n return clientDebugLogger;\n}\n"]} | ||
| {"version":3,"sources":["../src/context.tsx","../src/hooks.ts"],"names":["AppsContext","createContext","AppsProvider","children","providedClient","_forceAdapter","autoResize","fallback","ErrorFallback","client","setClient","useState","isConnecting","setIsConnecting","error","setError","useEffect","newClient","createClient","err","jsx","Fragment","contextValue","useAppsContext","context","useContext","DEFAULT_HOST_CONTEXT","DEFAULT_INSETS","createSizeObserver","element","onResize","observer","entries","entry","width","height","rect","useAppsClient","useToolResult","result","setResult","initialOutput","newResult","useToolInput","input","setInput","newInput","useHostContext","setContext","useWidgetState","defaultValue","state","setStateInternal","setState","useCallback","newState","prev","next","useHostStyleVariables","variables","root","key","value","useDocumentTheme","lightClass","darkClass","theme","body","useDisplayMode","requestMode","mode","useSafeAreaInsets","useOnToolCancelled","handler","handlerRef","useRef","reason","useOnTeardown","useOnToolInputPartial","useHostCapabilities","capabilities","setCapabilities","useHostVersion","version","setVersion","useSizeChangedNotifications","containerRef","useFileUpload","isSupported","isUploading","setIsUploading","fileId","setFileId","upload","file","useFileDownload","isLoading","setIsLoading","downloadUrl","setDownloadUrl","getDownloadUrl","useIntrinsicHeight","notify","_width","useView","useModal","isOpen","setIsOpen","showModal","options","useDebugLogger","config","clientDebugLogger"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * React context and provider for @mcp-apps-kit/ui-react\n */\n\nimport type { ReactNode, ComponentType, JSX } from \"react\";\nimport { createContext, useContext, useState, useEffect } from \"react\";\nimport type { AppsClient, ToolDefs } from \"@mcp-apps-kit/ui\";\nimport { createClient } from \"@mcp-apps-kit/ui\";\n\n// =============================================================================\n// CONTEXT\n// =============================================================================\n\n// Internal context value - uses `unknown` for the client to allow any typed client\n// The actual type parameter is applied when consuming via hooks\ninterface AppsContextValueInternal {\n client: AppsClient | null;\n isConnecting: boolean;\n error: Error | null;\n}\n\nconst AppsContext = createContext<AppsContextValueInternal | null>(null);\n\n// =============================================================================\n// PROVIDER PROPS\n// =============================================================================\n\n/**\n * Props for AppsProvider\n */\nexport interface AppsProviderProps<T extends ToolDefs = ToolDefs> {\n /** Child components */\n children: ReactNode;\n\n /**\n * Pre-created client instance (optional)\n * If not provided, creates client automatically\n */\n client?: AppsClient<T>;\n\n /**\n * Force a specific protocol adapter\n */\n forceAdapter?: \"mcp\" | \"openai\" | \"mock\";\n\n /**\n * Enable automatic size change notifications (MCP adapter only)\n *\n * When enabled, the UI automatically reports its size changes to the host\n * using a ResizeObserver on document.body and document.documentElement.\n * The host can then resize the UI container accordingly.\n *\n * Note: This option is only applied during initial mount. Changing it\n * at runtime will have no effect.\n *\n * @default true\n */\n autoResize?: boolean;\n\n /**\n * Fallback UI while client is connecting\n */\n fallback?: ReactNode;\n\n /**\n * Error boundary fallback\n */\n errorFallback?: ComponentType<{ error: Error; reset: () => void }>;\n}\n\n// =============================================================================\n// PROVIDER\n// =============================================================================\n\n/**\n * Context provider for mcp-apps-kit React integration\n *\n * Wraps your app and provides the client instance to all hooks.\n *\n * @example\n * ```tsx\n * function App() {\n * return (\n * <AppsProvider fallback={<Loading />}>\n * <MyWidget />\n * </AppsProvider>\n * );\n * }\n * ```\n */\nexport function AppsProvider<T extends ToolDefs = ToolDefs>({\n children,\n client: providedClient,\n forceAdapter: _forceAdapter,\n autoResize,\n fallback,\n errorFallback: ErrorFallback,\n}: AppsProviderProps<T>): JSX.Element {\n const [client, setClient] = useState<AppsClient<T> | null>(providedClient ?? null);\n const [isConnecting, setIsConnecting] = useState(!providedClient);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n if (providedClient) {\n setClient(providedClient);\n setIsConnecting(false);\n return;\n }\n\n // Initialize client with auto-detection or forced adapter\n const initClient = async () => {\n try {\n const newClient = await createClient<T>({\n forceAdapter: _forceAdapter,\n autoResize,\n });\n setClient(newClient);\n setIsConnecting(false);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setIsConnecting(false);\n }\n };\n\n void initClient();\n // Note: autoResize is intentionally not in the dependency array.\n // It should only be set during initial mount. Changing it at runtime\n // would cause unnecessary client re-initialization.\n }, [providedClient, _forceAdapter]);\n\n if (error && ErrorFallback) {\n return <ErrorFallback error={error} reset={() => setError(null)} />;\n }\n\n // Don't render children until client is connected\n // This prevents hooks from throwing during initial connection\n if (isConnecting) {\n return <>{fallback ?? null}</>;\n }\n\n // Cast to internal type - the generic T is preserved at runtime,\n // and consumers use hooks with their own type parameter to get proper typing\n const contextValue: AppsContextValueInternal = {\n client: client as AppsClient | null,\n isConnecting,\n error,\n };\n\n return <AppsContext.Provider value={contextValue}>{children}</AppsContext.Provider>;\n}\n\n// =============================================================================\n// INTERNAL HOOK\n// =============================================================================\n\n/**\n * Context value exposed by useAppsContext\n */\nexport interface AppsContextValue<T extends ToolDefs = ToolDefs> {\n client: AppsClient<T> | null;\n isConnecting: boolean;\n error: Error | null;\n}\n\n/**\n * Internal hook to access the context\n * @internal\n */\nexport function useAppsContext<T extends ToolDefs = ToolDefs>(): AppsContextValue<T> {\n const context = useContext(AppsContext);\n if (!context) {\n throw new Error(\"useAppsContext must be used within an AppsProvider\");\n }\n return context as AppsContextValue<T>;\n}\n","/**\n * React hooks for @mcp-apps-kit/ui-react\n */\n\nimport type { RefObject } from \"react\";\nimport { useState, useEffect, useCallback, useRef } from \"react\";\nimport type {\n AppsClient,\n HostContext,\n ToolDefs,\n ToolResult,\n ClientDebugConfig,\n ModalOptions,\n ModalResult,\n HostCapabilities,\n HostVersion,\n} from \"@mcp-apps-kit/ui\";\nimport { clientDebugLogger, type ClientDebugLogger } from \"@mcp-apps-kit/ui\";\nimport { useAppsContext } from \"./context\";\n\n// =============================================================================\n// SHARED UTILITIES\n// =============================================================================\n\n/** Default host context for initial state */\nconst DEFAULT_HOST_CONTEXT: HostContext = {\n theme: \"light\",\n displayMode: \"inline\",\n availableDisplayModes: [\"inline\"],\n viewport: { width: 0, height: 0 },\n locale: \"en-US\",\n platform: \"web\",\n};\n\n/** Default safe area insets */\nconst DEFAULT_INSETS = { top: 0, right: 0, bottom: 0, left: 0 };\n\n/**\n * Helper to create a ResizeObserver that reports size changes\n */\nfunction createSizeObserver(\n element: HTMLElement,\n onResize: (width: number, height: number) => void\n): ResizeObserver {\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect;\n onResize(Math.round(width), Math.round(height));\n }\n });\n\n observer.observe(element);\n\n // Report initial size\n const rect = element.getBoundingClientRect();\n onResize(Math.round(rect.width), Math.round(rect.height));\n\n return observer;\n}\n\n// =============================================================================\n// CORE HOOKS\n// =============================================================================\n\n/**\n * Access the typed client instance\n *\n * @returns Client instance\n * @throws Error if used outside AppsProvider\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const client = useAppsClient<typeof app.tools>();\n *\n * const handleClick = async () => {\n * await client.callTool(\"myTool\", { arg: \"value\" });\n * };\n *\n * return <button onClick={handleClick}>Call Tool</button>;\n * }\n * ```\n */\nexport function useAppsClient<T extends ToolDefs = ToolDefs>(): AppsClient<T> {\n const { client, isConnecting, error } = useAppsContext<T>();\n\n if (error) {\n throw error;\n }\n\n if (isConnecting || !client) {\n throw new Error(\"Client not ready. Make sure AppsProvider has finished connecting.\");\n }\n\n return client;\n}\n\n/**\n * Access current tool result with automatic re-renders\n *\n * @returns Current tool result or undefined\n *\n * @example\n * ```tsx\n * function ResultDisplay() {\n * const result = useToolResult<typeof app.tools>();\n *\n * if (!result?.myTool) {\n * return <div>No results yet</div>;\n * }\n *\n * return <div>{result.myTool.message}</div>;\n * }\n * ```\n */\nexport function useToolResult<T extends ToolDefs = ToolDefs>(): ToolResult<T> | undefined {\n const { client } = useAppsContext<T>();\n const [result, setResult] = useState<ToolResult<T> | undefined>(undefined);\n\n useEffect(() => {\n if (!client) {\n return;\n }\n\n // Get initial tool output if available (wrapped with tool name)\n const initialOutput = client.toolOutput;\n if (initialOutput && Object.keys(initialOutput).length > 0) {\n setResult(initialOutput as ToolResult<T>);\n }\n\n // Subscribe to future tool result updates\n const unsubscribe = client.onToolResult((newResult) => {\n setResult(newResult as ToolResult<T>);\n });\n\n return unsubscribe;\n }, [client]);\n\n return result;\n}\n\n/**\n * Access current tool input\n *\n * @returns Current tool input or undefined\n *\n * @example\n * ```tsx\n * function InputDisplay() {\n * const input = useToolInput();\n * return <pre>{JSON.stringify(input, null, 2)}</pre>;\n * }\n * ```\n */\nexport function useToolInput(): Record<string, unknown> | undefined {\n const { client } = useAppsContext();\n const [input, setInput] = useState<Record<string, unknown> | undefined>(client?.toolInput);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.onToolInput((newInput) => {\n setInput(newInput);\n });\n\n return unsubscribe;\n }, [client]);\n\n return input;\n}\n\n/**\n * Access host context with automatic re-renders on changes\n *\n * @returns Current host context\n *\n * @example\n * ```tsx\n * function ThemedComponent() {\n * const context = useHostContext();\n *\n * return (\n * <div className={context.theme}>\n * Display: {context.displayMode}\n * </div>\n * );\n * }\n * ```\n */\nexport function useHostContext(): HostContext {\n const { client } = useAppsContext();\n const [context, setContext] = useState<HostContext>(client?.hostContext ?? DEFAULT_HOST_CONTEXT);\n\n useEffect(() => {\n if (!client) return;\n\n setContext(client.hostContext);\n return client.onHostContextChange(setContext);\n }, [client]);\n\n return context;\n}\n\n/**\n * Persisted widget state with automatic sync\n *\n * Works like useState but persists across widget reloads.\n * On ChatGPT: Session-scoped persistence\n * On MCP Apps: Silent no-op (returns default, setState is ignored)\n *\n * @param defaultValue - Initial state value\n * @returns [state, setState] tuple\n *\n * @example\n * ```tsx\n * function Counter() {\n * const [count, setCount] = useWidgetState(0);\n *\n * return (\n * <button onClick={() => setCount(c => c + 1)}>\n * Count: {count}\n * </button>\n * );\n * }\n * ```\n */\nexport function useWidgetState<S>(defaultValue: S): [S, (newState: S | ((prev: S) => S)) => void] {\n const { client } = useAppsContext();\n\n const [state, setStateInternal] = useState<S>(() => {\n if (!client) return defaultValue;\n const stored = client.getState<S>();\n return stored ?? defaultValue;\n });\n\n const setState = useCallback(\n (newState: S | ((prev: S) => S)) => {\n setStateInternal((prev) => {\n const next = typeof newState === \"function\" ? (newState as (prev: S) => S)(prev) : newState;\n\n // Persist to client (silent no-op on MCP Apps)\n client?.setState(next);\n\n return next;\n });\n },\n [client]\n );\n\n return [state, setState];\n}\n\n// =============================================================================\n// UTILITY HOOKS\n// =============================================================================\n\n/**\n * Apply host CSS variables to document root\n *\n * Call this once in your root component to apply host theming.\n *\n * @example\n * ```tsx\n * function App() {\n * useHostStyleVariables();\n * return <MyWidget />;\n * }\n * ```\n */\nexport function useHostStyleVariables(): void {\n const context = useHostContext();\n\n useEffect(() => {\n const variables = context.styles?.variables;\n if (!variables) return;\n\n const root = document.documentElement;\n for (const [key, value] of Object.entries(variables)) {\n root.style.setProperty(key, value);\n }\n\n // Cleanup\n return () => {\n for (const key of Object.keys(variables)) {\n root.style.removeProperty(key);\n }\n };\n }, [context.styles?.variables]);\n}\n\n/**\n * Apply theme class to document body\n *\n * @param lightClass - Class name for light theme (default: \"light\")\n * @param darkClass - Class name for dark theme (default: \"dark\")\n *\n * @example\n * ```tsx\n * function App() {\n * useDocumentTheme(\"theme-light\", \"theme-dark\");\n * return <MyWidget />;\n * }\n * ```\n */\nexport function useDocumentTheme(lightClass = \"light\", darkClass = \"dark\"): void {\n const context = useHostContext();\n\n useEffect(() => {\n const { theme } = context;\n const body = document.body;\n\n body.classList.remove(lightClass, darkClass);\n body.classList.add(theme === \"dark\" ? darkClass : lightClass);\n\n return () => {\n body.classList.remove(lightClass, darkClass);\n };\n }, [context.theme, lightClass, darkClass]);\n}\n\n/**\n * Access and manage display mode\n *\n * @returns Display mode state and controls\n *\n * @example\n * ```tsx\n * function DisplayModeToggle() {\n * const { mode, availableModes, requestMode } = useDisplayMode();\n *\n * return (\n * <select value={mode} onChange={e => requestMode(e.target.value)}>\n * {availableModes.map(m => (\n * <option key={m} value={m}>{m}</option>\n * ))}\n * </select>\n * );\n * }\n * ```\n */\nexport function useDisplayMode(): {\n mode: string;\n availableModes: string[];\n requestMode: (mode: \"inline\" | \"fullscreen\" | \"pip\") => Promise<void>;\n} {\n const context = useHostContext();\n const { client } = useAppsContext();\n\n const requestMode = useCallback(\n async (mode: \"inline\" | \"fullscreen\" | \"pip\") => {\n await client?.requestDisplayMode(mode);\n },\n [client]\n );\n\n return {\n mode: context.displayMode,\n availableModes: context.availableDisplayModes,\n requestMode,\n };\n}\n\n/**\n * Access safe area insets for mobile layouts\n *\n * @returns Safe area insets or default zeros\n *\n * @example\n * ```tsx\n * function SafeContent() {\n * const insets = useSafeAreaInsets();\n *\n * return (\n * <div style={{ paddingTop: insets.top, paddingBottom: insets.bottom }}>\n * Content\n * </div>\n * );\n * }\n * ```\n */\nexport function useSafeAreaInsets(): { top: number; right: number; bottom: number; left: number } {\n const context = useHostContext();\n return context.safeAreaInsets ?? DEFAULT_INSETS;\n}\n\n// =============================================================================\n// EVENT HOOKS\n// =============================================================================\n\n/**\n * Subscribe to tool cancellation\n *\n * @param handler - Callback when tool is cancelled\n *\n * @example\n * ```tsx\n * function CancellableOperation() {\n * const [cancelled, setCancelled] = useState(false);\n *\n * useOnToolCancelled((reason) => {\n * setCancelled(true);\n * console.log(\"Cancelled:\", reason);\n * });\n *\n * return cancelled ? <div>Cancelled</div> : <div>Running...</div>;\n * }\n * ```\n */\nexport function useOnToolCancelled(handler: (reason?: string) => void): void {\n const { client } = useAppsContext();\n const handlerRef = useRef(handler);\n\n useEffect(() => {\n handlerRef.current = handler;\n }, [handler]);\n\n useEffect(() => {\n if (!client) return;\n return client.onToolCancelled((reason) => handlerRef.current(reason));\n }, [client]);\n}\n\n/**\n * Subscribe to teardown events\n *\n * @param handler - Callback when widget is torn down\n *\n * @example\n * ```tsx\n * function CleanupComponent() {\n * useOnTeardown((reason) => {\n * console.log(\"Tearing down:\", reason);\n * // Cleanup resources\n * });\n *\n * return <div>Widget</div>;\n * }\n * ```\n */\nexport function useOnTeardown(handler: (reason?: string) => void): void {\n const { client } = useAppsContext();\n const handlerRef = useRef(handler);\n\n useEffect(() => {\n handlerRef.current = handler;\n }, [handler]);\n\n useEffect(() => {\n if (!client) return;\n return client.onTeardown((reason) => handlerRef.current(reason));\n }, [client]);\n}\n\n/**\n * Subscribe to partial/streaming tool input\n *\n * Called when the host sends partial tool arguments during streaming.\n * Useful for showing real-time input as the user types or as the model generates.\n *\n * @param handler - Callback for partial input\n *\n * @example\n * ```tsx\n * function StreamingInput() {\n * const [partialInput, setPartialInput] = useState<Record<string, unknown>>({});\n *\n * useOnToolInputPartial((input) => {\n * setPartialInput(input);\n * });\n *\n * return <pre>{JSON.stringify(partialInput, null, 2)}</pre>;\n * }\n * ```\n */\nexport function useOnToolInputPartial(handler: (input: Record<string, unknown>) => void): void {\n const { client } = useAppsContext();\n const handlerRef = useRef(handler);\n\n useEffect(() => {\n handlerRef.current = handler;\n }, [handler]);\n\n useEffect(() => {\n if (!client) return;\n return client.onToolInputPartial((input) => handlerRef.current(input));\n }, [client]);\n}\n\n// =============================================================================\n// HOST INFORMATION HOOKS\n// =============================================================================\n\n/**\n * Access host capabilities\n *\n * Returns the capabilities advertised by the host during handshake.\n * Use this to check if features like logging or server tools are supported.\n *\n * @returns Host capabilities or undefined if not yet connected\n *\n * @example\n * ```tsx\n * function CapabilitiesDisplay() {\n * const capabilities = useHostCapabilities();\n *\n * return (\n * <div>\n * <p>Logging: {capabilities?.logging ? \"Supported\" : \"Not supported\"}</p>\n * <p>Open Links: {capabilities?.openLinks ? \"Supported\" : \"Not supported\"}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useHostCapabilities(): HostCapabilities | undefined {\n const { client } = useAppsContext();\n const [capabilities, setCapabilities] = useState<HostCapabilities | undefined>(\n client?.getHostCapabilities()\n );\n\n useEffect(() => {\n if (!client) {\n setCapabilities(undefined);\n return;\n }\n\n setCapabilities(client.getHostCapabilities());\n return client.onHostContextChange(() => setCapabilities(client.getHostCapabilities()));\n }, [client]);\n\n return capabilities;\n}\n\n/**\n * Access host version information\n *\n * Returns the name and version of the host application.\n *\n * @returns Host version info or undefined if not yet connected\n *\n * @example\n * ```tsx\n * function HostInfo() {\n * const hostVersion = useHostVersion();\n *\n * if (!hostVersion) return <div>Loading...</div>;\n *\n * return (\n * <div>\n * Running on {hostVersion.name} v{hostVersion.version}\n * </div>\n * );\n * }\n * ```\n */\nexport function useHostVersion(): HostVersion | undefined {\n const { client } = useAppsContext();\n const [version, setVersion] = useState<HostVersion | undefined>(() => client?.getHostVersion());\n\n useEffect(() => {\n if (!client) {\n setVersion(undefined);\n return;\n }\n\n // Update version when client changes\n setVersion(client.getHostVersion());\n }, [client]);\n\n return version;\n}\n\n// =============================================================================\n// SIZE NOTIFICATION HOOKS\n// =============================================================================\n\n/**\n * Hook to set up automatic size change notifications\n *\n * Creates a ResizeObserver that automatically sends size changed\n * notifications to the host when the observed element resizes.\n *\n * @returns Ref to attach to the element to observe\n *\n * @example\n * ```tsx\n * function AutoSizeWidget() {\n * const containerRef = useSizeChangedNotifications();\n *\n * return (\n * <div ref={containerRef}>\n * <p>Content that may change size...</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useSizeChangedNotifications(): RefObject<HTMLElement | null> {\n const { client } = useAppsContext();\n const containerRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n const element = containerRef.current;\n if (!client || !element || typeof ResizeObserver === \"undefined\") return;\n\n const observer = createSizeObserver(element, (width, height) => {\n void client.sendSizeChanged({ width, height });\n });\n\n return () => observer.disconnect();\n }, [client]);\n\n return containerRef;\n}\n\n// =============================================================================\n// FILE OPERATION HOOKS\n// =============================================================================\n\n/**\n * File upload result\n */\nexport interface FileUploadResult {\n /** Uploaded file ID */\n fileId: string;\n}\n\n/**\n * File upload state\n */\nexport interface UseFileUploadState {\n /** Whether file upload is supported on this platform */\n isSupported: boolean;\n /** Whether upload is in progress */\n isUploading: boolean;\n /** Upload error if any */\n error: Error | null;\n /** Last uploaded file ID */\n fileId: string | null;\n}\n\n/**\n * Hook for uploading files (ChatGPT only)\n *\n * Provides a function to upload files and tracks upload state.\n * On unsupported platforms, isSupported will be false.\n *\n * Supported file types: PNG, JPEG, WebP images\n *\n * @returns Upload function and state\n *\n * @example\n * ```tsx\n * function ImageUploader() {\n * const { upload, isSupported, isUploading, error, fileId } = useFileUpload();\n *\n * if (!isSupported) {\n * return <div>File upload not supported on this platform</div>;\n * }\n *\n * const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {\n * const file = e.target.files?.[0];\n * if (file) {\n * const result = await upload(file);\n * console.log(\"Uploaded:\", result?.fileId);\n * }\n * };\n *\n * return (\n * <div>\n * <input type=\"file\" accept=\"image/*\" onChange={handleFileChange} />\n * {isUploading && <span>Uploading...</span>}\n * {error && <span>Error: {error.message}</span>}\n * {fileId && <span>Uploaded: {fileId}</span>}\n * </div>\n * );\n * }\n * ```\n */\nexport function useFileUpload(): UseFileUploadState & {\n upload: (file: File) => Promise<FileUploadResult | null>;\n} {\n const { client } = useAppsContext();\n const isSupported = !!client?.uploadFile;\n const [isUploading, setIsUploading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [fileId, setFileId] = useState<string | null>(null);\n\n const upload = useCallback(\n async (file: File): Promise<FileUploadResult | null> => {\n if (!client?.uploadFile) {\n setError(new Error(\"File upload not supported on this platform\"));\n return null;\n }\n\n setIsUploading(true);\n setError(null);\n\n try {\n const result = await client.uploadFile(file);\n setFileId(result.fileId);\n return result;\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n return null;\n } finally {\n setIsUploading(false);\n }\n },\n [client]\n );\n\n return { isSupported, isUploading, error, fileId, upload };\n}\n\n/**\n * Hook for getting file download URLs (ChatGPT only)\n *\n * Provides a function to get temporary download URLs for uploaded files.\n * On unsupported platforms, isSupported will be false.\n *\n * @returns Download URL function and state\n *\n * @example\n * ```tsx\n * function FileDownloader({ fileId }: { fileId: string }) {\n * const { getDownloadUrl, isSupported, isLoading, error, downloadUrl } = useFileDownload();\n *\n * useEffect(() => {\n * if (fileId && isSupported) {\n * getDownloadUrl(fileId);\n * }\n * }, [fileId, isSupported, getDownloadUrl]);\n *\n * if (!isSupported) return <div>Not supported</div>;\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (downloadUrl) return <img src={downloadUrl} alt=\"Uploaded file\" />;\n *\n * return null;\n * }\n * ```\n */\nexport function useFileDownload(): {\n isSupported: boolean;\n isLoading: boolean;\n error: Error | null;\n downloadUrl: string | null;\n getDownloadUrl: (fileId: string) => Promise<string | null>;\n} {\n const { client } = useAppsContext();\n const isSupported = !!client?.getFileDownloadUrl;\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [downloadUrl, setDownloadUrl] = useState<string | null>(null);\n\n const getDownloadUrl = useCallback(\n async (fileId: string): Promise<string | null> => {\n if (!client?.getFileDownloadUrl) {\n setError(new Error(\"File download not supported on this platform\"));\n return null;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await client.getFileDownloadUrl(fileId);\n setDownloadUrl(result.downloadUrl);\n return result.downloadUrl;\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n return null;\n } finally {\n setIsLoading(false);\n }\n },\n [client]\n );\n\n return { isSupported, isLoading, error, downloadUrl, getDownloadUrl };\n}\n\n// =============================================================================\n// LAYOUT HOOKS\n// =============================================================================\n\n/**\n * Hook to notify host of widget's intrinsic height (ChatGPT only)\n *\n * Automatically reports height changes to prevent scroll clipping.\n * Returns a ref to attach to your root element for automatic height tracking,\n * or a manual notify function for custom height reporting.\n *\n * @returns Ref for auto-tracking and manual notify function\n *\n * @example\n * ```tsx\n * // Automatic height tracking\n * function AutoHeightWidget() {\n * const { containerRef, isSupported } = useIntrinsicHeight();\n *\n * return (\n * <div ref={containerRef}>\n * <p>Content that may change height...</p>\n * </div>\n * );\n * }\n *\n * // Manual height notification\n * function ManualHeightWidget() {\n * const { notify, isSupported } = useIntrinsicHeight();\n *\n * useEffect(() => {\n * // Notify after content loads\n * notify(500);\n * }, [notify]);\n *\n * return <div style={{ height: 500 }}>Fixed height content</div>;\n * }\n * ```\n */\nexport function useIntrinsicHeight(): {\n /** Whether intrinsic height notification is supported */\n isSupported: boolean;\n /** Ref to attach to container for automatic height tracking */\n containerRef: RefObject<HTMLElement | null>;\n /** Manually notify host of height */\n notify: (height: number) => void;\n} {\n const { client } = useAppsContext();\n const containerRef = useRef<HTMLElement | null>(null);\n const isSupported = !!client?.notifyIntrinsicHeight;\n\n const notify = useCallback(\n (height: number) => {\n client?.notifyIntrinsicHeight?.(height);\n },\n [client]\n );\n\n useEffect(() => {\n const element = containerRef.current;\n if (!client?.notifyIntrinsicHeight || !element || typeof ResizeObserver === \"undefined\") return;\n\n const observer = createSizeObserver(element, (_width, height) => {\n client.notifyIntrinsicHeight?.(height);\n });\n\n return () => observer.disconnect();\n }, [client]);\n\n return { isSupported, containerRef, notify };\n}\n\n/**\n * Hook to access the current view identifier (ChatGPT only)\n *\n * Useful for multi-view widgets that need to know which view is active.\n *\n * @returns Current view identifier or undefined\n *\n * @example\n * ```tsx\n * function MultiViewWidget() {\n * const view = useView();\n *\n * switch (view) {\n * case \"settings\":\n * return <SettingsView />;\n * case \"details\":\n * return <DetailsView />;\n * default:\n * return <MainView />;\n * }\n * }\n * ```\n */\nexport function useView(): string | undefined {\n const context = useHostContext();\n return context.view;\n}\n\n// =============================================================================\n// MODAL HOOKS\n// =============================================================================\n\n/**\n * Hook for showing host-owned modal dialogs (ChatGPT only)\n *\n * Spawns native ChatGPT modals for confirmations, inputs, etc.\n * On unsupported platforms, isSupported will be false.\n *\n * @returns Modal function and state\n *\n * @example\n * ```tsx\n * function DeleteButton() {\n * const { showModal, isSupported, isOpen } = useModal();\n *\n * const handleDelete = async () => {\n * const result = await showModal({\n * title: \"Confirm Delete\",\n * body: \"Are you sure you want to delete this item?\",\n * buttons: [\n * { label: \"Cancel\", variant: \"secondary\", value: \"cancel\" },\n * { label: \"Delete\", variant: \"destructive\", value: \"delete\" },\n * ],\n * });\n *\n * if (result?.action === \"delete\") {\n * // Perform delete\n * }\n * };\n *\n * if (!isSupported) {\n * return <button onClick={() => window.confirm(\"Delete?\")}>Delete</button>;\n * }\n *\n * return (\n * <button onClick={handleDelete} disabled={isOpen}>\n * Delete\n * </button>\n * );\n * }\n *\n * // Input modal example\n * function RenameButton() {\n * const { showModal } = useModal();\n *\n * const handleRename = async () => {\n * const result = await showModal({\n * title: \"Rename Item\",\n * input: {\n * type: \"text\",\n * placeholder: \"Enter new name\",\n * defaultValue: \"Current Name\",\n * },\n * buttons: [\n * { label: \"Cancel\", variant: \"secondary\", value: \"cancel\" },\n * { label: \"Rename\", variant: \"primary\", value: \"rename\" },\n * ],\n * });\n *\n * if (result?.action === \"rename\" && result.inputValue) {\n * console.log(\"New name:\", result.inputValue);\n * }\n * };\n *\n * return <button onClick={handleRename}>Rename</button>;\n * }\n * ```\n */\nexport function useModal(): {\n /** Whether modal API is supported */\n isSupported: boolean;\n /** Whether a modal is currently open */\n isOpen: boolean;\n /** Show a modal dialog */\n showModal: (options: ModalOptions) => Promise<ModalResult | null>;\n} {\n const { client } = useAppsContext();\n const isSupported = !!client?.requestModal;\n const [isOpen, setIsOpen] = useState(false);\n\n const showModal = useCallback(\n async (options: ModalOptions): Promise<ModalResult | null> => {\n if (!client?.requestModal) {\n return null;\n }\n\n setIsOpen(true);\n try {\n const result = await client.requestModal(options);\n return result;\n } finally {\n setIsOpen(false);\n }\n },\n [client]\n );\n\n return { isSupported, isOpen, showModal };\n}\n\n// =============================================================================\n// DEBUG LOGGING HOOKS\n// =============================================================================\n\n/**\n * Access the debug logger with automatic adapter injection\n *\n * The adapter is automatically configured when AppsProvider connects.\n * Use this hook to access the logger and optionally configure it.\n *\n * @param config - Optional configuration to apply\n * @returns The configured client debug logger\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const logger = useDebugLogger({ enabled: true, level: \"debug\" });\n *\n * const handleClick = () => {\n * logger.info(\"Button clicked\", { timestamp: Date.now() });\n * };\n *\n * return <button onClick={handleClick}>Click me</button>;\n * }\n * ```\n */\nexport function useDebugLogger(config?: Partial<ClientDebugConfig>): ClientDebugLogger {\n // Verify we're inside AppsProvider (adapter is set by createClient)\n useAppsContext();\n\n // Apply configuration when it changes\n useEffect(() => {\n if (config) {\n clientDebugLogger.configure(config);\n }\n }, [config]);\n\n return clientDebugLogger;\n}\n"]} |
+25
-9
| import { ToolDefs, AppsClient, ToolResult, HostContext, ModalOptions, ModalResult, ClientDebugConfig, ClientDebugLogger, HostCapabilities, HostVersion } from '@mcp-apps-kit/ui'; | ||
| export { AppCapabilities, AppToolDefinition, AppsClient, CallToolHandler, ClientDebugConfig, ClientDebugLogger, HostCapabilities, HostContext, HostVersion, ListToolsHandler, ModalButton, ModalInput, ModalOptions, ModalResult, SizeChangedParams, ToolResult } from '@mcp-apps-kit/ui'; | ||
| import React, { ReactNode, ComponentType } from 'react'; | ||
| import { ReactNode, ComponentType, JSX, RefObject } from 'react'; | ||
@@ -9,7 +9,2 @@ /** | ||
| interface AppsContextValue<T extends ToolDefs = ToolDefs> { | ||
| client: AppsClient<T> | null; | ||
| isConnecting: boolean; | ||
| error: Error | null; | ||
| } | ||
| /** | ||
@@ -31,2 +26,15 @@ * Props for AppsProvider | ||
| /** | ||
| * Enable automatic size change notifications (MCP adapter only) | ||
| * | ||
| * When enabled, the UI automatically reports its size changes to the host | ||
| * using a ResizeObserver on document.body and document.documentElement. | ||
| * The host can then resize the UI container accordingly. | ||
| * | ||
| * Note: This option is only applied during initial mount. Changing it | ||
| * at runtime will have no effect. | ||
| * | ||
| * @default true | ||
| */ | ||
| autoResize?: boolean; | ||
| /** | ||
| * Fallback UI while client is connecting | ||
@@ -59,4 +67,12 @@ */ | ||
| */ | ||
| declare function AppsProvider<T extends ToolDefs = ToolDefs>({ children, client: providedClient, forceAdapter: _forceAdapter, fallback, errorFallback: ErrorFallback, }: AppsProviderProps<T>): React.JSX.Element; | ||
| declare function AppsProvider<T extends ToolDefs = ToolDefs>({ children, client: providedClient, forceAdapter: _forceAdapter, autoResize, fallback, errorFallback: ErrorFallback, }: AppsProviderProps<T>): JSX.Element; | ||
| /** | ||
| * Context value exposed by useAppsContext | ||
| */ | ||
| interface AppsContextValue<T extends ToolDefs = ToolDefs> { | ||
| client: AppsClient<T> | null; | ||
| isConnecting: boolean; | ||
| error: Error | null; | ||
| } | ||
| /** | ||
| * Internal hook to access the context | ||
@@ -372,3 +388,3 @@ * @internal | ||
| */ | ||
| declare function useSizeChangedNotifications(): React.RefObject<HTMLElement | null>; | ||
| declare function useSizeChangedNotifications(): RefObject<HTMLElement | null>; | ||
| /** | ||
@@ -509,3 +525,3 @@ * File upload result | ||
| /** Ref to attach to container for automatic height tracking */ | ||
| containerRef: React.RefObject<HTMLElement | null>; | ||
| containerRef: RefObject<HTMLElement | null>; | ||
| /** Manually notify host of height */ | ||
@@ -512,0 +528,0 @@ notify: (height: number) => void; |
+25
-9
| import { ToolDefs, AppsClient, ToolResult, HostContext, ModalOptions, ModalResult, ClientDebugConfig, ClientDebugLogger, HostCapabilities, HostVersion } from '@mcp-apps-kit/ui'; | ||
| export { AppCapabilities, AppToolDefinition, AppsClient, CallToolHandler, ClientDebugConfig, ClientDebugLogger, HostCapabilities, HostContext, HostVersion, ListToolsHandler, ModalButton, ModalInput, ModalOptions, ModalResult, SizeChangedParams, ToolResult } from '@mcp-apps-kit/ui'; | ||
| import React, { ReactNode, ComponentType } from 'react'; | ||
| import { ReactNode, ComponentType, JSX, RefObject } from 'react'; | ||
@@ -9,7 +9,2 @@ /** | ||
| interface AppsContextValue<T extends ToolDefs = ToolDefs> { | ||
| client: AppsClient<T> | null; | ||
| isConnecting: boolean; | ||
| error: Error | null; | ||
| } | ||
| /** | ||
@@ -31,2 +26,15 @@ * Props for AppsProvider | ||
| /** | ||
| * Enable automatic size change notifications (MCP adapter only) | ||
| * | ||
| * When enabled, the UI automatically reports its size changes to the host | ||
| * using a ResizeObserver on document.body and document.documentElement. | ||
| * The host can then resize the UI container accordingly. | ||
| * | ||
| * Note: This option is only applied during initial mount. Changing it | ||
| * at runtime will have no effect. | ||
| * | ||
| * @default true | ||
| */ | ||
| autoResize?: boolean; | ||
| /** | ||
| * Fallback UI while client is connecting | ||
@@ -59,4 +67,12 @@ */ | ||
| */ | ||
| declare function AppsProvider<T extends ToolDefs = ToolDefs>({ children, client: providedClient, forceAdapter: _forceAdapter, fallback, errorFallback: ErrorFallback, }: AppsProviderProps<T>): React.JSX.Element; | ||
| declare function AppsProvider<T extends ToolDefs = ToolDefs>({ children, client: providedClient, forceAdapter: _forceAdapter, autoResize, fallback, errorFallback: ErrorFallback, }: AppsProviderProps<T>): JSX.Element; | ||
| /** | ||
| * Context value exposed by useAppsContext | ||
| */ | ||
| interface AppsContextValue<T extends ToolDefs = ToolDefs> { | ||
| client: AppsClient<T> | null; | ||
| isConnecting: boolean; | ||
| error: Error | null; | ||
| } | ||
| /** | ||
| * Internal hook to access the context | ||
@@ -372,3 +388,3 @@ * @internal | ||
| */ | ||
| declare function useSizeChangedNotifications(): React.RefObject<HTMLElement | null>; | ||
| declare function useSizeChangedNotifications(): RefObject<HTMLElement | null>; | ||
| /** | ||
@@ -509,3 +525,3 @@ * File upload result | ||
| /** Ref to attach to container for automatic height tracking */ | ||
| containerRef: React.RefObject<HTMLElement | null>; | ||
| containerRef: RefObject<HTMLElement | null>; | ||
| /** Manually notify host of height */ | ||
@@ -512,0 +528,0 @@ notify: (height: number) => void; |
+1
-1
@@ -1,2 +0,2 @@ | ||
| import {createContext,useState,useEffect,useContext,useCallback,useRef}from'react';import {createClient,clientDebugLogger}from'@mcp-apps-kit/ui';import {jsx,Fragment}from'react/jsx-runtime';var T=createContext(null);function D({children:e,client:t,forceAdapter:o,fallback:s,errorFallback:r}){let[n,i]=useState(t??null),[a,p]=useState(!t),[g,C]=useState(null);if(useEffect(()=>{if(t){i(t),p(false);return}(async()=>{try{let b=await createClient({forceAdapter:o});i(b),p(!1);}catch(b){C(b instanceof Error?b:new Error(String(b))),p(false);}})();},[t,o]),g&&r)return jsx(r,{error:g,reset:()=>C(null)});if(a)return jsx(Fragment,{children:s??null});let S={client:n,isConnecting:a,error:g};return jsx(T.Provider,{value:S,children:e})}function l(){let e=useContext(T);if(!e)throw new Error("useAppsContext must be used within an AppsProvider");return e}function M(){let{client:e,isConnecting:t,error:o}=l();if(o)throw o;if(t||!e)throw new Error("Client not ready. Make sure AppsProvider has finished connecting.");return e}function I(){let{client:e}=l(),[t,o]=useState(void 0);return useEffect(()=>{if(!e)return;let s=e.toolOutput;return s&&Object.keys(s).length>0&&o(s),e.onToolResult(n=>{o(n);})},[e]),t}function U(){let{client:e}=l(),[t,o]=useState(e?.toolInput);return useEffect(()=>e?e.onToolInput(r=>{o(r);}):void 0,[e]),t}function f(){let{client:e}=l(),[t,o]=useState(e?.hostContext??{theme:"light",displayMode:"inline",availableDisplayModes:["inline"],viewport:{width:0,height:0},locale:"en-US",platform:"web"});return useEffect(()=>e?(o(e.hostContext),e.onHostContextChange(r=>{o(r);})):void 0,[e]),t}function P(e){let{client:t}=l(),[o,s]=useState(()=>t?t.getState()??e:e),r=useCallback(n=>{s(i=>{let a=typeof n=="function"?n(i):n;return t?.setState(a),a});},[t]);return [o,r]}function E(){let e=f();useEffect(()=>{let t=e.styles?.variables;if(!t)return;let o=document.documentElement;for(let[s,r]of Object.entries(t))o.style.setProperty(s,r);return ()=>{for(let s of Object.keys(t))o.style.removeProperty(s);}},[e.styles?.variables]);}function F(e="light",t="dark"){let o=f();useEffect(()=>{let{theme:s}=o,r=document.body;return r.classList.remove(e,t),r.classList.add(s==="dark"?t:e),()=>{r.classList.remove(e,t);}},[o.theme,e,t]);}function O(){let e=f(),{client:t}=l(),o=useCallback(async s=>{await t?.requestDisplayMode(s);},[t]);return {mode:e.displayMode,availableModes:e.availableDisplayModes,requestMode:o}}function L(){return f().safeAreaInsets??{top:0,right:0,bottom:0,left:0}}function V(e){let{client:t}=l();useEffect(()=>t?t.onToolCancelled(e):void 0,[t,e]);}function k(e){let{client:t}=l();useEffect(()=>t?t.onTeardown(e):void 0,[t,e]);}function z(e){let{client:t}=l();useEffect(()=>t?t.onToolInputPartial(e):void 0,[t,e]);}function q(){let{client:e}=l(),[t,o]=useState(e?.getHostCapabilities());return useEffect(()=>{e&&o(e.getHostCapabilities());},[e]),t}function N(){let{client:e}=l(),[t,o]=useState(e?.getHostVersion());return useEffect(()=>{e&&o(e.getHostVersion());},[e]),t}function j(){let{client:e}=l(),t=useRef(null);return useEffect(()=>{if(!e||typeof ResizeObserver>"u")return;let o=t.current;if(!o)return;let s=new ResizeObserver(n=>{for(let i of n){let{width:a,height:p}=i.contentRect;e.sendSizeChanged({width:Math.round(a),height:Math.round(p)});}});s.observe(o);let r=o.getBoundingClientRect();return e.sendSizeChanged({width:Math.round(r.width),height:Math.round(r.height)}),()=>s.disconnect()},[e]),t}function B(){let{client:e}=l(),[t,o]=useState({isSupported:false,isUploading:false,error:null,fileId:null});useEffect(()=>{o(r=>({...r,isSupported:!!e?.uploadFile}));},[e]);let s=useCallback(async r=>{if(!e?.uploadFile)return o(n=>({...n,error:new Error("File upload not supported on this platform")})),null;o(n=>({...n,isUploading:true,error:null}));try{let n=await e.uploadFile(r);return o(i=>({...i,isUploading:!1,fileId:n.fileId})),n}catch(n){let i=n instanceof Error?n:new Error(String(n));return o(a=>({...a,isUploading:false,error:i})),null}},[e]);return {...t,upload:s}}function W(){let{client:e}=l(),[t,o]=useState({isSupported:false,isLoading:false,error:null,downloadUrl:null});useEffect(()=>{o(r=>({...r,isSupported:!!e?.getFileDownloadUrl}));},[e]);let s=useCallback(async r=>{if(!e?.getFileDownloadUrl)return o(n=>({...n,error:new Error("File download not supported on this platform")})),null;o(n=>({...n,isLoading:true,error:null}));try{let n=await e.getFileDownloadUrl(r);return o(i=>({...i,isLoading:!1,downloadUrl:n.downloadUrl})),n.downloadUrl}catch(n){let i=n instanceof Error?n:new Error(String(n));return o(a=>({...a,isLoading:false,error:i})),null}},[e]);return {...t,getDownloadUrl:s}}function J(){let{client:e}=l(),t=useRef(null),[o,s]=useState(false);useEffect(()=>{s(!!e?.notifyIntrinsicHeight);},[e]);let r=useCallback(n=>{e?.notifyIntrinsicHeight?.(n);},[e]);return useEffect(()=>{if(!e?.notifyIntrinsicHeight||!t.current)return;let n=t.current,i=new ResizeObserver(a=>{for(let p of a){let g=p.contentRect.height;e.notifyIntrinsicHeight?.(g);}});return i.observe(n),e.notifyIntrinsicHeight(n.offsetHeight),()=>i.disconnect()},[e]),{isSupported:o,containerRef:t,notify:r}}function X(){return f().view}function G(){let{client:e}=l(),[t,o]=useState(false),[s,r]=useState(false);useEffect(()=>{o(!!e?.requestModal);},[e]);let n=useCallback(async i=>{if(!e?.requestModal)return null;r(true);try{return await e.requestModal(i)}finally{r(false);}},[e]);return {isSupported:t,isOpen:s,showModal:n}}function K(e){return l(),useEffect(()=>{e&&clientDebugLogger.configure(e);},[e]),clientDebugLogger}export{D as AppsProvider,M as useAppsClient,l as useAppsContext,K as useDebugLogger,O as useDisplayMode,F as useDocumentTheme,W as useFileDownload,B as useFileUpload,q as useHostCapabilities,f as useHostContext,E as useHostStyleVariables,N as useHostVersion,J as useIntrinsicHeight,G as useModal,k as useOnTeardown,V as useOnToolCancelled,z as useOnToolInputPartial,L as useSafeAreaInsets,j as useSizeChangedNotifications,U as useToolInput,I as useToolResult,X as useView,P as useWidgetState};//# sourceMappingURL=index.js.map | ||
| import {createContext,useState,useEffect,useContext,useCallback,useRef}from'react';import {createClient,clientDebugLogger}from'@mcp-apps-kit/ui';import {jsx,Fragment}from'react/jsx-runtime';var h=createContext(null);function M({children:e,client:t,forceAdapter:n,autoResize:o,fallback:r,errorFallback:s}){let[p,a]=useState(t??null),[f,d]=useState(!t),[l,y]=useState(null);if(useEffect(()=>{if(t){a(t),d(false);return}(async()=>{try{let m=await createClient({forceAdapter:n,autoResize:o});a(m),d(!1);}catch(m){y(m instanceof Error?m:new Error(String(m))),d(false);}})();},[t,n]),l&&s)return jsx(s,{error:l,reset:()=>y(null)});if(f)return jsx(Fragment,{children:r??null});let v={client:p,isConnecting:f,error:l};return jsx(h.Provider,{value:v,children:e})}function i(){let e=useContext(h);if(!e)throw new Error("useAppsContext must be used within an AppsProvider");return e}var I={theme:"light",displayMode:"inline",availableDisplayModes:["inline"],viewport:{width:0,height:0},locale:"en-US",platform:"web"},O={top:0,right:0,bottom:0,left:0};function w(e,t){let n=new ResizeObserver(r=>{for(let s of r){let{width:p,height:a}=s.contentRect;t(Math.round(p),Math.round(a));}});n.observe(e);let o=e.getBoundingClientRect();return t(Math.round(o.width),Math.round(o.height)),n}function U(){let{client:e,isConnecting:t,error:n}=i();if(n)throw n;if(t||!e)throw new Error("Client not ready. Make sure AppsProvider has finished connecting.");return e}function P(){let{client:e}=i(),[t,n]=useState(void 0);return useEffect(()=>{if(!e)return;let o=e.toolOutput;return o&&Object.keys(o).length>0&&n(o),e.onToolResult(s=>{n(s);})},[e]),t}function F(){let{client:e}=i(),[t,n]=useState(e?.toolInput);return useEffect(()=>e?e.onToolInput(r=>{n(r);}):void 0,[e]),t}function b(){let{client:e}=i(),[t,n]=useState(e?.hostContext??I);return useEffect(()=>{if(e)return n(e.hostContext),e.onHostContextChange(n)},[e]),t}function L(e){let{client:t}=i(),[n,o]=useState(()=>t?t.getState()??e:e),r=useCallback(s=>{o(p=>{let a=typeof s=="function"?s(p):s;return t?.setState(a),a});},[t]);return [n,r]}function V(){let e=b();useEffect(()=>{let t=e.styles?.variables;if(!t)return;let n=document.documentElement;for(let[o,r]of Object.entries(t))n.style.setProperty(o,r);return ()=>{for(let o of Object.keys(t))n.style.removeProperty(o);}},[e.styles?.variables]);}function k(e="light",t="dark"){let n=b();useEffect(()=>{let{theme:o}=n,r=document.body;return r.classList.remove(e,t),r.classList.add(o==="dark"?t:e),()=>{r.classList.remove(e,t);}},[n.theme,e,t]);}function z(){let e=b(),{client:t}=i(),n=useCallback(async o=>{await t?.requestDisplayMode(o);},[t]);return {mode:e.displayMode,availableModes:e.availableDisplayModes,requestMode:n}}function N(){return b().safeAreaInsets??O}function q(e){let{client:t}=i(),n=useRef(e);useEffect(()=>{n.current=e;},[e]),useEffect(()=>{if(t)return t.onToolCancelled(o=>n.current(o))},[t]);}function j(e){let{client:t}=i(),n=useRef(e);useEffect(()=>{n.current=e;},[e]),useEffect(()=>{if(t)return t.onTeardown(o=>n.current(o))},[t]);}function X(e){let{client:t}=i(),n=useRef(e);useEffect(()=>{n.current=e;},[e]),useEffect(()=>{if(t)return t.onToolInputPartial(o=>n.current(o))},[t]);}function _(){let{client:e}=i(),[t,n]=useState(e?.getHostCapabilities());return useEffect(()=>{if(!e){n(void 0);return}return n(e.getHostCapabilities()),e.onHostContextChange(()=>n(e.getHostCapabilities()))},[e]),t}function B(){let{client:e}=i(),[t,n]=useState(()=>e?.getHostVersion());return useEffect(()=>{if(!e){n(void 0);return}n(e.getHostVersion());},[e]),t}function J(){let{client:e}=i(),t=useRef(null);return useEffect(()=>{let n=t.current;if(!e||!n||typeof ResizeObserver>"u")return;let o=w(n,(r,s)=>{e.sendSizeChanged({width:r,height:s});});return ()=>o.disconnect()},[e]),t}function W(){let{client:e}=i(),t=!!e?.uploadFile,[n,o]=useState(false),[r,s]=useState(null),[p,a]=useState(null),f=useCallback(async d=>{if(!e?.uploadFile)return s(new Error("File upload not supported on this platform")),null;o(true),s(null);try{let l=await e.uploadFile(d);return a(l.fileId),l}catch(l){return s(l instanceof Error?l:new Error(String(l))),null}finally{o(false);}},[e]);return {isSupported:t,isUploading:n,error:r,fileId:p,upload:f}}function G(){let{client:e}=i(),t=!!e?.getFileDownloadUrl,[n,o]=useState(false),[r,s]=useState(null),[p,a]=useState(null),f=useCallback(async d=>{if(!e?.getFileDownloadUrl)return s(new Error("File download not supported on this platform")),null;o(true),s(null);try{let l=await e.getFileDownloadUrl(d);return a(l.downloadUrl),l.downloadUrl}catch(l){return s(l instanceof Error?l:new Error(String(l))),null}finally{o(false);}},[e]);return {isSupported:t,isLoading:n,error:r,downloadUrl:p,getDownloadUrl:f}}function K(){let{client:e}=i(),t=useRef(null),n=!!e?.notifyIntrinsicHeight,o=useCallback(r=>{e?.notifyIntrinsicHeight?.(r);},[e]);return useEffect(()=>{let r=t.current;if(!e?.notifyIntrinsicHeight||!r||typeof ResizeObserver>"u")return;let s=w(r,(p,a)=>{e.notifyIntrinsicHeight?.(a);});return ()=>s.disconnect()},[e]),{isSupported:n,containerRef:t,notify:o}}function Q(){return b().view}function Y(){let{client:e}=i(),t=!!e?.requestModal,[n,o]=useState(false),r=useCallback(async s=>{if(!e?.requestModal)return null;o(true);try{return await e.requestModal(s)}finally{o(false);}},[e]);return {isSupported:t,isOpen:n,showModal:r}}function Z(e){return i(),useEffect(()=>{e&&clientDebugLogger.configure(e);},[e]),clientDebugLogger}export{M as AppsProvider,U as useAppsClient,i as useAppsContext,Z as useDebugLogger,z as useDisplayMode,k as useDocumentTheme,G as useFileDownload,W as useFileUpload,_ as useHostCapabilities,b as useHostContext,V as useHostStyleVariables,B as useHostVersion,K as useIntrinsicHeight,Y as useModal,j as useOnTeardown,q as useOnToolCancelled,X as useOnToolInputPartial,N as useSafeAreaInsets,J as useSizeChangedNotifications,F as useToolInput,P as useToolResult,Q as useView,L as useWidgetState};//# sourceMappingURL=index.js.map | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/context.tsx","../src/hooks.ts"],"names":["AppsContext","createContext","AppsProvider","children","providedClient","_forceAdapter","fallback","ErrorFallback","client","setClient","useState","isConnecting","setIsConnecting","error","setError","useEffect","newClient","createClient","err","jsx","Fragment","contextValue","useAppsContext","context","useContext","useAppsClient","useToolResult","result","setResult","initialOutput","newResult","useToolInput","input","setInput","newInput","useHostContext","setContext","newContext","useWidgetState","defaultValue","state","setStateInternal","setState","useCallback","newState","prev","next","useHostStyleVariables","variables","root","key","value","useDocumentTheme","lightClass","darkClass","theme","body","useDisplayMode","requestMode","mode","useSafeAreaInsets","useOnToolCancelled","handler","useOnTeardown","useOnToolInputPartial","useHostCapabilities","capabilities","setCapabilities","useHostVersion","version","setVersion","useSizeChangedNotifications","containerRef","useRef","element","observer","entries","entry","width","height","rect","useFileUpload","upload","file","useFileDownload","getDownloadUrl","fileId","useIntrinsicHeight","isSupported","setIsSupported","notify","useView","useModal","isOpen","setIsOpen","showModal","options","useDebugLogger","config","clientDebugLogger"],"mappings":"8LAkCA,IAAMA,CAAAA,CAAcC,cAA+C,IAAI,CAAA,CAuDhE,SAASC,CAAAA,CAA4C,CAC1D,SAAAC,CAAAA,CACA,MAAA,CAAQC,CAAAA,CACR,YAAA,CAAcC,EACd,QAAA,CAAAC,CAAAA,CACA,cAAeC,CACjB,CAAA,CAA4C,CAC1C,GAAM,CAACC,CAAAA,CAAQC,CAAS,EAAIC,QAAAA,CAA+BN,CAAAA,EAAkB,IAAI,CAAA,CAC3E,CAACO,EAAcC,CAAe,CAAA,CAAIF,QAAAA,CAAS,CAACN,CAAc,CAAA,CAC1D,CAACS,EAAOC,CAAQ,CAAA,CAAIJ,SAAuB,IAAI,CAAA,CA0BrD,GAxBAK,SAAAA,CAAU,IAAM,CACd,GAAIX,EAAgB,CAClBK,CAAAA,CAAUL,CAAc,CAAA,CACxBQ,CAAAA,CAAgB,KAAK,CAAA,CACrB,MACF,CAAA,CAGmB,SAAY,CAC7B,GAAI,CACF,IAAMI,CAAAA,CAAY,MAAMC,YAAAA,CAAgB,CACtC,aAAcZ,CAChB,CAAC,CAAA,CACDI,CAAAA,CAAUO,CAAS,CAAA,CACnBJ,CAAAA,CAAgB,CAAA,CAAK,EACvB,OAASM,CAAAA,CAAK,CACZJ,EAASI,CAAAA,YAAe,KAAA,CAAQA,EAAM,IAAI,KAAA,CAAM,MAAA,CAAOA,CAAG,CAAC,CAAC,CAAA,CAC5DN,EAAgB,KAAK,EACvB,CACF,CAAA,IAGF,CAAA,CAAG,CAACR,EAAgBC,CAAa,CAAC,EAE9BQ,CAAAA,EAASN,CAAAA,CACX,OAAOY,GAAAA,CAACZ,CAAAA,CAAA,CAAc,KAAA,CAAOM,EAAO,KAAA,CAAO,IAAMC,EAAS,IAAI,CAAA,CAAG,EAKnE,GAAIH,CAAAA,CACF,OAAOQ,GAAAA,CAAAC,SAAA,CAAG,QAAA,CAAAd,GAAY,IAAA,CAAK,CAAA,CAK7B,IAAMe,CAAAA,CAAyC,CAC7C,MAAA,CAAQb,CAAAA,CACR,aAAAG,CAAAA,CACA,KAAA,CAAAE,CACF,CAAA,CAEA,OAAOM,IAACnB,CAAAA,CAAY,QAAA,CAAZ,CAAqB,KAAA,CAAOqB,EAAe,QAAA,CAAAlB,CAAAA,CAAS,CAC9D,CAUO,SAASmB,GAAqE,CACnF,IAAMC,CAAAA,CAAUC,UAAAA,CAAWxB,CAAW,CAAA,CACtC,GAAI,CAACuB,CAAAA,CACH,MAAM,IAAI,KAAA,CAAM,oDAAoD,CAAA,CAEtE,OAAOA,CACT,CCrHO,SAASE,CAAAA,EAA8D,CAC5E,GAAM,CAAE,OAAAjB,CAAAA,CAAQ,YAAA,CAAAG,EAAc,KAAA,CAAAE,CAAM,EAAIS,CAAAA,EAAkB,CAE1D,GAAIT,CAAAA,CACF,MAAMA,CAAAA,CAGR,GAAIF,GAAgB,CAACH,CAAAA,CACnB,MAAM,IAAI,KAAA,CAAM,mEAAmE,CAAA,CAGrF,OAAOA,CACT,CAoBO,SAASkB,CAAAA,EAA0E,CACxF,GAAM,CAAE,MAAA,CAAAlB,CAAO,CAAA,CAAIc,GAAkB,CAC/B,CAACK,EAAQC,CAAS,CAAA,CAAIlB,SAAoC,MAAS,CAAA,CAEzE,OAAAK,SAAAA,CAAU,IAAM,CACd,GAAI,CAACP,CAAAA,CACH,OAIF,IAAMqB,CAAAA,CAAgBrB,CAAAA,CAAO,UAAA,CAC7B,OAAIqB,GAAiB,MAAA,CAAO,IAAA,CAAKA,CAAa,CAAA,CAAE,MAAA,CAAS,GACvDD,CAAAA,CAAUC,CAA8B,CAAA,CAItBrB,CAAAA,CAAO,aAAcsB,CAAAA,EAAc,CACrDF,EAAUE,CAA0B,EACtC,CAAC,CAGH,CAAA,CAAG,CAACtB,CAAM,CAAC,CAAA,CAEJmB,CACT,CAeO,SAASI,CAAAA,EAAoD,CAClE,GAAM,CAAE,MAAA,CAAAvB,CAAO,EAAIc,CAAAA,EAAe,CAC5B,CAACU,CAAAA,CAAOC,CAAQ,EAAIvB,QAAAA,CAA8CF,CAAAA,EAAQ,SAAS,CAAA,CAEzF,OAAAO,SAAAA,CAAU,IACHP,EAEeA,CAAAA,CAAO,WAAA,CAAa0B,GAAa,CACnDD,CAAAA,CAASC,CAAQ,EACnB,CAAC,CAAA,CAJY,MAAA,CAOZ,CAAC1B,CAAM,CAAC,EAEJwB,CACT,CAoBO,SAASG,CAAAA,EAA8B,CAC5C,GAAM,CAAE,OAAA3B,CAAO,CAAA,CAAIc,GAAe,CAC5B,CAACC,CAAAA,CAASa,CAAU,EAAI1B,QAAAA,CAC5BF,CAAAA,EAAQ,aAAe,CACrB,KAAA,CAAO,QACP,WAAA,CAAa,QAAA,CACb,qBAAA,CAAuB,CAAC,QAAQ,CAAA,CAChC,QAAA,CAAU,CAAE,KAAA,CAAO,EAAG,MAAA,CAAQ,CAAE,CAAA,CAChC,MAAA,CAAQ,QACR,QAAA,CAAU,KACZ,CACF,CAAA,CAEA,OAAAO,UAAU,IACHP,CAAAA,EAEL4B,CAAAA,CAAW5B,CAAAA,CAAO,WAAW,CAAA,CAETA,CAAAA,CAAO,oBAAqB6B,CAAAA,EAAe,CAC7DD,EAAWC,CAAU,EACvB,CAAC,CAAA,EANY,OASZ,CAAC7B,CAAM,CAAC,CAAA,CAEJe,CACT,CAyBO,SAASe,CAAAA,CAAkBC,CAAAA,CAAgE,CAChG,GAAM,CAAE,MAAA,CAAA/B,CAAO,CAAA,CAAIc,CAAAA,GAEb,CAACkB,CAAAA,CAAOC,CAAgB,CAAA,CAAI/B,SAAY,IACvCF,CAAAA,CACUA,EAAO,QAAA,EAAY,EACjB+B,EAFGA,CAGrB,CAAA,CAEKG,CAAAA,CAAWC,WAAAA,CACdC,GAAmC,CAClCH,CAAAA,CAAkBI,GAAS,CACzB,IAAMC,EAAO,OAAOF,CAAAA,EAAa,UAAA,CAAcA,CAAAA,CAA4BC,CAAI,CAAA,CAAID,CAAAA,CAGnF,OAAApC,CAAAA,EAAQ,QAAA,CAASsC,CAAI,CAAA,CAEdA,CACT,CAAC,EACH,EACA,CAACtC,CAAM,CACT,CAAA,CAEA,OAAO,CAACgC,CAAAA,CAAOE,CAAQ,CACzB,CAmBO,SAASK,CAAAA,EAA8B,CAC5C,IAAMxB,CAAAA,CAAUY,GAAe,CAE/BpB,SAAAA,CAAU,IAAM,CACd,IAAMiC,CAAAA,CAAYzB,CAAAA,CAAQ,QAAQ,SAAA,CAClC,GAAI,CAACyB,CAAAA,CAAW,OAEhB,IAAMC,CAAAA,CAAO,SAAS,eAAA,CACtB,IAAA,GAAW,CAACC,CAAAA,CAAKC,CAAK,IAAK,MAAA,CAAO,OAAA,CAAQH,CAAS,CAAA,CACjDC,EAAK,KAAA,CAAM,WAAA,CAAYC,EAAKC,CAAK,CAAA,CAInC,OAAO,IAAM,CACX,IAAA,IAAWD,CAAAA,IAAO,OAAO,IAAA,CAAKF,CAAS,EACrCC,CAAAA,CAAK,KAAA,CAAM,eAAeC,CAAG,EAEjC,CACF,CAAA,CAAG,CAAC3B,CAAAA,CAAQ,MAAA,EAAQ,SAAS,CAAC,EAChC,CAgBO,SAAS6B,CAAAA,CAAiBC,CAAAA,CAAa,OAAA,CAASC,EAAY,MAAA,CAAc,CAC/E,IAAM/B,CAAAA,CAAUY,CAAAA,GAEhBpB,SAAAA,CAAU,IAAM,CACd,GAAM,CAAE,KAAA,CAAAwC,CAAM,CAAA,CAAIhC,CAAAA,CACZiC,EAAO,QAAA,CAAS,IAAA,CAEtB,OAAAA,CAAAA,CAAK,UAAU,MAAA,CAAOH,CAAAA,CAAYC,CAAS,CAAA,CAC3CE,CAAAA,CAAK,UAAU,GAAA,CAAID,CAAAA,GAAU,MAAA,CAASD,CAAAA,CAAYD,CAAU,CAAA,CAErD,IAAM,CACXG,CAAAA,CAAK,SAAA,CAAU,OAAOH,CAAAA,CAAYC,CAAS,EAC7C,CACF,EAAG,CAAC/B,CAAAA,CAAQ,MAAO8B,CAAAA,CAAYC,CAAS,CAAC,EAC3C,CAsBO,SAASG,CAAAA,EAId,CACA,IAAMlC,CAAAA,CAAUY,GAAe,CACzB,CAAE,OAAA3B,CAAO,CAAA,CAAIc,CAAAA,EAAe,CAE5BoC,EAAcf,WAAAA,CAClB,MAAOgB,GAA0C,CAC/C,MAAMnD,GAAQ,kBAAA,CAAmBmD,CAAI,EACvC,CAAA,CACA,CAACnD,CAAM,CACT,EAEA,OAAO,CACL,KAAMe,CAAAA,CAAQ,WAAA,CACd,cAAA,CAAgBA,CAAAA,CAAQ,sBACxB,WAAA,CAAAmC,CACF,CACF,CAoBO,SAASE,GAKd,CAGA,OAFgBzB,CAAAA,EAAe,CAGrB,gBAAkB,CACxB,GAAA,CAAK,EACL,KAAA,CAAO,CAAA,CACP,OAAQ,CAAA,CACR,IAAA,CAAM,CACR,CAEJ,CAyBO,SAAS0B,CAAAA,CAAmBC,EAA0C,CAC3E,GAAM,CAAE,MAAA,CAAAtD,CAAO,CAAA,CAAIc,CAAAA,GAEnBP,SAAAA,CAAU,IACHP,EAEeA,CAAAA,CAAO,eAAA,CAAgBsD,CAAO,CAAA,CAFrC,MAAA,CAIZ,CAACtD,CAAAA,CAAQsD,CAAO,CAAC,EACtB,CAmBO,SAASC,CAAAA,CAAcD,EAA0C,CACtE,GAAM,CAAE,MAAA,CAAAtD,CAAO,CAAA,CAAIc,CAAAA,GAEnBP,SAAAA,CAAU,IACHP,EAEeA,CAAAA,CAAO,UAAA,CAAWsD,CAAO,CAAA,CAFhC,OAIZ,CAACtD,CAAAA,CAAQsD,CAAO,CAAC,EACtB,CAuBO,SAASE,CAAAA,CAAsBF,CAAAA,CAAyD,CAC7F,GAAM,CAAE,MAAA,CAAAtD,CAAO,CAAA,CAAIc,CAAAA,GAEnBP,SAAAA,CAAU,IACHP,CAAAA,CAEeA,CAAAA,CAAO,mBAAmBsD,CAAO,CAAA,CAFxC,OAIZ,CAACtD,CAAAA,CAAQsD,CAAO,CAAC,EACtB,CA4BO,SAASG,GAAoD,CAClE,GAAM,CAAE,MAAA,CAAAzD,CAAO,CAAA,CAAIc,CAAAA,EAAe,CAC5B,CAAC4C,EAAcC,CAAe,CAAA,CAAIzD,SACtCF,CAAAA,EAAQ,mBAAA,EACV,CAAA,CAEA,OAAAO,SAAAA,CAAU,IAAM,CACTP,CAAAA,EACL2D,CAAAA,CAAgB3D,EAAO,mBAAA,EAAqB,EAC9C,CAAA,CAAG,CAACA,CAAM,CAAC,EAEJ0D,CACT,CAwBO,SAASE,CAAAA,EAA0C,CACxD,GAAM,CAAE,MAAA,CAAA5D,CAAO,CAAA,CAAIc,GAAe,CAC5B,CAAC+C,EAASC,CAAU,CAAA,CAAI5D,SAAkCF,CAAAA,EAAQ,cAAA,EAAgB,CAAA,CAExF,OAAAO,SAAAA,CAAU,IAAM,CACTP,CAAAA,EACL8D,CAAAA,CAAW9D,EAAO,cAAA,EAAgB,EACpC,CAAA,CAAG,CAACA,CAAM,CAAC,EAEJ6D,CACT,CA2BO,SAASE,CAAAA,EAAmE,CACjF,GAAM,CAAE,OAAA/D,CAAO,CAAA,CAAIc,GAAe,CAC5BkD,CAAAA,CAAeC,OAA2B,IAAI,CAAA,CAEpD,OAAA1D,SAAAA,CAAU,IAAM,CACd,GAAI,CAACP,CAAAA,EAAU,OAAO,cAAA,CAAmB,GAAA,CAAa,OAEtD,IAAMkE,EAAUF,CAAAA,CAAa,OAAA,CAC7B,GAAI,CAACE,CAAAA,CAAS,OAEd,IAAMC,CAAAA,CAAW,IAAI,cAAA,CAAgBC,GAAY,CAC/C,IAAA,IAAWC,KAASD,CAAAA,CAAS,CAC3B,GAAM,CAAE,KAAA,CAAAE,CAAAA,CAAO,MAAA,CAAAC,CAAO,CAAA,CAAIF,CAAAA,CAAM,YAC3BrE,CAAAA,CAAO,eAAA,CAAgB,CAC1B,KAAA,CAAO,IAAA,CAAK,KAAA,CAAMsE,CAAK,EACvB,MAAA,CAAQ,IAAA,CAAK,MAAMC,CAAM,CAC3B,CAAC,EACH,CACF,CAAC,CAAA,CAEDJ,EAAS,OAAA,CAAQD,CAAO,EAGxB,IAAMM,CAAAA,CAAON,EAAQ,qBAAA,EAAsB,CAC3C,OAAKlE,CAAAA,CAAO,gBAAgB,CAC1B,KAAA,CAAO,KAAK,KAAA,CAAMwE,CAAAA,CAAK,KAAK,CAAA,CAC5B,MAAA,CAAQ,IAAA,CAAK,KAAA,CAAMA,EAAK,MAAM,CAChC,CAAC,CAAA,CAEM,IAAML,EAAS,UAAA,EACxB,CAAA,CAAG,CAACnE,CAAM,CAAC,CAAA,CAEJgE,CACT,CAkEO,SAASS,CAAAA,EAEd,CACA,GAAM,CAAE,OAAAzE,CAAO,CAAA,CAAIc,GAAe,CAC5B,CAACkB,EAAOE,CAAQ,CAAA,CAAIhC,QAAAA,CAA6B,CACrD,YAAa,KAAA,CACb,WAAA,CAAa,MACb,KAAA,CAAO,IAAA,CACP,OAAQ,IACV,CAAC,CAAA,CAGDK,SAAAA,CAAU,IAAM,CACd2B,CAAAA,CAAUG,IAAU,CAClB,GAAGA,EACH,WAAA,CAAa,CAAC,CAACrC,CAAAA,EAAQ,UACzB,CAAA,CAAE,EACJ,EAAG,CAACA,CAAM,CAAC,CAAA,CAEX,IAAM0E,CAAAA,CAASvC,WAAAA,CACb,MAAOwC,CAAAA,EAAiD,CACtD,GAAI,CAAC3E,CAAAA,EAAQ,WACX,OAAAkC,CAAAA,CAAUG,CAAAA,GAAU,CAClB,GAAGA,CAAAA,CACH,KAAA,CAAO,IAAI,KAAA,CAAM,4CAA4C,CAC/D,CAAA,CAAE,CAAA,CACK,IAAA,CAGTH,CAAAA,CAAUG,IAAU,CAAE,GAAGA,EAAM,WAAA,CAAa,IAAA,CAAM,MAAO,IAAK,CAAA,CAAE,CAAA,CAEhE,GAAI,CACF,IAAMlB,CAAAA,CAAS,MAAMnB,CAAAA,CAAO,UAAA,CAAW2E,CAAI,CAAA,CAC3C,OAAAzC,CAAAA,CAAUG,CAAAA,GAAU,CAClB,GAAGA,CAAAA,CACH,YAAa,CAAA,CAAA,CACb,MAAA,CAAQlB,EAAO,MACjB,CAAA,CAAE,CAAA,CACKA,CACT,OAAST,CAAAA,CAAK,CACZ,IAAML,CAAAA,CAAQK,CAAAA,YAAe,MAAQA,CAAAA,CAAM,IAAI,KAAA,CAAM,MAAA,CAAOA,CAAG,CAAC,CAAA,CAChE,OAAAwB,CAAAA,CAAUG,CAAAA,GAAU,CAClB,GAAGA,CAAAA,CACH,WAAA,CAAa,KAAA,CACb,MAAAhC,CACF,CAAA,CAAE,EACK,IACT,CACF,EACA,CAACL,CAAM,CACT,CAAA,CAEA,OAAO,CAAE,GAAGgC,EAAO,MAAA,CAAA0C,CAAO,CAC5B,CA8BO,SAASE,CAAAA,EAMd,CACA,GAAM,CAAE,MAAA,CAAA5E,CAAO,CAAA,CAAIc,CAAAA,GACb,CAACkB,CAAAA,CAAOE,CAAQ,CAAA,CAAIhC,SAKvB,CACD,WAAA,CAAa,MACb,SAAA,CAAW,KAAA,CACX,MAAO,IAAA,CACP,WAAA,CAAa,IACf,CAAC,EAGDK,SAAAA,CAAU,IAAM,CACd2B,CAAAA,CAAUG,IAAU,CAClB,GAAGA,CAAAA,CACH,WAAA,CAAa,CAAC,CAACrC,CAAAA,EAAQ,kBACzB,CAAA,CAAE,EACJ,EAAG,CAACA,CAAM,CAAC,CAAA,CAEX,IAAM6E,CAAAA,CAAiB1C,WAAAA,CACrB,MAAO2C,CAAAA,EAA2C,CAChD,GAAI,CAAC9E,CAAAA,EAAQ,kBAAA,CACX,OAAAkC,EAAUG,CAAAA,GAAU,CAClB,GAAGA,CAAAA,CACH,KAAA,CAAO,IAAI,KAAA,CAAM,8CAA8C,CACjE,CAAA,CAAE,EACK,IAAA,CAGTH,CAAAA,CAAUG,IAAU,CAAE,GAAGA,EAAM,SAAA,CAAW,IAAA,CAAM,KAAA,CAAO,IAAK,EAAE,CAAA,CAE9D,GAAI,CACF,IAAMlB,CAAAA,CAAS,MAAMnB,CAAAA,CAAO,kBAAA,CAAmB8E,CAAM,CAAA,CACrD,OAAA5C,CAAAA,CAAUG,CAAAA,GAAU,CAClB,GAAGA,CAAAA,CACH,UAAW,CAAA,CAAA,CACX,WAAA,CAAalB,CAAAA,CAAO,WACtB,EAAE,CAAA,CACKA,CAAAA,CAAO,WAChB,CAAA,MAAST,CAAAA,CAAK,CACZ,IAAML,CAAAA,CAAQK,CAAAA,YAAe,KAAA,CAAQA,EAAM,IAAI,KAAA,CAAM,MAAA,CAAOA,CAAG,CAAC,CAAA,CAChE,OAAAwB,CAAAA,CAAUG,CAAAA,GAAU,CAClB,GAAGA,CAAAA,CACH,UAAW,KAAA,CACX,KAAA,CAAAhC,CACF,CAAA,CAAE,CAAA,CACK,IACT,CACF,EACA,CAACL,CAAM,CACT,CAAA,CAEA,OAAO,CAAE,GAAGgC,CAAAA,CAAO,cAAA,CAAA6C,CAAe,CACpC,CAyCO,SAASE,GAOd,CACA,GAAM,CAAE,MAAA,CAAA/E,CAAO,CAAA,CAAIc,CAAAA,GACbkD,CAAAA,CAAeC,MAAAA,CAA2B,IAAI,CAAA,CAC9C,CAACe,EAAaC,CAAc,CAAA,CAAI/E,QAAAA,CAAS,KAAK,EAGpDK,SAAAA,CAAU,IAAM,CACd0E,CAAAA,CAAe,CAAC,CAACjF,CAAAA,EAAQ,qBAAqB,EAChD,CAAA,CAAG,CAACA,CAAM,CAAC,EAGX,IAAMkF,CAAAA,CAAS/C,YACZoC,CAAAA,EAAmB,CAClBvE,CAAAA,EAAQ,qBAAA,GAAwBuE,CAAM,EACxC,CAAA,CACA,CAACvE,CAAM,CACT,EAGA,OAAAO,SAAAA,CAAU,IAAM,CACd,GAAI,CAACP,CAAAA,EAAQ,qBAAA,EAAyB,CAACgE,EAAa,OAAA,CAAS,OAE7D,IAAME,CAAAA,CAAUF,EAAa,OAAA,CACvBG,CAAAA,CAAW,IAAI,cAAA,CAAgBC,CAAAA,EAAY,CAC/C,IAAA,IAAWC,CAAAA,IAASD,CAAAA,CAAS,CAC3B,IAAMG,CAAAA,CAASF,CAAAA,CAAM,YAAY,MAAA,CACjCrE,CAAAA,CAAO,wBAAwBuE,CAAM,EACvC,CACF,CAAC,EAED,OAAAJ,CAAAA,CAAS,QAAQD,CAAO,CAAA,CAGxBlE,EAAO,qBAAA,CAAsBkE,CAAAA,CAAQ,YAAY,CAAA,CAE1C,IAAMC,CAAAA,CAAS,UAAA,EACxB,CAAA,CAAG,CAACnE,CAAM,CAAC,CAAA,CAEJ,CAAE,WAAA,CAAAgF,EAAa,YAAA,CAAAhB,CAAAA,CAAc,OAAAkB,CAAO,CAC7C,CAyBO,SAASC,CAAAA,EAA8B,CAE5C,OADgBxD,GAAe,CAChB,IACjB,CAwEO,SAASyD,CAAAA,EAOd,CACA,GAAM,CAAE,MAAA,CAAApF,CAAO,EAAIc,CAAAA,EAAe,CAC5B,CAACkE,CAAAA,CAAaC,CAAc,EAAI/E,QAAAA,CAAS,KAAK,CAAA,CAC9C,CAACmF,EAAQC,CAAS,CAAA,CAAIpF,SAAS,KAAK,CAAA,CAG1CK,UAAU,IAAM,CACd0E,CAAAA,CAAe,CAAC,CAACjF,CAAAA,EAAQ,YAAY,EACvC,CAAA,CAAG,CAACA,CAAM,CAAC,CAAA,CAEX,IAAMuF,CAAAA,CAAYpD,YAChB,MAAOqD,CAAAA,EAAuD,CAC5D,GAAI,CAACxF,GAAQ,YAAA,CACX,OAAO,IAAA,CAGTsF,CAAAA,CAAU,IAAI,CAAA,CACd,GAAI,CAEF,OADe,MAAMtF,EAAO,YAAA,CAAawF,CAAO,CAElD,CAAA,OAAE,CACAF,CAAAA,CAAU,KAAK,EACjB,CACF,CAAA,CACA,CAACtF,CAAM,CACT,CAAA,CAEA,OAAO,CAAE,WAAA,CAAAgF,CAAAA,CAAa,OAAAK,CAAAA,CAAQ,SAAA,CAAAE,CAAU,CAC1C,CA4BO,SAASE,CAAAA,CAAeC,EAAwD,CAErF,OAAA5E,GAAe,CAGfP,SAAAA,CAAU,IAAM,CACVmF,CAAAA,EACFC,iBAAAA,CAAkB,SAAA,CAAUD,CAAM,EAEtC,CAAA,CAAG,CAACA,CAAM,CAAC,EAEJC,iBACT","file":"index.js","sourcesContent":["/**\n * React context and provider for @mcp-apps-kit/ui-react\n */\n\nimport React, {\n createContext,\n useContext,\n useState,\n useEffect,\n type ReactNode,\n type ComponentType,\n} from \"react\";\nimport type { AppsClient, ToolDefs } from \"@mcp-apps-kit/ui\";\nimport { createClient } from \"@mcp-apps-kit/ui\";\n\n// =============================================================================\n// CONTEXT\n// =============================================================================\n\n// Internal context value - uses `unknown` for the client to allow any typed client\n// The actual type parameter is applied when consuming via hooks\ninterface AppsContextValueInternal {\n client: AppsClient | null;\n isConnecting: boolean;\n error: Error | null;\n}\n\n// Public interface with generic type parameter for typed access\ninterface AppsContextValue<T extends ToolDefs = ToolDefs> {\n client: AppsClient<T> | null;\n isConnecting: boolean;\n error: Error | null;\n}\n\nconst AppsContext = createContext<AppsContextValueInternal | null>(null);\n\n// =============================================================================\n// PROVIDER PROPS\n// =============================================================================\n\n/**\n * Props for AppsProvider\n */\nexport interface AppsProviderProps<T extends ToolDefs = ToolDefs> {\n /** Child components */\n children: ReactNode;\n\n /**\n * Pre-created client instance (optional)\n * If not provided, creates client automatically\n */\n client?: AppsClient<T>;\n\n /**\n * Force a specific protocol adapter\n */\n forceAdapter?: \"mcp\" | \"openai\" | \"mock\";\n\n /**\n * Fallback UI while client is connecting\n */\n fallback?: ReactNode;\n\n /**\n * Error boundary fallback\n */\n errorFallback?: ComponentType<{ error: Error; reset: () => void }>;\n}\n\n// =============================================================================\n// PROVIDER\n// =============================================================================\n\n/**\n * Context provider for mcp-apps-kit React integration\n *\n * Wraps your app and provides the client instance to all hooks.\n *\n * @example\n * ```tsx\n * function App() {\n * return (\n * <AppsProvider fallback={<Loading />}>\n * <MyWidget />\n * </AppsProvider>\n * );\n * }\n * ```\n */\nexport function AppsProvider<T extends ToolDefs = ToolDefs>({\n children,\n client: providedClient,\n forceAdapter: _forceAdapter,\n fallback,\n errorFallback: ErrorFallback,\n}: AppsProviderProps<T>): React.JSX.Element {\n const [client, setClient] = useState<AppsClient<T> | null>(providedClient ?? null);\n const [isConnecting, setIsConnecting] = useState(!providedClient);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n if (providedClient) {\n setClient(providedClient);\n setIsConnecting(false);\n return;\n }\n\n // Initialize client with auto-detection or forced adapter\n const initClient = async () => {\n try {\n const newClient = await createClient<T>({\n forceAdapter: _forceAdapter,\n });\n setClient(newClient);\n setIsConnecting(false);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setIsConnecting(false);\n }\n };\n\n void initClient();\n }, [providedClient, _forceAdapter]);\n\n if (error && ErrorFallback) {\n return <ErrorFallback error={error} reset={() => setError(null)} />;\n }\n\n // Don't render children until client is connected\n // This prevents hooks from throwing during initial connection\n if (isConnecting) {\n return <>{fallback ?? null}</>;\n }\n\n // Cast to internal type - the generic T is preserved at runtime,\n // and consumers use hooks with their own type parameter to get proper typing\n const contextValue: AppsContextValueInternal = {\n client: client as AppsClient | null,\n isConnecting,\n error,\n };\n\n return <AppsContext.Provider value={contextValue}>{children}</AppsContext.Provider>;\n}\n\n// =============================================================================\n// INTERNAL HOOK\n// =============================================================================\n\n/**\n * Internal hook to access the context\n * @internal\n */\nexport function useAppsContext<T extends ToolDefs = ToolDefs>(): AppsContextValue<T> {\n const context = useContext(AppsContext);\n if (!context) {\n throw new Error(\"useAppsContext must be used within an AppsProvider\");\n }\n return context as AppsContextValue<T>;\n}\n","/**\n * React hooks for @mcp-apps-kit/ui-react\n */\n\nimport React, { useState, useEffect, useCallback, useRef } from \"react\";\nimport type {\n AppsClient,\n HostContext,\n ToolDefs,\n ToolResult,\n ClientDebugConfig,\n ModalOptions,\n ModalResult,\n HostCapabilities,\n HostVersion,\n} from \"@mcp-apps-kit/ui\";\nimport { clientDebugLogger, type ClientDebugLogger } from \"@mcp-apps-kit/ui\";\nimport { useAppsContext } from \"./context\";\n\n// =============================================================================\n// CORE HOOKS\n// =============================================================================\n\n/**\n * Access the typed client instance\n *\n * @returns Client instance\n * @throws Error if used outside AppsProvider\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const client = useAppsClient<typeof app.tools>();\n *\n * const handleClick = async () => {\n * await client.callTool(\"myTool\", { arg: \"value\" });\n * };\n *\n * return <button onClick={handleClick}>Call Tool</button>;\n * }\n * ```\n */\nexport function useAppsClient<T extends ToolDefs = ToolDefs>(): AppsClient<T> {\n const { client, isConnecting, error } = useAppsContext<T>();\n\n if (error) {\n throw error;\n }\n\n if (isConnecting || !client) {\n throw new Error(\"Client not ready. Make sure AppsProvider has finished connecting.\");\n }\n\n return client;\n}\n\n/**\n * Access current tool result with automatic re-renders\n *\n * @returns Current tool result or undefined\n *\n * @example\n * ```tsx\n * function ResultDisplay() {\n * const result = useToolResult<typeof app.tools>();\n *\n * if (!result?.myTool) {\n * return <div>No results yet</div>;\n * }\n *\n * return <div>{result.myTool.message}</div>;\n * }\n * ```\n */\nexport function useToolResult<T extends ToolDefs = ToolDefs>(): ToolResult<T> | undefined {\n const { client } = useAppsContext<T>();\n const [result, setResult] = useState<ToolResult<T> | undefined>(undefined);\n\n useEffect(() => {\n if (!client) {\n return;\n }\n\n // Get initial tool output if available (wrapped with tool name)\n const initialOutput = client.toolOutput;\n if (initialOutput && Object.keys(initialOutput).length > 0) {\n setResult(initialOutput as ToolResult<T>);\n }\n\n // Subscribe to future tool result updates\n const unsubscribe = client.onToolResult((newResult) => {\n setResult(newResult as ToolResult<T>);\n });\n\n return unsubscribe;\n }, [client]);\n\n return result;\n}\n\n/**\n * Access current tool input\n *\n * @returns Current tool input or undefined\n *\n * @example\n * ```tsx\n * function InputDisplay() {\n * const input = useToolInput();\n * return <pre>{JSON.stringify(input, null, 2)}</pre>;\n * }\n * ```\n */\nexport function useToolInput(): Record<string, unknown> | undefined {\n const { client } = useAppsContext();\n const [input, setInput] = useState<Record<string, unknown> | undefined>(client?.toolInput);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.onToolInput((newInput) => {\n setInput(newInput);\n });\n\n return unsubscribe;\n }, [client]);\n\n return input;\n}\n\n/**\n * Access host context with automatic re-renders on changes\n *\n * @returns Current host context\n *\n * @example\n * ```tsx\n * function ThemedComponent() {\n * const context = useHostContext();\n *\n * return (\n * <div className={context.theme}>\n * Display: {context.displayMode}\n * </div>\n * );\n * }\n * ```\n */\nexport function useHostContext(): HostContext {\n const { client } = useAppsContext();\n const [context, setContext] = useState<HostContext>(\n client?.hostContext ?? {\n theme: \"light\",\n displayMode: \"inline\",\n availableDisplayModes: [\"inline\"],\n viewport: { width: 0, height: 0 },\n locale: \"en-US\",\n platform: \"web\",\n }\n );\n\n useEffect(() => {\n if (!client) return;\n\n setContext(client.hostContext);\n\n const unsubscribe = client.onHostContextChange((newContext) => {\n setContext(newContext);\n });\n\n return unsubscribe;\n }, [client]);\n\n return context;\n}\n\n/**\n * Persisted widget state with automatic sync\n *\n * Works like useState but persists across widget reloads.\n * On ChatGPT: Session-scoped persistence\n * On MCP Apps: Silent no-op (returns default, setState is ignored)\n *\n * @param defaultValue - Initial state value\n * @returns [state, setState] tuple\n *\n * @example\n * ```tsx\n * function Counter() {\n * const [count, setCount] = useWidgetState(0);\n *\n * return (\n * <button onClick={() => setCount(c => c + 1)}>\n * Count: {count}\n * </button>\n * );\n * }\n * ```\n */\nexport function useWidgetState<S>(defaultValue: S): [S, (newState: S | ((prev: S) => S)) => void] {\n const { client } = useAppsContext();\n\n const [state, setStateInternal] = useState<S>(() => {\n if (!client) return defaultValue;\n const stored = client.getState<S>();\n return stored ?? defaultValue;\n });\n\n const setState = useCallback(\n (newState: S | ((prev: S) => S)) => {\n setStateInternal((prev) => {\n const next = typeof newState === \"function\" ? (newState as (prev: S) => S)(prev) : newState;\n\n // Persist to client (silent no-op on MCP Apps)\n client?.setState(next);\n\n return next;\n });\n },\n [client]\n );\n\n return [state, setState];\n}\n\n// =============================================================================\n// UTILITY HOOKS\n// =============================================================================\n\n/**\n * Apply host CSS variables to document root\n *\n * Call this once in your root component to apply host theming.\n *\n * @example\n * ```tsx\n * function App() {\n * useHostStyleVariables();\n * return <MyWidget />;\n * }\n * ```\n */\nexport function useHostStyleVariables(): void {\n const context = useHostContext();\n\n useEffect(() => {\n const variables = context.styles?.variables;\n if (!variables) return;\n\n const root = document.documentElement;\n for (const [key, value] of Object.entries(variables)) {\n root.style.setProperty(key, value);\n }\n\n // Cleanup\n return () => {\n for (const key of Object.keys(variables)) {\n root.style.removeProperty(key);\n }\n };\n }, [context.styles?.variables]);\n}\n\n/**\n * Apply theme class to document body\n *\n * @param lightClass - Class name for light theme (default: \"light\")\n * @param darkClass - Class name for dark theme (default: \"dark\")\n *\n * @example\n * ```tsx\n * function App() {\n * useDocumentTheme(\"theme-light\", \"theme-dark\");\n * return <MyWidget />;\n * }\n * ```\n */\nexport function useDocumentTheme(lightClass = \"light\", darkClass = \"dark\"): void {\n const context = useHostContext();\n\n useEffect(() => {\n const { theme } = context;\n const body = document.body;\n\n body.classList.remove(lightClass, darkClass);\n body.classList.add(theme === \"dark\" ? darkClass : lightClass);\n\n return () => {\n body.classList.remove(lightClass, darkClass);\n };\n }, [context.theme, lightClass, darkClass]);\n}\n\n/**\n * Access and manage display mode\n *\n * @returns Display mode state and controls\n *\n * @example\n * ```tsx\n * function DisplayModeToggle() {\n * const { mode, availableModes, requestMode } = useDisplayMode();\n *\n * return (\n * <select value={mode} onChange={e => requestMode(e.target.value)}>\n * {availableModes.map(m => (\n * <option key={m} value={m}>{m}</option>\n * ))}\n * </select>\n * );\n * }\n * ```\n */\nexport function useDisplayMode(): {\n mode: string;\n availableModes: string[];\n requestMode: (mode: \"inline\" | \"fullscreen\" | \"pip\") => Promise<void>;\n} {\n const context = useHostContext();\n const { client } = useAppsContext();\n\n const requestMode = useCallback(\n async (mode: \"inline\" | \"fullscreen\" | \"pip\") => {\n await client?.requestDisplayMode(mode);\n },\n [client]\n );\n\n return {\n mode: context.displayMode,\n availableModes: context.availableDisplayModes,\n requestMode,\n };\n}\n\n/**\n * Access safe area insets for mobile layouts\n *\n * @returns Safe area insets or default zeros\n *\n * @example\n * ```tsx\n * function SafeContent() {\n * const insets = useSafeAreaInsets();\n *\n * return (\n * <div style={{ paddingTop: insets.top, paddingBottom: insets.bottom }}>\n * Content\n * </div>\n * );\n * }\n * ```\n */\nexport function useSafeAreaInsets(): {\n top: number;\n right: number;\n bottom: number;\n left: number;\n} {\n const context = useHostContext();\n\n return (\n context.safeAreaInsets ?? {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n }\n );\n}\n\n// =============================================================================\n// EVENT HOOKS\n// =============================================================================\n\n/**\n * Subscribe to tool cancellation\n *\n * @param handler - Callback when tool is cancelled\n *\n * @example\n * ```tsx\n * function CancellableOperation() {\n * const [cancelled, setCancelled] = useState(false);\n *\n * useOnToolCancelled((reason) => {\n * setCancelled(true);\n * console.log(\"Cancelled:\", reason);\n * });\n *\n * return cancelled ? <div>Cancelled</div> : <div>Running...</div>;\n * }\n * ```\n */\nexport function useOnToolCancelled(handler: (reason?: string) => void): void {\n const { client } = useAppsContext();\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.onToolCancelled(handler);\n return unsubscribe;\n }, [client, handler]);\n}\n\n/**\n * Subscribe to teardown events\n *\n * @param handler - Callback when widget is torn down\n *\n * @example\n * ```tsx\n * function CleanupComponent() {\n * useOnTeardown((reason) => {\n * console.log(\"Tearing down:\", reason);\n * // Cleanup resources\n * });\n *\n * return <div>Widget</div>;\n * }\n * ```\n */\nexport function useOnTeardown(handler: (reason?: string) => void): void {\n const { client } = useAppsContext();\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.onTeardown(handler);\n return unsubscribe;\n }, [client, handler]);\n}\n\n/**\n * Subscribe to partial/streaming tool input\n *\n * Called when the host sends partial tool arguments during streaming.\n * Useful for showing real-time input as the user types or as the model generates.\n *\n * @param handler - Callback for partial input\n *\n * @example\n * ```tsx\n * function StreamingInput() {\n * const [partialInput, setPartialInput] = useState<Record<string, unknown>>({});\n *\n * useOnToolInputPartial((input) => {\n * setPartialInput(input);\n * });\n *\n * return <pre>{JSON.stringify(partialInput, null, 2)}</pre>;\n * }\n * ```\n */\nexport function useOnToolInputPartial(handler: (input: Record<string, unknown>) => void): void {\n const { client } = useAppsContext();\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.onToolInputPartial(handler);\n return unsubscribe;\n }, [client, handler]);\n}\n\n// =============================================================================\n// HOST INFORMATION HOOKS\n// =============================================================================\n\n/**\n * Access host capabilities\n *\n * Returns the capabilities advertised by the host during handshake.\n * Use this to check if features like logging or server tools are supported.\n *\n * @returns Host capabilities or undefined if not yet connected\n *\n * @example\n * ```tsx\n * function CapabilitiesDisplay() {\n * const capabilities = useHostCapabilities();\n *\n * return (\n * <div>\n * <p>Logging: {capabilities?.logging ? \"Supported\" : \"Not supported\"}</p>\n * <p>Open Links: {capabilities?.openLinks ? \"Supported\" : \"Not supported\"}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useHostCapabilities(): HostCapabilities | undefined {\n const { client } = useAppsContext();\n const [capabilities, setCapabilities] = useState<HostCapabilities | undefined>(\n client?.getHostCapabilities()\n );\n\n useEffect(() => {\n if (!client) return;\n setCapabilities(client.getHostCapabilities());\n }, [client]);\n\n return capabilities;\n}\n\n/**\n * Access host version information\n *\n * Returns the name and version of the host application.\n *\n * @returns Host version info or undefined if not yet connected\n *\n * @example\n * ```tsx\n * function HostInfo() {\n * const hostVersion = useHostVersion();\n *\n * if (!hostVersion) return <div>Loading...</div>;\n *\n * return (\n * <div>\n * Running on {hostVersion.name} v{hostVersion.version}\n * </div>\n * );\n * }\n * ```\n */\nexport function useHostVersion(): HostVersion | undefined {\n const { client } = useAppsContext();\n const [version, setVersion] = useState<HostVersion | undefined>(client?.getHostVersion());\n\n useEffect(() => {\n if (!client) return;\n setVersion(client.getHostVersion());\n }, [client]);\n\n return version;\n}\n\n// =============================================================================\n// SIZE NOTIFICATION HOOKS\n// =============================================================================\n\n/**\n * Hook to set up automatic size change notifications\n *\n * Creates a ResizeObserver that automatically sends size changed\n * notifications to the host when the observed element resizes.\n *\n * @returns Ref to attach to the element to observe\n *\n * @example\n * ```tsx\n * function AutoSizeWidget() {\n * const containerRef = useSizeChangedNotifications();\n *\n * return (\n * <div ref={containerRef}>\n * <p>Content that may change size...</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useSizeChangedNotifications(): React.RefObject<HTMLElement | null> {\n const { client } = useAppsContext();\n const containerRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n if (!client || typeof ResizeObserver === \"undefined\") return;\n\n const element = containerRef.current;\n if (!element) return;\n\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect;\n void client.sendSizeChanged({\n width: Math.round(width),\n height: Math.round(height),\n });\n }\n });\n\n observer.observe(element);\n\n // Report initial size\n const rect = element.getBoundingClientRect();\n void client.sendSizeChanged({\n width: Math.round(rect.width),\n height: Math.round(rect.height),\n });\n\n return () => observer.disconnect();\n }, [client]);\n\n return containerRef;\n}\n\n// =============================================================================\n// FILE OPERATION HOOKS\n// =============================================================================\n\n/**\n * File upload result\n */\nexport interface FileUploadResult {\n /** Uploaded file ID */\n fileId: string;\n}\n\n/**\n * File upload state\n */\nexport interface UseFileUploadState {\n /** Whether file upload is supported on this platform */\n isSupported: boolean;\n /** Whether upload is in progress */\n isUploading: boolean;\n /** Upload error if any */\n error: Error | null;\n /** Last uploaded file ID */\n fileId: string | null;\n}\n\n/**\n * Hook for uploading files (ChatGPT only)\n *\n * Provides a function to upload files and tracks upload state.\n * On unsupported platforms, isSupported will be false.\n *\n * Supported file types: PNG, JPEG, WebP images\n *\n * @returns Upload function and state\n *\n * @example\n * ```tsx\n * function ImageUploader() {\n * const { upload, isSupported, isUploading, error, fileId } = useFileUpload();\n *\n * if (!isSupported) {\n * return <div>File upload not supported on this platform</div>;\n * }\n *\n * const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {\n * const file = e.target.files?.[0];\n * if (file) {\n * const result = await upload(file);\n * console.log(\"Uploaded:\", result?.fileId);\n * }\n * };\n *\n * return (\n * <div>\n * <input type=\"file\" accept=\"image/*\" onChange={handleFileChange} />\n * {isUploading && <span>Uploading...</span>}\n * {error && <span>Error: {error.message}</span>}\n * {fileId && <span>Uploaded: {fileId}</span>}\n * </div>\n * );\n * }\n * ```\n */\nexport function useFileUpload(): UseFileUploadState & {\n upload: (file: File) => Promise<FileUploadResult | null>;\n} {\n const { client } = useAppsContext();\n const [state, setState] = useState<UseFileUploadState>({\n isSupported: false,\n isUploading: false,\n error: null,\n fileId: null,\n });\n\n // Check if upload is supported\n useEffect(() => {\n setState((prev) => ({\n ...prev,\n isSupported: !!client?.uploadFile,\n }));\n }, [client]);\n\n const upload = useCallback(\n async (file: File): Promise<FileUploadResult | null> => {\n if (!client?.uploadFile) {\n setState((prev) => ({\n ...prev,\n error: new Error(\"File upload not supported on this platform\"),\n }));\n return null;\n }\n\n setState((prev) => ({ ...prev, isUploading: true, error: null }));\n\n try {\n const result = await client.uploadFile(file);\n setState((prev) => ({\n ...prev,\n isUploading: false,\n fileId: result.fileId,\n }));\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setState((prev) => ({\n ...prev,\n isUploading: false,\n error,\n }));\n return null;\n }\n },\n [client]\n );\n\n return { ...state, upload };\n}\n\n/**\n * Hook for getting file download URLs (ChatGPT only)\n *\n * Provides a function to get temporary download URLs for uploaded files.\n * On unsupported platforms, isSupported will be false.\n *\n * @returns Download URL function and state\n *\n * @example\n * ```tsx\n * function FileDownloader({ fileId }: { fileId: string }) {\n * const { getDownloadUrl, isSupported, isLoading, error, downloadUrl } = useFileDownload();\n *\n * useEffect(() => {\n * if (fileId && isSupported) {\n * getDownloadUrl(fileId);\n * }\n * }, [fileId, isSupported, getDownloadUrl]);\n *\n * if (!isSupported) return <div>Not supported</div>;\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (downloadUrl) return <img src={downloadUrl} alt=\"Uploaded file\" />;\n *\n * return null;\n * }\n * ```\n */\nexport function useFileDownload(): {\n isSupported: boolean;\n isLoading: boolean;\n error: Error | null;\n downloadUrl: string | null;\n getDownloadUrl: (fileId: string) => Promise<string | null>;\n} {\n const { client } = useAppsContext();\n const [state, setState] = useState<{\n isSupported: boolean;\n isLoading: boolean;\n error: Error | null;\n downloadUrl: string | null;\n }>({\n isSupported: false,\n isLoading: false,\n error: null,\n downloadUrl: null,\n });\n\n // Check if download URL is supported\n useEffect(() => {\n setState((prev) => ({\n ...prev,\n isSupported: !!client?.getFileDownloadUrl,\n }));\n }, [client]);\n\n const getDownloadUrl = useCallback(\n async (fileId: string): Promise<string | null> => {\n if (!client?.getFileDownloadUrl) {\n setState((prev) => ({\n ...prev,\n error: new Error(\"File download not supported on this platform\"),\n }));\n return null;\n }\n\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n\n try {\n const result = await client.getFileDownloadUrl(fileId);\n setState((prev) => ({\n ...prev,\n isLoading: false,\n downloadUrl: result.downloadUrl,\n }));\n return result.downloadUrl;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setState((prev) => ({\n ...prev,\n isLoading: false,\n error,\n }));\n return null;\n }\n },\n [client]\n );\n\n return { ...state, getDownloadUrl };\n}\n\n// =============================================================================\n// LAYOUT HOOKS\n// =============================================================================\n\n/**\n * Hook to notify host of widget's intrinsic height (ChatGPT only)\n *\n * Automatically reports height changes to prevent scroll clipping.\n * Returns a ref to attach to your root element for automatic height tracking,\n * or a manual notify function for custom height reporting.\n *\n * @returns Ref for auto-tracking and manual notify function\n *\n * @example\n * ```tsx\n * // Automatic height tracking\n * function AutoHeightWidget() {\n * const { containerRef, isSupported } = useIntrinsicHeight();\n *\n * return (\n * <div ref={containerRef}>\n * <p>Content that may change height...</p>\n * </div>\n * );\n * }\n *\n * // Manual height notification\n * function ManualHeightWidget() {\n * const { notify, isSupported } = useIntrinsicHeight();\n *\n * useEffect(() => {\n * // Notify after content loads\n * notify(500);\n * }, [notify]);\n *\n * return <div style={{ height: 500 }}>Fixed height content</div>;\n * }\n * ```\n */\nexport function useIntrinsicHeight(): {\n /** Whether intrinsic height notification is supported */\n isSupported: boolean;\n /** Ref to attach to container for automatic height tracking */\n containerRef: React.RefObject<HTMLElement | null>;\n /** Manually notify host of height */\n notify: (height: number) => void;\n} {\n const { client } = useAppsContext();\n const containerRef = useRef<HTMLElement | null>(null);\n const [isSupported, setIsSupported] = useState(false);\n\n // Check if supported\n useEffect(() => {\n setIsSupported(!!client?.notifyIntrinsicHeight);\n }, [client]);\n\n // Manual notify function\n const notify = useCallback(\n (height: number) => {\n client?.notifyIntrinsicHeight?.(height);\n },\n [client]\n );\n\n // Auto-track height with ResizeObserver\n useEffect(() => {\n if (!client?.notifyIntrinsicHeight || !containerRef.current) return;\n\n const element = containerRef.current;\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const height = entry.contentRect.height;\n client.notifyIntrinsicHeight?.(height);\n }\n });\n\n observer.observe(element);\n\n // Report initial height\n client.notifyIntrinsicHeight(element.offsetHeight);\n\n return () => observer.disconnect();\n }, [client]);\n\n return { isSupported, containerRef, notify };\n}\n\n/**\n * Hook to access the current view identifier (ChatGPT only)\n *\n * Useful for multi-view widgets that need to know which view is active.\n *\n * @returns Current view identifier or undefined\n *\n * @example\n * ```tsx\n * function MultiViewWidget() {\n * const view = useView();\n *\n * switch (view) {\n * case \"settings\":\n * return <SettingsView />;\n * case \"details\":\n * return <DetailsView />;\n * default:\n * return <MainView />;\n * }\n * }\n * ```\n */\nexport function useView(): string | undefined {\n const context = useHostContext();\n return context.view;\n}\n\n// =============================================================================\n// MODAL HOOKS\n// =============================================================================\n\n/**\n * Hook for showing host-owned modal dialogs (ChatGPT only)\n *\n * Spawns native ChatGPT modals for confirmations, inputs, etc.\n * On unsupported platforms, isSupported will be false.\n *\n * @returns Modal function and state\n *\n * @example\n * ```tsx\n * function DeleteButton() {\n * const { showModal, isSupported, isOpen } = useModal();\n *\n * const handleDelete = async () => {\n * const result = await showModal({\n * title: \"Confirm Delete\",\n * body: \"Are you sure you want to delete this item?\",\n * buttons: [\n * { label: \"Cancel\", variant: \"secondary\", value: \"cancel\" },\n * { label: \"Delete\", variant: \"destructive\", value: \"delete\" },\n * ],\n * });\n *\n * if (result?.action === \"delete\") {\n * // Perform delete\n * }\n * };\n *\n * if (!isSupported) {\n * return <button onClick={() => window.confirm(\"Delete?\")}>Delete</button>;\n * }\n *\n * return (\n * <button onClick={handleDelete} disabled={isOpen}>\n * Delete\n * </button>\n * );\n * }\n *\n * // Input modal example\n * function RenameButton() {\n * const { showModal } = useModal();\n *\n * const handleRename = async () => {\n * const result = await showModal({\n * title: \"Rename Item\",\n * input: {\n * type: \"text\",\n * placeholder: \"Enter new name\",\n * defaultValue: \"Current Name\",\n * },\n * buttons: [\n * { label: \"Cancel\", variant: \"secondary\", value: \"cancel\" },\n * { label: \"Rename\", variant: \"primary\", value: \"rename\" },\n * ],\n * });\n *\n * if (result?.action === \"rename\" && result.inputValue) {\n * console.log(\"New name:\", result.inputValue);\n * }\n * };\n *\n * return <button onClick={handleRename}>Rename</button>;\n * }\n * ```\n */\nexport function useModal(): {\n /** Whether modal API is supported */\n isSupported: boolean;\n /** Whether a modal is currently open */\n isOpen: boolean;\n /** Show a modal dialog */\n showModal: (options: ModalOptions) => Promise<ModalResult | null>;\n} {\n const { client } = useAppsContext();\n const [isSupported, setIsSupported] = useState(false);\n const [isOpen, setIsOpen] = useState(false);\n\n // Check if supported\n useEffect(() => {\n setIsSupported(!!client?.requestModal);\n }, [client]);\n\n const showModal = useCallback(\n async (options: ModalOptions): Promise<ModalResult | null> => {\n if (!client?.requestModal) {\n return null;\n }\n\n setIsOpen(true);\n try {\n const result = await client.requestModal(options);\n return result;\n } finally {\n setIsOpen(false);\n }\n },\n [client]\n );\n\n return { isSupported, isOpen, showModal };\n}\n\n// =============================================================================\n// DEBUG LOGGING HOOKS\n// =============================================================================\n\n/**\n * Access the debug logger with automatic adapter injection\n *\n * The adapter is automatically configured when AppsProvider connects.\n * Use this hook to access the logger and optionally configure it.\n *\n * @param config - Optional configuration to apply\n * @returns The configured client debug logger\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const logger = useDebugLogger({ enabled: true, level: \"debug\" });\n *\n * const handleClick = () => {\n * logger.info(\"Button clicked\", { timestamp: Date.now() });\n * };\n *\n * return <button onClick={handleClick}>Click me</button>;\n * }\n * ```\n */\nexport function useDebugLogger(config?: Partial<ClientDebugConfig>): ClientDebugLogger {\n // Verify we're inside AppsProvider (adapter is set by createClient)\n useAppsContext();\n\n // Apply configuration when it changes\n useEffect(() => {\n if (config) {\n clientDebugLogger.configure(config);\n }\n }, [config]);\n\n return clientDebugLogger;\n}\n"]} | ||
| {"version":3,"sources":["../src/context.tsx","../src/hooks.ts"],"names":["AppsContext","createContext","AppsProvider","children","providedClient","_forceAdapter","autoResize","fallback","ErrorFallback","client","setClient","useState","isConnecting","setIsConnecting","error","setError","useEffect","newClient","createClient","err","jsx","Fragment","contextValue","useAppsContext","context","useContext","DEFAULT_HOST_CONTEXT","DEFAULT_INSETS","createSizeObserver","element","onResize","observer","entries","entry","width","height","rect","useAppsClient","useToolResult","result","setResult","initialOutput","newResult","useToolInput","input","setInput","newInput","useHostContext","setContext","useWidgetState","defaultValue","state","setStateInternal","setState","useCallback","newState","prev","next","useHostStyleVariables","variables","root","key","value","useDocumentTheme","lightClass","darkClass","theme","body","useDisplayMode","requestMode","mode","useSafeAreaInsets","useOnToolCancelled","handler","handlerRef","useRef","reason","useOnTeardown","useOnToolInputPartial","useHostCapabilities","capabilities","setCapabilities","useHostVersion","version","setVersion","useSizeChangedNotifications","containerRef","useFileUpload","isSupported","isUploading","setIsUploading","fileId","setFileId","upload","file","useFileDownload","isLoading","setIsLoading","downloadUrl","setDownloadUrl","getDownloadUrl","useIntrinsicHeight","notify","_width","useView","useModal","isOpen","setIsOpen","showModal","options","useDebugLogger","config","clientDebugLogger"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * React context and provider for @mcp-apps-kit/ui-react\n */\n\nimport type { ReactNode, ComponentType, JSX } from \"react\";\nimport { createContext, useContext, useState, useEffect } from \"react\";\nimport type { AppsClient, ToolDefs } from \"@mcp-apps-kit/ui\";\nimport { createClient } from \"@mcp-apps-kit/ui\";\n\n// =============================================================================\n// CONTEXT\n// =============================================================================\n\n// Internal context value - uses `unknown` for the client to allow any typed client\n// The actual type parameter is applied when consuming via hooks\ninterface AppsContextValueInternal {\n client: AppsClient | null;\n isConnecting: boolean;\n error: Error | null;\n}\n\nconst AppsContext = createContext<AppsContextValueInternal | null>(null);\n\n// =============================================================================\n// PROVIDER PROPS\n// =============================================================================\n\n/**\n * Props for AppsProvider\n */\nexport interface AppsProviderProps<T extends ToolDefs = ToolDefs> {\n /** Child components */\n children: ReactNode;\n\n /**\n * Pre-created client instance (optional)\n * If not provided, creates client automatically\n */\n client?: AppsClient<T>;\n\n /**\n * Force a specific protocol adapter\n */\n forceAdapter?: \"mcp\" | \"openai\" | \"mock\";\n\n /**\n * Enable automatic size change notifications (MCP adapter only)\n *\n * When enabled, the UI automatically reports its size changes to the host\n * using a ResizeObserver on document.body and document.documentElement.\n * The host can then resize the UI container accordingly.\n *\n * Note: This option is only applied during initial mount. Changing it\n * at runtime will have no effect.\n *\n * @default true\n */\n autoResize?: boolean;\n\n /**\n * Fallback UI while client is connecting\n */\n fallback?: ReactNode;\n\n /**\n * Error boundary fallback\n */\n errorFallback?: ComponentType<{ error: Error; reset: () => void }>;\n}\n\n// =============================================================================\n// PROVIDER\n// =============================================================================\n\n/**\n * Context provider for mcp-apps-kit React integration\n *\n * Wraps your app and provides the client instance to all hooks.\n *\n * @example\n * ```tsx\n * function App() {\n * return (\n * <AppsProvider fallback={<Loading />}>\n * <MyWidget />\n * </AppsProvider>\n * );\n * }\n * ```\n */\nexport function AppsProvider<T extends ToolDefs = ToolDefs>({\n children,\n client: providedClient,\n forceAdapter: _forceAdapter,\n autoResize,\n fallback,\n errorFallback: ErrorFallback,\n}: AppsProviderProps<T>): JSX.Element {\n const [client, setClient] = useState<AppsClient<T> | null>(providedClient ?? null);\n const [isConnecting, setIsConnecting] = useState(!providedClient);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n if (providedClient) {\n setClient(providedClient);\n setIsConnecting(false);\n return;\n }\n\n // Initialize client with auto-detection or forced adapter\n const initClient = async () => {\n try {\n const newClient = await createClient<T>({\n forceAdapter: _forceAdapter,\n autoResize,\n });\n setClient(newClient);\n setIsConnecting(false);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setIsConnecting(false);\n }\n };\n\n void initClient();\n // Note: autoResize is intentionally not in the dependency array.\n // It should only be set during initial mount. Changing it at runtime\n // would cause unnecessary client re-initialization.\n }, [providedClient, _forceAdapter]);\n\n if (error && ErrorFallback) {\n return <ErrorFallback error={error} reset={() => setError(null)} />;\n }\n\n // Don't render children until client is connected\n // This prevents hooks from throwing during initial connection\n if (isConnecting) {\n return <>{fallback ?? null}</>;\n }\n\n // Cast to internal type - the generic T is preserved at runtime,\n // and consumers use hooks with their own type parameter to get proper typing\n const contextValue: AppsContextValueInternal = {\n client: client as AppsClient | null,\n isConnecting,\n error,\n };\n\n return <AppsContext.Provider value={contextValue}>{children}</AppsContext.Provider>;\n}\n\n// =============================================================================\n// INTERNAL HOOK\n// =============================================================================\n\n/**\n * Context value exposed by useAppsContext\n */\nexport interface AppsContextValue<T extends ToolDefs = ToolDefs> {\n client: AppsClient<T> | null;\n isConnecting: boolean;\n error: Error | null;\n}\n\n/**\n * Internal hook to access the context\n * @internal\n */\nexport function useAppsContext<T extends ToolDefs = ToolDefs>(): AppsContextValue<T> {\n const context = useContext(AppsContext);\n if (!context) {\n throw new Error(\"useAppsContext must be used within an AppsProvider\");\n }\n return context as AppsContextValue<T>;\n}\n","/**\n * React hooks for @mcp-apps-kit/ui-react\n */\n\nimport type { RefObject } from \"react\";\nimport { useState, useEffect, useCallback, useRef } from \"react\";\nimport type {\n AppsClient,\n HostContext,\n ToolDefs,\n ToolResult,\n ClientDebugConfig,\n ModalOptions,\n ModalResult,\n HostCapabilities,\n HostVersion,\n} from \"@mcp-apps-kit/ui\";\nimport { clientDebugLogger, type ClientDebugLogger } from \"@mcp-apps-kit/ui\";\nimport { useAppsContext } from \"./context\";\n\n// =============================================================================\n// SHARED UTILITIES\n// =============================================================================\n\n/** Default host context for initial state */\nconst DEFAULT_HOST_CONTEXT: HostContext = {\n theme: \"light\",\n displayMode: \"inline\",\n availableDisplayModes: [\"inline\"],\n viewport: { width: 0, height: 0 },\n locale: \"en-US\",\n platform: \"web\",\n};\n\n/** Default safe area insets */\nconst DEFAULT_INSETS = { top: 0, right: 0, bottom: 0, left: 0 };\n\n/**\n * Helper to create a ResizeObserver that reports size changes\n */\nfunction createSizeObserver(\n element: HTMLElement,\n onResize: (width: number, height: number) => void\n): ResizeObserver {\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect;\n onResize(Math.round(width), Math.round(height));\n }\n });\n\n observer.observe(element);\n\n // Report initial size\n const rect = element.getBoundingClientRect();\n onResize(Math.round(rect.width), Math.round(rect.height));\n\n return observer;\n}\n\n// =============================================================================\n// CORE HOOKS\n// =============================================================================\n\n/**\n * Access the typed client instance\n *\n * @returns Client instance\n * @throws Error if used outside AppsProvider\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const client = useAppsClient<typeof app.tools>();\n *\n * const handleClick = async () => {\n * await client.callTool(\"myTool\", { arg: \"value\" });\n * };\n *\n * return <button onClick={handleClick}>Call Tool</button>;\n * }\n * ```\n */\nexport function useAppsClient<T extends ToolDefs = ToolDefs>(): AppsClient<T> {\n const { client, isConnecting, error } = useAppsContext<T>();\n\n if (error) {\n throw error;\n }\n\n if (isConnecting || !client) {\n throw new Error(\"Client not ready. Make sure AppsProvider has finished connecting.\");\n }\n\n return client;\n}\n\n/**\n * Access current tool result with automatic re-renders\n *\n * @returns Current tool result or undefined\n *\n * @example\n * ```tsx\n * function ResultDisplay() {\n * const result = useToolResult<typeof app.tools>();\n *\n * if (!result?.myTool) {\n * return <div>No results yet</div>;\n * }\n *\n * return <div>{result.myTool.message}</div>;\n * }\n * ```\n */\nexport function useToolResult<T extends ToolDefs = ToolDefs>(): ToolResult<T> | undefined {\n const { client } = useAppsContext<T>();\n const [result, setResult] = useState<ToolResult<T> | undefined>(undefined);\n\n useEffect(() => {\n if (!client) {\n return;\n }\n\n // Get initial tool output if available (wrapped with tool name)\n const initialOutput = client.toolOutput;\n if (initialOutput && Object.keys(initialOutput).length > 0) {\n setResult(initialOutput as ToolResult<T>);\n }\n\n // Subscribe to future tool result updates\n const unsubscribe = client.onToolResult((newResult) => {\n setResult(newResult as ToolResult<T>);\n });\n\n return unsubscribe;\n }, [client]);\n\n return result;\n}\n\n/**\n * Access current tool input\n *\n * @returns Current tool input or undefined\n *\n * @example\n * ```tsx\n * function InputDisplay() {\n * const input = useToolInput();\n * return <pre>{JSON.stringify(input, null, 2)}</pre>;\n * }\n * ```\n */\nexport function useToolInput(): Record<string, unknown> | undefined {\n const { client } = useAppsContext();\n const [input, setInput] = useState<Record<string, unknown> | undefined>(client?.toolInput);\n\n useEffect(() => {\n if (!client) return;\n\n const unsubscribe = client.onToolInput((newInput) => {\n setInput(newInput);\n });\n\n return unsubscribe;\n }, [client]);\n\n return input;\n}\n\n/**\n * Access host context with automatic re-renders on changes\n *\n * @returns Current host context\n *\n * @example\n * ```tsx\n * function ThemedComponent() {\n * const context = useHostContext();\n *\n * return (\n * <div className={context.theme}>\n * Display: {context.displayMode}\n * </div>\n * );\n * }\n * ```\n */\nexport function useHostContext(): HostContext {\n const { client } = useAppsContext();\n const [context, setContext] = useState<HostContext>(client?.hostContext ?? DEFAULT_HOST_CONTEXT);\n\n useEffect(() => {\n if (!client) return;\n\n setContext(client.hostContext);\n return client.onHostContextChange(setContext);\n }, [client]);\n\n return context;\n}\n\n/**\n * Persisted widget state with automatic sync\n *\n * Works like useState but persists across widget reloads.\n * On ChatGPT: Session-scoped persistence\n * On MCP Apps: Silent no-op (returns default, setState is ignored)\n *\n * @param defaultValue - Initial state value\n * @returns [state, setState] tuple\n *\n * @example\n * ```tsx\n * function Counter() {\n * const [count, setCount] = useWidgetState(0);\n *\n * return (\n * <button onClick={() => setCount(c => c + 1)}>\n * Count: {count}\n * </button>\n * );\n * }\n * ```\n */\nexport function useWidgetState<S>(defaultValue: S): [S, (newState: S | ((prev: S) => S)) => void] {\n const { client } = useAppsContext();\n\n const [state, setStateInternal] = useState<S>(() => {\n if (!client) return defaultValue;\n const stored = client.getState<S>();\n return stored ?? defaultValue;\n });\n\n const setState = useCallback(\n (newState: S | ((prev: S) => S)) => {\n setStateInternal((prev) => {\n const next = typeof newState === \"function\" ? (newState as (prev: S) => S)(prev) : newState;\n\n // Persist to client (silent no-op on MCP Apps)\n client?.setState(next);\n\n return next;\n });\n },\n [client]\n );\n\n return [state, setState];\n}\n\n// =============================================================================\n// UTILITY HOOKS\n// =============================================================================\n\n/**\n * Apply host CSS variables to document root\n *\n * Call this once in your root component to apply host theming.\n *\n * @example\n * ```tsx\n * function App() {\n * useHostStyleVariables();\n * return <MyWidget />;\n * }\n * ```\n */\nexport function useHostStyleVariables(): void {\n const context = useHostContext();\n\n useEffect(() => {\n const variables = context.styles?.variables;\n if (!variables) return;\n\n const root = document.documentElement;\n for (const [key, value] of Object.entries(variables)) {\n root.style.setProperty(key, value);\n }\n\n // Cleanup\n return () => {\n for (const key of Object.keys(variables)) {\n root.style.removeProperty(key);\n }\n };\n }, [context.styles?.variables]);\n}\n\n/**\n * Apply theme class to document body\n *\n * @param lightClass - Class name for light theme (default: \"light\")\n * @param darkClass - Class name for dark theme (default: \"dark\")\n *\n * @example\n * ```tsx\n * function App() {\n * useDocumentTheme(\"theme-light\", \"theme-dark\");\n * return <MyWidget />;\n * }\n * ```\n */\nexport function useDocumentTheme(lightClass = \"light\", darkClass = \"dark\"): void {\n const context = useHostContext();\n\n useEffect(() => {\n const { theme } = context;\n const body = document.body;\n\n body.classList.remove(lightClass, darkClass);\n body.classList.add(theme === \"dark\" ? darkClass : lightClass);\n\n return () => {\n body.classList.remove(lightClass, darkClass);\n };\n }, [context.theme, lightClass, darkClass]);\n}\n\n/**\n * Access and manage display mode\n *\n * @returns Display mode state and controls\n *\n * @example\n * ```tsx\n * function DisplayModeToggle() {\n * const { mode, availableModes, requestMode } = useDisplayMode();\n *\n * return (\n * <select value={mode} onChange={e => requestMode(e.target.value)}>\n * {availableModes.map(m => (\n * <option key={m} value={m}>{m}</option>\n * ))}\n * </select>\n * );\n * }\n * ```\n */\nexport function useDisplayMode(): {\n mode: string;\n availableModes: string[];\n requestMode: (mode: \"inline\" | \"fullscreen\" | \"pip\") => Promise<void>;\n} {\n const context = useHostContext();\n const { client } = useAppsContext();\n\n const requestMode = useCallback(\n async (mode: \"inline\" | \"fullscreen\" | \"pip\") => {\n await client?.requestDisplayMode(mode);\n },\n [client]\n );\n\n return {\n mode: context.displayMode,\n availableModes: context.availableDisplayModes,\n requestMode,\n };\n}\n\n/**\n * Access safe area insets for mobile layouts\n *\n * @returns Safe area insets or default zeros\n *\n * @example\n * ```tsx\n * function SafeContent() {\n * const insets = useSafeAreaInsets();\n *\n * return (\n * <div style={{ paddingTop: insets.top, paddingBottom: insets.bottom }}>\n * Content\n * </div>\n * );\n * }\n * ```\n */\nexport function useSafeAreaInsets(): { top: number; right: number; bottom: number; left: number } {\n const context = useHostContext();\n return context.safeAreaInsets ?? DEFAULT_INSETS;\n}\n\n// =============================================================================\n// EVENT HOOKS\n// =============================================================================\n\n/**\n * Subscribe to tool cancellation\n *\n * @param handler - Callback when tool is cancelled\n *\n * @example\n * ```tsx\n * function CancellableOperation() {\n * const [cancelled, setCancelled] = useState(false);\n *\n * useOnToolCancelled((reason) => {\n * setCancelled(true);\n * console.log(\"Cancelled:\", reason);\n * });\n *\n * return cancelled ? <div>Cancelled</div> : <div>Running...</div>;\n * }\n * ```\n */\nexport function useOnToolCancelled(handler: (reason?: string) => void): void {\n const { client } = useAppsContext();\n const handlerRef = useRef(handler);\n\n useEffect(() => {\n handlerRef.current = handler;\n }, [handler]);\n\n useEffect(() => {\n if (!client) return;\n return client.onToolCancelled((reason) => handlerRef.current(reason));\n }, [client]);\n}\n\n/**\n * Subscribe to teardown events\n *\n * @param handler - Callback when widget is torn down\n *\n * @example\n * ```tsx\n * function CleanupComponent() {\n * useOnTeardown((reason) => {\n * console.log(\"Tearing down:\", reason);\n * // Cleanup resources\n * });\n *\n * return <div>Widget</div>;\n * }\n * ```\n */\nexport function useOnTeardown(handler: (reason?: string) => void): void {\n const { client } = useAppsContext();\n const handlerRef = useRef(handler);\n\n useEffect(() => {\n handlerRef.current = handler;\n }, [handler]);\n\n useEffect(() => {\n if (!client) return;\n return client.onTeardown((reason) => handlerRef.current(reason));\n }, [client]);\n}\n\n/**\n * Subscribe to partial/streaming tool input\n *\n * Called when the host sends partial tool arguments during streaming.\n * Useful for showing real-time input as the user types or as the model generates.\n *\n * @param handler - Callback for partial input\n *\n * @example\n * ```tsx\n * function StreamingInput() {\n * const [partialInput, setPartialInput] = useState<Record<string, unknown>>({});\n *\n * useOnToolInputPartial((input) => {\n * setPartialInput(input);\n * });\n *\n * return <pre>{JSON.stringify(partialInput, null, 2)}</pre>;\n * }\n * ```\n */\nexport function useOnToolInputPartial(handler: (input: Record<string, unknown>) => void): void {\n const { client } = useAppsContext();\n const handlerRef = useRef(handler);\n\n useEffect(() => {\n handlerRef.current = handler;\n }, [handler]);\n\n useEffect(() => {\n if (!client) return;\n return client.onToolInputPartial((input) => handlerRef.current(input));\n }, [client]);\n}\n\n// =============================================================================\n// HOST INFORMATION HOOKS\n// =============================================================================\n\n/**\n * Access host capabilities\n *\n * Returns the capabilities advertised by the host during handshake.\n * Use this to check if features like logging or server tools are supported.\n *\n * @returns Host capabilities or undefined if not yet connected\n *\n * @example\n * ```tsx\n * function CapabilitiesDisplay() {\n * const capabilities = useHostCapabilities();\n *\n * return (\n * <div>\n * <p>Logging: {capabilities?.logging ? \"Supported\" : \"Not supported\"}</p>\n * <p>Open Links: {capabilities?.openLinks ? \"Supported\" : \"Not supported\"}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useHostCapabilities(): HostCapabilities | undefined {\n const { client } = useAppsContext();\n const [capabilities, setCapabilities] = useState<HostCapabilities | undefined>(\n client?.getHostCapabilities()\n );\n\n useEffect(() => {\n if (!client) {\n setCapabilities(undefined);\n return;\n }\n\n setCapabilities(client.getHostCapabilities());\n return client.onHostContextChange(() => setCapabilities(client.getHostCapabilities()));\n }, [client]);\n\n return capabilities;\n}\n\n/**\n * Access host version information\n *\n * Returns the name and version of the host application.\n *\n * @returns Host version info or undefined if not yet connected\n *\n * @example\n * ```tsx\n * function HostInfo() {\n * const hostVersion = useHostVersion();\n *\n * if (!hostVersion) return <div>Loading...</div>;\n *\n * return (\n * <div>\n * Running on {hostVersion.name} v{hostVersion.version}\n * </div>\n * );\n * }\n * ```\n */\nexport function useHostVersion(): HostVersion | undefined {\n const { client } = useAppsContext();\n const [version, setVersion] = useState<HostVersion | undefined>(() => client?.getHostVersion());\n\n useEffect(() => {\n if (!client) {\n setVersion(undefined);\n return;\n }\n\n // Update version when client changes\n setVersion(client.getHostVersion());\n }, [client]);\n\n return version;\n}\n\n// =============================================================================\n// SIZE NOTIFICATION HOOKS\n// =============================================================================\n\n/**\n * Hook to set up automatic size change notifications\n *\n * Creates a ResizeObserver that automatically sends size changed\n * notifications to the host when the observed element resizes.\n *\n * @returns Ref to attach to the element to observe\n *\n * @example\n * ```tsx\n * function AutoSizeWidget() {\n * const containerRef = useSizeChangedNotifications();\n *\n * return (\n * <div ref={containerRef}>\n * <p>Content that may change size...</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useSizeChangedNotifications(): RefObject<HTMLElement | null> {\n const { client } = useAppsContext();\n const containerRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n const element = containerRef.current;\n if (!client || !element || typeof ResizeObserver === \"undefined\") return;\n\n const observer = createSizeObserver(element, (width, height) => {\n void client.sendSizeChanged({ width, height });\n });\n\n return () => observer.disconnect();\n }, [client]);\n\n return containerRef;\n}\n\n// =============================================================================\n// FILE OPERATION HOOKS\n// =============================================================================\n\n/**\n * File upload result\n */\nexport interface FileUploadResult {\n /** Uploaded file ID */\n fileId: string;\n}\n\n/**\n * File upload state\n */\nexport interface UseFileUploadState {\n /** Whether file upload is supported on this platform */\n isSupported: boolean;\n /** Whether upload is in progress */\n isUploading: boolean;\n /** Upload error if any */\n error: Error | null;\n /** Last uploaded file ID */\n fileId: string | null;\n}\n\n/**\n * Hook for uploading files (ChatGPT only)\n *\n * Provides a function to upload files and tracks upload state.\n * On unsupported platforms, isSupported will be false.\n *\n * Supported file types: PNG, JPEG, WebP images\n *\n * @returns Upload function and state\n *\n * @example\n * ```tsx\n * function ImageUploader() {\n * const { upload, isSupported, isUploading, error, fileId } = useFileUpload();\n *\n * if (!isSupported) {\n * return <div>File upload not supported on this platform</div>;\n * }\n *\n * const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {\n * const file = e.target.files?.[0];\n * if (file) {\n * const result = await upload(file);\n * console.log(\"Uploaded:\", result?.fileId);\n * }\n * };\n *\n * return (\n * <div>\n * <input type=\"file\" accept=\"image/*\" onChange={handleFileChange} />\n * {isUploading && <span>Uploading...</span>}\n * {error && <span>Error: {error.message}</span>}\n * {fileId && <span>Uploaded: {fileId}</span>}\n * </div>\n * );\n * }\n * ```\n */\nexport function useFileUpload(): UseFileUploadState & {\n upload: (file: File) => Promise<FileUploadResult | null>;\n} {\n const { client } = useAppsContext();\n const isSupported = !!client?.uploadFile;\n const [isUploading, setIsUploading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [fileId, setFileId] = useState<string | null>(null);\n\n const upload = useCallback(\n async (file: File): Promise<FileUploadResult | null> => {\n if (!client?.uploadFile) {\n setError(new Error(\"File upload not supported on this platform\"));\n return null;\n }\n\n setIsUploading(true);\n setError(null);\n\n try {\n const result = await client.uploadFile(file);\n setFileId(result.fileId);\n return result;\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n return null;\n } finally {\n setIsUploading(false);\n }\n },\n [client]\n );\n\n return { isSupported, isUploading, error, fileId, upload };\n}\n\n/**\n * Hook for getting file download URLs (ChatGPT only)\n *\n * Provides a function to get temporary download URLs for uploaded files.\n * On unsupported platforms, isSupported will be false.\n *\n * @returns Download URL function and state\n *\n * @example\n * ```tsx\n * function FileDownloader({ fileId }: { fileId: string }) {\n * const { getDownloadUrl, isSupported, isLoading, error, downloadUrl } = useFileDownload();\n *\n * useEffect(() => {\n * if (fileId && isSupported) {\n * getDownloadUrl(fileId);\n * }\n * }, [fileId, isSupported, getDownloadUrl]);\n *\n * if (!isSupported) return <div>Not supported</div>;\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (downloadUrl) return <img src={downloadUrl} alt=\"Uploaded file\" />;\n *\n * return null;\n * }\n * ```\n */\nexport function useFileDownload(): {\n isSupported: boolean;\n isLoading: boolean;\n error: Error | null;\n downloadUrl: string | null;\n getDownloadUrl: (fileId: string) => Promise<string | null>;\n} {\n const { client } = useAppsContext();\n const isSupported = !!client?.getFileDownloadUrl;\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [downloadUrl, setDownloadUrl] = useState<string | null>(null);\n\n const getDownloadUrl = useCallback(\n async (fileId: string): Promise<string | null> => {\n if (!client?.getFileDownloadUrl) {\n setError(new Error(\"File download not supported on this platform\"));\n return null;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await client.getFileDownloadUrl(fileId);\n setDownloadUrl(result.downloadUrl);\n return result.downloadUrl;\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n return null;\n } finally {\n setIsLoading(false);\n }\n },\n [client]\n );\n\n return { isSupported, isLoading, error, downloadUrl, getDownloadUrl };\n}\n\n// =============================================================================\n// LAYOUT HOOKS\n// =============================================================================\n\n/**\n * Hook to notify host of widget's intrinsic height (ChatGPT only)\n *\n * Automatically reports height changes to prevent scroll clipping.\n * Returns a ref to attach to your root element for automatic height tracking,\n * or a manual notify function for custom height reporting.\n *\n * @returns Ref for auto-tracking and manual notify function\n *\n * @example\n * ```tsx\n * // Automatic height tracking\n * function AutoHeightWidget() {\n * const { containerRef, isSupported } = useIntrinsicHeight();\n *\n * return (\n * <div ref={containerRef}>\n * <p>Content that may change height...</p>\n * </div>\n * );\n * }\n *\n * // Manual height notification\n * function ManualHeightWidget() {\n * const { notify, isSupported } = useIntrinsicHeight();\n *\n * useEffect(() => {\n * // Notify after content loads\n * notify(500);\n * }, [notify]);\n *\n * return <div style={{ height: 500 }}>Fixed height content</div>;\n * }\n * ```\n */\nexport function useIntrinsicHeight(): {\n /** Whether intrinsic height notification is supported */\n isSupported: boolean;\n /** Ref to attach to container for automatic height tracking */\n containerRef: RefObject<HTMLElement | null>;\n /** Manually notify host of height */\n notify: (height: number) => void;\n} {\n const { client } = useAppsContext();\n const containerRef = useRef<HTMLElement | null>(null);\n const isSupported = !!client?.notifyIntrinsicHeight;\n\n const notify = useCallback(\n (height: number) => {\n client?.notifyIntrinsicHeight?.(height);\n },\n [client]\n );\n\n useEffect(() => {\n const element = containerRef.current;\n if (!client?.notifyIntrinsicHeight || !element || typeof ResizeObserver === \"undefined\") return;\n\n const observer = createSizeObserver(element, (_width, height) => {\n client.notifyIntrinsicHeight?.(height);\n });\n\n return () => observer.disconnect();\n }, [client]);\n\n return { isSupported, containerRef, notify };\n}\n\n/**\n * Hook to access the current view identifier (ChatGPT only)\n *\n * Useful for multi-view widgets that need to know which view is active.\n *\n * @returns Current view identifier or undefined\n *\n * @example\n * ```tsx\n * function MultiViewWidget() {\n * const view = useView();\n *\n * switch (view) {\n * case \"settings\":\n * return <SettingsView />;\n * case \"details\":\n * return <DetailsView />;\n * default:\n * return <MainView />;\n * }\n * }\n * ```\n */\nexport function useView(): string | undefined {\n const context = useHostContext();\n return context.view;\n}\n\n// =============================================================================\n// MODAL HOOKS\n// =============================================================================\n\n/**\n * Hook for showing host-owned modal dialogs (ChatGPT only)\n *\n * Spawns native ChatGPT modals for confirmations, inputs, etc.\n * On unsupported platforms, isSupported will be false.\n *\n * @returns Modal function and state\n *\n * @example\n * ```tsx\n * function DeleteButton() {\n * const { showModal, isSupported, isOpen } = useModal();\n *\n * const handleDelete = async () => {\n * const result = await showModal({\n * title: \"Confirm Delete\",\n * body: \"Are you sure you want to delete this item?\",\n * buttons: [\n * { label: \"Cancel\", variant: \"secondary\", value: \"cancel\" },\n * { label: \"Delete\", variant: \"destructive\", value: \"delete\" },\n * ],\n * });\n *\n * if (result?.action === \"delete\") {\n * // Perform delete\n * }\n * };\n *\n * if (!isSupported) {\n * return <button onClick={() => window.confirm(\"Delete?\")}>Delete</button>;\n * }\n *\n * return (\n * <button onClick={handleDelete} disabled={isOpen}>\n * Delete\n * </button>\n * );\n * }\n *\n * // Input modal example\n * function RenameButton() {\n * const { showModal } = useModal();\n *\n * const handleRename = async () => {\n * const result = await showModal({\n * title: \"Rename Item\",\n * input: {\n * type: \"text\",\n * placeholder: \"Enter new name\",\n * defaultValue: \"Current Name\",\n * },\n * buttons: [\n * { label: \"Cancel\", variant: \"secondary\", value: \"cancel\" },\n * { label: \"Rename\", variant: \"primary\", value: \"rename\" },\n * ],\n * });\n *\n * if (result?.action === \"rename\" && result.inputValue) {\n * console.log(\"New name:\", result.inputValue);\n * }\n * };\n *\n * return <button onClick={handleRename}>Rename</button>;\n * }\n * ```\n */\nexport function useModal(): {\n /** Whether modal API is supported */\n isSupported: boolean;\n /** Whether a modal is currently open */\n isOpen: boolean;\n /** Show a modal dialog */\n showModal: (options: ModalOptions) => Promise<ModalResult | null>;\n} {\n const { client } = useAppsContext();\n const isSupported = !!client?.requestModal;\n const [isOpen, setIsOpen] = useState(false);\n\n const showModal = useCallback(\n async (options: ModalOptions): Promise<ModalResult | null> => {\n if (!client?.requestModal) {\n return null;\n }\n\n setIsOpen(true);\n try {\n const result = await client.requestModal(options);\n return result;\n } finally {\n setIsOpen(false);\n }\n },\n [client]\n );\n\n return { isSupported, isOpen, showModal };\n}\n\n// =============================================================================\n// DEBUG LOGGING HOOKS\n// =============================================================================\n\n/**\n * Access the debug logger with automatic adapter injection\n *\n * The adapter is automatically configured when AppsProvider connects.\n * Use this hook to access the logger and optionally configure it.\n *\n * @param config - Optional configuration to apply\n * @returns The configured client debug logger\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const logger = useDebugLogger({ enabled: true, level: \"debug\" });\n *\n * const handleClick = () => {\n * logger.info(\"Button clicked\", { timestamp: Date.now() });\n * };\n *\n * return <button onClick={handleClick}>Click me</button>;\n * }\n * ```\n */\nexport function useDebugLogger(config?: Partial<ClientDebugConfig>): ClientDebugLogger {\n // Verify we're inside AppsProvider (adapter is set by createClient)\n useAppsContext();\n\n // Apply configuration when it changes\n useEffect(() => {\n if (config) {\n clientDebugLogger.configure(config);\n }\n }, [config]);\n\n return clientDebugLogger;\n}\n"]} |
+2
-2
| { | ||
| "name": "@mcp-apps-kit/ui-react", | ||
| "version": "0.3.0", | ||
| "version": "0.4.0", | ||
| "description": "React bindings for MCP applications", | ||
@@ -47,3 +47,3 @@ "type": "module", | ||
| "dependencies": { | ||
| "@mcp-apps-kit/ui": "^0.3.0" | ||
| "@mcp-apps-kit/ui": "^0.4.0" | ||
| }, | ||
@@ -50,0 +50,0 @@ "peerDependencies": { |
+24
-1
@@ -120,2 +120,20 @@ # @mcp-apps-kit/ui-react | ||
| ### Automatic size notifications | ||
| By default, the MCP adapter automatically reports UI size changes to the host using a ResizeObserver. This feature is **only supported in MCP Apps** and is silently ignored in ChatGPT. | ||
| To disable automatic resizing: | ||
| ```tsx | ||
| export function App() { | ||
| return ( | ||
| <AppsProvider autoResize={false}> | ||
| <Widget /> | ||
| </AppsProvider> | ||
| ); | ||
| } | ||
| ``` | ||
| **Note:** The `autoResize` option is only applied during initial mount. Changing it at runtime has no effect. | ||
| The `AppClientTools` type is generated in your server code: | ||
@@ -150,2 +168,7 @@ | ||
| - `AppsProvider` - Context wrapper for all hooks | ||
| - `client?` - Pre-initialized client instance (optional) | ||
| - `forceAdapter?` - Force a specific adapter ("mcp" | "openai" | "mock") | ||
| - `autoResize?` - Enable/disable automatic size change notifications (default: `true`). Only supported in MCP Apps; ignored in ChatGPT. Note: changing this prop after initial mount has no effect. | ||
| - `fallback?` - Component to show while client initializes | ||
| - `errorFallback?` - Component to show on initialization error | ||
@@ -207,3 +230,3 @@ ### Core Hooks | ||
| // Host version (MCP Apps only) | ||
| // { name: "Claude Desktop", version: "1.0.0" } | ||
| // { name: "MCP Host", version: "1.0.0" } | ||
| return <div>Host: {version?.name}</div>; | ||
@@ -210,0 +233,0 @@ } |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
149093
2.19%692
2.37%303
8.21%+ Added
- Removed
Updated