diff --git a/.changeset/breezy-files-divide.md b/.changeset/breezy-files-divide.md new file mode 100644 index 0000000..14b2d7f --- /dev/null +++ b/.changeset/breezy-files-divide.md @@ -0,0 +1,5 @@ +--- +'@openai/chatkit-react': patch +--- + +Removed usage of React 19 only ref callback cleanup function diff --git a/.changeset/thick-eggs-know.md b/.changeset/thick-eggs-know.md new file mode 100644 index 0000000..7298d44 --- /dev/null +++ b/.changeset/thick-eggs-know.md @@ -0,0 +1,5 @@ +--- +'@openai/chatkit-react': minor +--- + +Exposed a ref to the underlying `OpenAIChatKit` DOM element in the return value of `useChatKit` diff --git a/packages/chatkit-react/src/ChatKit.tsx b/packages/chatkit-react/src/ChatKit.tsx index 0395d85..d05314c 100644 --- a/packages/chatkit-react/src/ChatKit.tsx +++ b/packages/chatkit-react/src/ChatKit.tsx @@ -45,46 +45,39 @@ export const ChatKit = React.forwardRef( return ( { - ref.current = chatKit; control.setInstance(chatKit); + if (typeof forwardedRef === 'function') { forwardedRef(chatKit); } else if (forwardedRef) { forwardedRef.current = chatKit; } - if (ref.current) { - const abortController = new AbortController(); - const events = { - 'chatkit.error': 'onError', - 'chatkit.response.end': 'onResponseEnd', - 'chatkit.response.start': 'onResponseStart', - 'chatkit.log': 'onLog', - 'chatkit.thread.change': 'onThreadChange', - 'chatkit.thread.load.start': 'onThreadLoadStart', - 'chatkit.thread.load.end': 'onThreadLoadEnd', - } satisfies { - [K in keyof ChatKitEvents]: ToEventHandlerKey; - }; + if (!ref.current) { + return; + } + + const events: { + [K in keyof ChatKitEvents]: ToEventHandlerKey; + } = { + 'chatkit.error': 'onError', + 'chatkit.response.end': 'onResponseEnd', + 'chatkit.response.start': 'onResponseStart', + 'chatkit.log': 'onLog', + 'chatkit.thread.change': 'onThreadChange', + 'chatkit.thread.load.start': 'onThreadLoadStart', + 'chatkit.thread.load.end': 'onThreadLoadEnd', + }; - for (const eventName of Object.keys( - events, - ) as (keyof ChatKitEvents)[]) { - ref.current.addEventListener( - eventName, - (e) => { - const handler = control.handlers[events[eventName]]; - if (typeof handler === 'function') { - handler(e.detail as any); - } - }, - { signal: abortController.signal }, - ); - } + const eventNames = Object.keys(events) as (keyof ChatKitEvents)[]; - return () => { - abortController.abort(); - }; + for (const event of eventNames) { + ref.current.addEventListener(event, (e) => { + const handler = control.handlers[events[event]]; + if (typeof handler === 'function') { + handler(e.detail as any); + } + }); } }} {...htmlProps} diff --git a/packages/chatkit-react/src/useChatKit.ts b/packages/chatkit-react/src/useChatKit.ts index 1a4e8e8..dc2a790 100644 --- a/packages/chatkit-react/src/useChatKit.ts +++ b/packages/chatkit-react/src/useChatKit.ts @@ -50,6 +50,7 @@ export type ChatKitControl = { export type UseChatKitReturn = ChatKitMethods & { control: ChatKitControl; + ref: React.RefObject; }; export function useChatKit(options: UseChatKitOptions): UseChatKitReturn { @@ -98,5 +99,8 @@ export function useChatKit(options: UseChatKitOptions): UseChatKitReturn { }; }, [stableOptions, setInstance]); - return React.useMemo(() => ({ ...methods, control }), [methods, control]); + return React.useMemo( + () => ({ ...methods, control, ref }), + [methods, control], + ); }