feat(sdk): let the interview app own the slider/popup/float close button#62
Merged
Merged
Conversation
Contributor
📦 Snapshot ReleasePublished snapshot packages for this PR: pnpm add @perspective-ai/sdk@1.12.0-pr-62-20260701112728
pnpm add @perspective-ai/sdk-react@1.12.0-pr-62-20260701112728Or use the npm tag (always points to the latest snapshot from this PR): pnpm add @perspective-ai/sdk@pr-62
pnpm add @perspective-ai/sdk-react@pr-62 |
Contributor
Author
|
@codex review |
There was a problem hiding this comment.
Pull request overview
This PR updates the SDK/embed handshake and UI behavior so the interview app (inside the iframe) owns the persistent close (X) button for slider / popup / float embeds, while the SDK only shows a temporary close button during the loading skeleton and removes it at skeleton-hide to prevent overlap with the app’s top-right UI.
Changes:
- Add
renderCloseButtontoperspective:init(slider/popup/float only) and retire the SDK-emittedhasCloseButtonflag (kept as deprecated type for legacy clients). - Remove the SDK close button as soon as the loading skeleton hides for slider/popup/float (handoff moment).
- Update unit tests and e2e fixtures/tests so e2e clicks the app-rendered close button inside the iframe.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/sdk/src/types.ts | Deprecates hasCloseButton and adds renderCloseButton to the init protocol type. |
| packages/sdk/src/iframe.ts | Sends renderCloseButton (conditionally) in perspective:init and stops emitting hasCloseButton. |
| packages/sdk/src/slider.ts | Removes the SDK close button at skeleton-hide; sends renderCloseButton in init options. |
| packages/sdk/src/slider.test.ts | Adds a unit test asserting the SDK close button is removed on visual-ready. |
| packages/sdk/src/popup.ts | Removes the SDK close button at skeleton-hide; sends renderCloseButton in init options. |
| packages/sdk/src/popup.test.ts | Updates init-message assertions to renderCloseButton and adds skeleton-hide close-button removal coverage. |
| packages/sdk/src/float.ts | Makes float close button explicitly temporary (including disableClose handling); sends renderCloseButton. |
| packages/sdk/src/float.test.ts | Adds coverage for close-button handoff and renderCloseButton in init. |
| packages/sdk/e2e/fixtures/mock-iframe.html | Adds an app-rendered close button shown when renderCloseButton is requested; emits perspective:close. |
| packages/sdk/e2e/embed.spec.ts | Updates e2e to click the app-rendered close button inside the iframe after the loading overlay detaches. |
| .changeset/app-owned-close-button.md | Documents the protocol/UI change as a minor release. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
LEVI-RIVKIN
commented
Jul 1, 2026
The Perspective app now renders its own close (X) button for slider, popup, and float embeds and emits perspective:close when clicked (codebase#4397). This stops the SDK's X from overlapping the app's top-right UI — the participant avatar on slider/popup, and the header ··· menu on float. The SDK now only draws a temporary X over the loading skeleton and removes it the moment the interview becomes visible (at skeleton-hide), so the app's X takes over with no double or overlapping X, and no no-X gap. - iframe.ts: the perspective:init handshake sends `renderCloseButton` (true unless disableClose) for slider/popup/float; widget/fullpage have no X and omit it. - slider.ts / popup.ts / float.ts: temporary close button removed in hideSkeleton; float's launcher bubble is untouched and still closes the window (perspective:close maps to closeFloat). - styles.ts: the temporary X uses a ghost style (transparent background) to match the app's X, so the handoff has no visual pop. - Retire the legacy `hasCloseButton` init flag — the SDK no longer emits it. It stays on InitMessage as @deprecated for older deployed SDK clients. - e2e: the persistent X is now app-owned, so the mock iframe renders its own X on renderCloseButton and emits perspective:close; the close-button tests click that (after the loading overlay detaches). - Add a changeset (minor). Backdrop-click/Escape and disableClose unchanged. Verified end-to-end against the production app (getperspective.ai): slider/popup/float hand the X to the app header with no overlap. Unit (415) and e2e (39) tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lk3DUSi41xCaYr5GGC1qh8
ce2f0e9 to
d2f7626
Compare
vinaypuppal
approved these changes
Jul 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
The Perspective app now renders its own close (X) button for slider, popup, and float embeds and emits
perspective:closewhen clicked (shipped in codebase#4397). This was done because the SDK's own X overlapped the app's top-right UI — the participant avatar on slider/popup, and the header···menu on float.This PR retires the SDK's self-rendered X in favour of letting the app draw it, while keeping a close affordance visible during loading.
How it works
perspective:inithandshake now sendsrenderCloseButton(trueunlessdisableClose) for slider/popup/float.widget/fullpagehave no X and omit it.hasCloseButtoninit flag is retired — the SDK no longer emits it. It stays onInitMessageas@deprecatedbecause the app may still receive it from older deployed SDK clients.disableClosebehaviour are unchanged. Float's launcher bubble is untouched and still closes the window (perspective:closemaps tocloseFloat).Changes
iframe.ts— sendrenderCloseButtonin init; drophasCloseButtonfrom the send path.slider.ts/popup.ts/float.ts— temporary close button removed inhideSkeleton; sendrenderCloseButton: !disableClose.types.ts—renderCloseButtonadded;hasCloseButtonmarked@deprecated.e2e— the persistent X is now app-owned, so the mock iframe renders its own X onrenderCloseButtonand emitsperspective:close; the close-button tests click that (after the loading overlay detaches).minor).Verification
disableClosecorrectly shows no X on either side.Rollout note
This relies on the app rendering the X, which is already in production (codebase#4397), so there's no deploy-ordering risk. Versioned as a minor since it adds to the init protocol; backward compatible (the app prefers
renderCloseButtonand still honours the legacyhasCloseButtonpath for older SDKs).🤖 Generated with Claude Code
Generated by Claude Code