Skip to content

Add tooltip message type with viewport-aware positioning#127

Merged
karngyan merged 16 commits intodevelopfrom
inapp-14216
Mar 24, 2026
Merged

Add tooltip message type with viewport-aware positioning#127
karngyan merged 16 commits intodevelopfrom
inapp-14216

Conversation

@karngyan
Copy link
Copy Markdown
Member

@karngyan karngyan commented Mar 23, 2026

Summary

Adds a tooltip message type to the web SDK that anchors messages to DOM elements with viewport-aware positioning, auto-repositioning on scroll/resize, and directional arrow indicators.

Changes

  • Tooltip message flow (message-manager.ts): New showTooltipMessage() path that validates the target element exists, dismisses any existing tooltip on the same target, and loads the tooltip without blocking overlays. Tooltips coexist with overlays and with each other on different targets. Routes routeLoaded, sizeChanged, error, and routeError events through tooltip-specific handlers.
  • Positioning engine (tooltip-position-manager.ts): Full viewport-aware positioning system replacing the simple offset + single-flip logic:
    • Tries preferred position → opposite flip → remaining sides
    • Cross-axis clamping keeps tooltips within the viewport with arrow offset tracking
    • Hides tooltip when target scrolls out of view (viewport + scroll ancestor clipping)
    • Listens to scroll events on scrollable ancestors, not just the window
    • Returns a TooltipHandle with cleanup() and reposition() for external resize triggers
  • Tooltip template (tooltip.ts): Switched from id-based selectors (#gist-tooltip) to class-based (.gist-tooltip-inner) for multiple concurrent tooltips. CSS scoped under optional wrapperId. Added a clip wrapper around the iframe.
  • Component manager (message-component-manager.ts): showTooltipComponent returns a boolean indicating positioning success. New resizeTooltipComponent() sets iframe height and triggers repositioning. clearAllTooltipHandles() for bulk cleanup on setup() and clearUserToken().
  • Properties resolution (gist-properties-manager.ts): isEmbedded is false when tooltipPosition is set so tooltip messages skip the embed flow.
  • Example app: Tooltip demo section with position grid, edge-detection area, scrollable container, programmatic dismiss, and event log.

Test plan

  • Unit tests for tooltip-position-manager (visibility checks, fallback ordering, cross-axis clamping, hide/re-show, scroll ancestor clipping, arrow offset tracking)
  • Unit tests for message-component-manager (handle lifecycle, clearAllTooltipHandles, resize forwarding, positioning failure paths)
  • Unit tests for message-manager (tooltip show/hide flow, event routing, target validation, concurrent tooltips, overlay coexistence, invalid selector handling)
  • Unit tests for tooltip.ts template (scoped CSS, class-based selectors, multi-instance isolation)
  • Manual testing with example app tooltip demo section

Note

Medium Risk
Adds a new tooltip rendering path alongside existing overlay/embed flows and changes message lifecycle/event handling, which can affect how messages show/dismiss/resize across the SDK. Risk is moderated by extensive unit test coverage but touches core message routing and DOM interactions.

Overview
Adds a new tooltip message type to the web SDK, allowing Gist.showMessage to anchor messages to a DOM elementId using tooltipPosition without blocking existing overlays or other tooltips.

Implements a viewport/scroll-aware positioning engine (auto-fallback between sides, cross-axis clamping with arrow offset, hide/show when targets move in/out of view, and scroll-container listeners) and updates tooltip rendering to support multiple concurrent instances via class-based markup and optional CSS scoping.

Extends component/message managers with tooltip-specific load/show/hide/resize flows, tooltip-handle lifecycle cleanup (clearAllTooltipHandles() called during Gist.setup()), and updates property resolution so tooltip messages don’t route through embed behavior; also adds a tooltip demo section and styling in examples/ plus broad new/updated tests around tooltip behavior and event routing.

Written by Cursor Bugbot for commit 0f29bfe. This will update automatically on new commits. Configure here.

@karngyan karngyan requested a review from a team as a code owner March 23, 2026 15:38
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Comment on lines +382 to +384
log(
`Invalid tooltip target selector "${targetSelector}" for message ${currentMessage.messageId}`
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible for an exception to happen here? Would document ever be undefined?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

won't come from document as it always runs in browser, but might throw if the targetSelector is wrong .. which we are already catching.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

document.querySelector('not-existing-selector') returns null, and then !!null returns false 🤔.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To close the loop, Karn educated me in the error of my ways. Something like

document.querySelector('/')

can throw a SyntaxError exception.

@karngyan karngyan merged commit f468a85 into develop Mar 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants