Skip to content

Conversation

@trangdoan982
Copy link
Collaborator

@trangdoan982 trangdoan982 commented Jun 17, 2025

https://www.loom.com/share/ea08a74d1e584f8ab58702b70cf7bf27

Summary by CodeRabbit

  • New Features
    • Introduced a popup menu that appears when text is selected within a block, providing quick access to relevant actions.
    • Added keyboard navigation enhancements for the popup menu, supporting up/down arrow navigation.
    • Popup menu now restores and focuses the original text selection when triggered.
  • Style
    • Added new styles for the text selection popup, improving its appearance and visibility in the interface.

@linear
Copy link

linear bot commented Jun 17, 2025

@vercel
Copy link

vercel bot commented Jun 17, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
discourse-graph ⬜️ Skipped (Inspect) Jun 18, 2025 4:24pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 17, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This update introduces a text selection popup feature in the Roam app. It adds new UI components and event listeners to detect text selection and display a contextual menu near the cursor. Supporting utilities manage the popup's rendering and removal, and new styles are applied for the popup's appearance.

Changes

File(s) Change Summary
apps/roam/src/components/DiscourseNodeMenu.tsx Enhanced NodeMenu to accept a trigger prop, added internal state for open/close, improved keyboard navigation, and introduced new TextSelectionNodeMenu component.
apps/roam/src/index.ts Imported and applied new popup CSS, registered selectionchange and mousedown event listeners, and added cleanup on unload.
apps/roam/src/styles/textSelectionPopup.css Added new CSS for styling the text selection popup and its buttons.
apps/roam/src/utils/initializeObserversAndListeners.ts Added selectionChangeListener and documentClickListener for managing popup display and removal.
apps/roam/src/utils/renderTextSelectionPopup.tsx Introduced utility for rendering, positioning, and removing the text selection popup near the cursor.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Document
  participant Listeners
  participant PopupUtils
  participant PopupComponent

  User->>Document: Selects text
  Document->>Listeners: Fires selectionchange event
  Listeners->>PopupUtils: selectionChangeListener invoked
  PopupUtils->>PopupUtils: Finds block element & textarea
  PopupUtils->>PopupUtils: Calculates cursor position
  PopupUtils->>PopupComponent: Renders TextSelectionNodeMenu at cursor
  User->>Document: Clicks elsewhere
  Document->>Listeners: Fires mousedown event
  Listeners->>PopupUtils: documentClickListener invoked
  PopupUtils->>PopupUtils: Determines if click outside popup
  PopupUtils->>PopupComponent: Removes popup if needed
Loading

Suggested reviewers

  • mdroidian

Poem

A rabbit with paws oh-so-light,
Spotted your cursor’s shining bright.
With a menu that pops—
When selection just stops—
It hops in with features so right!
Now, with a click or a tap,
Your workflow’s a snap!
🐇✨


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@trangdoan982
Copy link
Collaborator Author

@CodeRabbit full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 17, 2025

✅ Actions performed

Full review triggered.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (6)
apps/roam/src/styles/textSelectionPopup.css (1)

8-14: Prefer using CSS variables or existing Blueprint tokens for colors and radii

Hard-coding palette values (#d3d8de, #f7f9fc, etc.) here makes it harder to keep the extension visually consistent with the host theme and to support dark-mode in the future. Consider exposing them through CSS variables (or referring to Blueprint’s Sass variables) so the popup automatically inherits theme changes.

apps/roam/src/utils/initializeObserversAndListeners.ts (1)

269-287: Minor: account for Blueprint v5 class names

bp3- prefixes are Blueprint v3/4. If the library is upgraded, the click-outside test will fail.
Consider a more future-proof test such as target.closest("[class*='bp']-popover-content") or explicitly include bp4- / bp5- in the selector list.

apps/roam/src/utils/renderTextSelectionPopup.tsx (3)

7-8: Type mismatch: container is a DIV, not a SPAN

currentPopupContainer is created with document.createElement("div"), so its type should be HTMLDivElement to avoid casting later.

-let currentPopupContainer: HTMLSpanElement | null = null;
+let currentPopupContainer: HTMLDivElement | null = null;

50-52: Remove leftover console.log to avoid noisy logs in production

-  const coords = getCoordsFromTextarea(targetTextarea);
-  console.log(coords);
+  const coords = getCoordsFromTextarea(targetTextarea);

56-60: Absolute positioning may break inside scrollable/relative containers

Because the popup is inserted inside the block’s parent but positioned absolute, its offset parent becomes the first position: relative ancestor (often the block itself). When the page is scrolled the popup can drift.
Consider using position: fixed with viewport coords, or compute offsets relative to document.body and insert the container there.

apps/roam/src/components/DiscourseNodeMenu.tsx (1)

101-130: Escape key no longer closes the menu

keydownListener intercepts arrows & enter but lost the "Escape" branch that previously dismissed the menu. Users expect Esc to cancel. Add it back:

+      } else if (e.key === "Escape") {
+        onClose();
+        document.body.click();
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 530c7a2 and 6357754.

📒 Files selected for processing (5)
  • apps/roam/src/components/DiscourseNodeMenu.tsx (8 hunks)
  • apps/roam/src/index.ts (4 hunks)
  • apps/roam/src/styles/textSelectionPopup.css (1 hunks)
  • apps/roam/src/utils/initializeObserversAndListeners.ts (4 hunks)
  • apps/roam/src/utils/renderTextSelectionPopup.tsx (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/roam/src/utils/initializeObserversAndListeners.ts (1)
apps/roam/src/utils/renderTextSelectionPopup.tsx (3)
  • findBlockElementFromSelection (9-35)
  • renderTextSelectionPopup (37-74)
  • removeTextSelectionPopup (76-82)
🔇 Additional comments (3)
apps/roam/src/index.ts (2)

108-117: Listener cleanup looks good — double-check capture/bubble symmetry

selectionchange and mousedown are attached without the { capture: true } option, but later removed with the default matcher as well – that’s correct.
Just make sure that elsewhere in the codebase we never attach the same listeners with capture: true, otherwise the removal in unload would leave the captured handler dangling.


135-140: Style element already returned → no further action

Nice to see the new textSelectionPopupStyle added to the elements array so Roam takes care of detaching it automatically.

apps/roam/src/components/DiscourseNodeMenu.tsx (1)

219-290: Selection preservation works – consider guarding against stale indices

If the user modifies the textarea before clicking the trigger, the saved {start,end} indices may be invalid. You could recompute the selection range from window.getSelection() in handleTriggerMouseDown instead of relying on initial values.

Copy link
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

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

A few requested changes and comments, but great stuff!

I'm wondering if we couldn't directly call the NodeMenu from the TextSelectionNodeMenu in a way that wouldn't require changes to isOpen, target, and the addition of onInteraction. But this could be a later optimization.

We should also remove the TextSelectionNodeMenu if a user selects text and hits the keyboard hotkey. I think this might be solved with a more direct call as well.

image

const keydownListener = useCallback(
(e: KeyboardEvent) => {
if (e.key === "ArrowRight" || e.key === "ArrowDown") {
if (e.key === "ArrowDown") {
Copy link
Contributor

Choose a reason for hiding this comment

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

Any specific reason ArrowRight/ArrowLeft was removed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yeah i often select with Shift+ arrow left/right, to select up to specific characters using keyboard-only. adding key listener for ArrowLeft and ArrowRight prevents this flow.

@trangdoan982 trangdoan982 requested a review from mdroidian July 1, 2025 14:38
Copy link
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

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

🔥

@trangdoan982 trangdoan982 merged commit 60f2784 into main Jul 1, 2025
4 checks passed
@trangdoan982 trangdoan982 deleted the eng-412-node-popover-create branch July 1, 2025 21:02
@github-project-automation github-project-automation bot moved this to Done in General Jul 1, 2025
document.body.click();
} else if (e.key === "Escape") {
onClose();
document.body.click();
Copy link
Contributor

Choose a reason for hiding this comment

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

@trangdoan982 do you remember why document.body.click() was added here? I imagine a user would like to keep editing the block so I want to remove it, but I don't want to re-introduce a bug that this possibly fixing.

Copy link
Contributor

Choose a reason for hiding this comment

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

I removed it here: #477

Let me know if that is in error.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i don't think it was specifically to address any bug but just as general behavior to de-focus. I think it's okay that you remove it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants