Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/float-teaser-dismissible-react.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@perspective-ai/sdk-react": patch
"@perspective-ai/sdk": patch
---

Forward the `teaser.dismissible` option through `FloatBubble` / `useFloatBubble` to the core SDK. The hook that stabilizes the teaser prop only carried `enabled`, `delay`, and `sound`, so it silently dropped `dismissible` — setting `teaser={{ dismissible: false }}` had no effect when using the React package (the × dismiss button still rendered). It is now forwarded alongside the other teaser fields.

Also corrects the `EmbedConfig.teaser` JSDoc to list `dismissible` among the fields it controls. The vanilla config, CDN `data-perspective-teaser-dismissible` attribute, and core resolution already handled `dismissible` correctly; only the React wrapper was dropping it.
28 changes: 28 additions & 0 deletions packages/sdk-react/src/hooks/useFloatBubble.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,34 @@ describe("useFloatBubble", () => {
expect(mockUnmount).toHaveBeenCalledTimes(1);
});

it("forwards all teaser fields to createFloatBubble", async () => {
const { unmount } = renderHook(() =>
useFloatBubble({
researchId: "test-research-id",
teaser: {
enabled: true,
delay: 2000,
sound: false,
dismissible: false,
},
})
);
await act(async () => {});

expect(mockCreateFloatBubble).toHaveBeenCalledWith(
expect.objectContaining({
teaser: {
enabled: true,
delay: 2000,
sound: false,
dismissible: false,
},
})
);

unmount();
});

it("returns expected interface", async () => {
const { result, unmount } = renderHook(() =>
useFloatBubble({ researchId: "test-research-id" })
Expand Down
10 changes: 8 additions & 2 deletions packages/sdk-react/src/hooks/useFloatBubble.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,19 @@ export function useFloatBubble(
const teaserEnabled = teaser?.enabled;
const teaserDelay = teaser?.delay;
const teaserSound = teaser?.sound;
const teaserDismissible = teaser?.dismissible;
const hasTeaser = teaser !== undefined;
const stableTeaser = useMemo(
(): EmbedConfig["teaser"] =>
hasTeaser
? { enabled: teaserEnabled, delay: teaserDelay, sound: teaserSound }
? {
enabled: teaserEnabled,
delay: teaserDelay,
sound: teaserSound,
dismissible: teaserDismissible,
}
: undefined,
[hasTeaser, teaserEnabled, teaserDelay, teaserSound]
[hasTeaser, teaserEnabled, teaserDelay, teaserSound, teaserDismissible]
);

// Resolve ReactNode icons to SVG strings for the core SDK
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export interface EmbedConfig {
channel?: AIAssistantChannel | AIAssistantChannel[] | null;
/** Welcome message shown as a teaser bubble next to the float button. Only used for float-type embeds. */
welcomeMessage?: string;
/** Controls if and when the welcome teaser appears (`enabled`, `delay`, `sound`). Only used for float-type embeds. */
/** Controls if and when the welcome teaser appears (`enabled`, `delay`, `sound`, `dismissible`). Only used for float-type embeds. */
teaser?: TeaserConfig;
/** Custom button text for popup/slider triggers */
buttonText?: string;
Expand Down
Loading