diff --git a/.changeset/forty-trees-sniff.md b/.changeset/forty-trees-sniff.md new file mode 100644 index 0000000000..1696f2f02c --- /dev/null +++ b/.changeset/forty-trees-sniff.md @@ -0,0 +1,5 @@ +--- +"@gitbook/embed": minor +--- + +Improve API to control the GitBook embed diff --git a/.changeset/sixty-pumas-tell.md b/.changeset/sixty-pumas-tell.md new file mode 100644 index 0000000000..7a750285b7 --- /dev/null +++ b/.changeset/sixty-pumas-tell.md @@ -0,0 +1,5 @@ +--- +"gitbook": minor +--- + +Support customization of buttons and tools through iframe API diff --git a/biome.json b/biome.json index 69349302ac..53669a0a0b 100644 --- a/biome.json +++ b/biome.json @@ -18,6 +18,7 @@ "**/.vercel/**/*", "**/.cache/**/*", "**/.wrangler/**/*", + "packages/embed/standalone/**/*", "packages/openapi-parser/src/fixtures/**/*", "packages/emoji-codepoints/index.ts", "packages/icons/src/data/*.json", diff --git a/packages/embed/src/client/createGitBookFrame.ts b/packages/embed/src/client/createGitBookFrame.ts index 031b0c4359..baaabf647c 100644 --- a/packages/embed/src/client/createGitBookFrame.ts +++ b/packages/embed/src/client/createGitBookFrame.ts @@ -1,8 +1,7 @@ import { createChannel } from 'bidc'; import type { FrameToParentMessage, - GitBookPlaceholderSettings, - GitBookToolDefinition, + GitBookEmbeddableConfiguration, ParentToFrameMessage, } from './protocol'; @@ -22,11 +21,6 @@ export type GitBookFrameClient = { */ postUserMessage: (message: string) => void; - /** - * Register a custom tool. - */ - registerTool: (tool: GitBookToolDefinition) => void; - /** * Clear the chat. */ @@ -35,7 +29,7 @@ export type GitBookFrameClient = { /** * Set the placeholder settings. */ - setPlaceholder: (placeholder: GitBookPlaceholderSettings) => void; + configure: (settings: Partial) => void; /** * Register an event listener. @@ -53,6 +47,7 @@ export function createGitBookFrame(iframe: HTMLIFrameElement): GitBookFrameClien const channel = createChannel(iframe.contentWindow); channel.receive((message: FrameToParentMessage) => { + console.log('[gitbook:embed] received message', message); if (message.type === 'close') { const listeners = events.get('close') || []; if (listeners) { @@ -62,11 +57,19 @@ export function createGitBookFrame(iframe: HTMLIFrameElement): GitBookFrameClien }); const sendToFrame = (message: ParentToFrameMessage) => { + console.log('[gitbook:embed] send message', message); channel.send(message); }; const events = new Map void>>(); + const configuration: GitBookEmbeddableConfiguration = { + buttons: [], + welcomeMessage: '', + suggestions: [], + tools: [], + }; + return { navigateToPage: (pagePath) => { sendToFrame({ type: 'navigateToPage', pagePath }); @@ -75,9 +78,11 @@ export function createGitBookFrame(iframe: HTMLIFrameElement): GitBookFrameClien sendToFrame({ type: 'navigateToAssistant' }); }, postUserMessage: (message) => sendToFrame({ type: 'postUserMessage', message }), - registerTool: (tool) => sendToFrame({ type: 'registerTool', tool }), + configure: (settings) => { + Object.assign(configuration, settings); + sendToFrame({ type: 'configure', settings: configuration }); + }, clearChat: () => sendToFrame({ type: 'clearChat' }), - setPlaceholder: (settings) => sendToFrame({ type: 'setPlaceholder', settings }), on: (event, listener) => { const listeners = events.get(event) || []; listeners.push(listener); diff --git a/packages/embed/src/client/protocol.ts b/packages/embed/src/client/protocol.ts index 1356768998..f19b400e37 100644 --- a/packages/embed/src/client/protocol.ts +++ b/packages/embed/src/client/protocol.ts @@ -21,18 +21,42 @@ export type GitBookToolDefinition = AIToolDefinition & { }; /** - * Placeholder settings. + * Custom button definition to be passed to the embeddable GitBook. */ -export type GitBookPlaceholderSettings = { +export type GitBookEmbeddableButtonDefinition = { /** - * Welcome message to be displayed in the placeholder. + * Icon to be displayed in the button. */ - welcomeMessage: string; + icon: IconName; + + /** + * Label to be displayed in the button. + */ + label: string; + + /** + * Callback when the button is clicked. + */ + onClick: () => void | Promise; +}; +/** + * Overall configuration for the layout of the embeddable GitBook. + */ +export type GitBookEmbeddableConfiguration = { /** - * Suggestions to be displayed in the placeholder. + * Buttons to be displayed in the header of the embeddable GitBook. */ + buttons: GitBookEmbeddableButtonDefinition[]; + + /** Message to be displayed in the welcome page. */ + welcomeMessage: string; + + /** Suggestions of questions to be displayed in the welcome page. */ suggestions: string[]; + + /** Tools to be provided to the assistant. */ + tools: GitBookToolDefinition[]; }; /** @@ -43,16 +67,12 @@ export type ParentToFrameMessage = type: 'postUserMessage'; message: string; } - | { - type: 'registerTool'; - tool: GitBookToolDefinition; - } | { type: 'clearChat'; } | { - type: 'setPlaceholder'; - settings: GitBookPlaceholderSettings; + type: 'configure'; + settings: GitBookEmbeddableConfiguration; } | { type: 'navigateToPage'; diff --git a/packages/embed/src/react/GitBookAssistantFrame.tsx b/packages/embed/src/react/GitBookAssistantFrame.tsx deleted file mode 100644 index a6e4980f07..0000000000 --- a/packages/embed/src/react/GitBookAssistantFrame.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; -import type { GetFrameURLOptions, GitBookFrameClient } from '../client'; -import { useGitBook } from './GitBookProvider'; - -export type GitBookAssistantFrameProps = { - title?: string; - className?: string; -} & GetFrameURLOptions; - -/** - * Render a frame with the GitBook Assistant in it. - */ -export function GitBookAssistantFrame(props: GitBookAssistantFrameProps) { - const { title, className, ...frameOptions } = props; - - const frameRef = React.useRef(null); - const gitbookFrameRef = React.useRef(null); - const gitbook = useGitBook(); - const frameURL = gitbook.getFrameURL(frameOptions); - - React.useEffect(() => { - if (frameRef.current) { - gitbookFrameRef.current = gitbook.createFrame(frameRef.current); - } - }, [gitbook]); - - return ( -
-