Skip to content

[WIKI-547] fix: update find suggestion logic for emoji extension#7411

Merged
pushya22 merged 9 commits intopreviewfrom
fix-emoji_popover_trigger
Jul 17, 2025
Merged

[WIKI-547] fix: update find suggestion logic for emoji extension#7411
pushya22 merged 9 commits intopreviewfrom
fix-emoji_popover_trigger

Conversation

@iam-vipin
Copy link
Copy Markdown
Member

@iam-vipin iam-vipin commented Jul 15, 2025

Description

Previously the logic looked at tiny pieces of text (one node at a time) which was breaking text on different decorator like bold and italic the updated logic looks at the whole text block as one piece now no matter how the text is decorated (bold, italic, etc.), the emoji suggestion will always find the colon and work correctly.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)

Screenshots and Media (if applicable)

Screen.Recording.2025-07-15.at.2.12.02.PM.mov
Screen.Recording.2025-07-15.at.8.44.27.PM.mov

Summary by CodeRabbit

  • New Features

    • Emoji suggestions now use improved matching logic for more accurate trigger detection.
    • The emoji list in the suggestion dropdown only appears when there is a non-empty query.
  • Bug Fixes

    • Prevented the emoji list from displaying when the query is empty.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jul 15, 2025

Walkthrough

The changes introduce a custom suggestion matching function for emoji triggers in the editor, update the emoji suggestion plugin to use this function, and modify the emoji list component to render only when a query is present. The query string is now passed to the emoji list during suggestion events.

Changes

File(s) Change Summary
.../emoji/emoji.ts Integrated customFindSuggestionMatch into emoji suggestion plugin configuration.
.../emoji/components/emojis-list.tsx Added query prop to EmojiListProps; component now conditionally renders only if query is non-empty.
.../emoji/suggestion.ts Passed current query string to EmojiList via props during suggestion lifecycle events.
.../helpers/find-suggestion-match.ts Added customFindSuggestionMatch function for advanced trigger-based suggestion matching in editor paragraphs.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Editor
    participant EmojiExtension
    participant EmojiList

    User->>Editor: Types text with emoji trigger
    Editor->>EmojiExtension: Detects trigger, invokes customFindSuggestionMatch
    EmojiExtension->>Editor: Returns match details (if any)
    Editor->>EmojiList: Renders EmojiList with query (if query is non-empty)
    EmojiList-->>Editor: Renders suggestion UI or returns null if query is empty
Loading

Possibly related PRs

Suggested reviewers

  • aaryan610

Poem

In the editor’s burrow, a trigger appears,
The rabbit hops in, matching queries with cheers.
If the query is empty, the list takes a nap,
But with a spark, emojis spring from the map!
Custom matches now guide each hop—
A joyful leap, emoji fun won’t stop!
🐰✨


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between af405f8 and 6347567.

📒 Files selected for processing (1)
  • packages/editor/src/core/helpers/find-suggestion-match.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/editor/src/core/helpers/find-suggestion-match.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript)
✨ Finishing Touches
  • 📝 Generate Docstrings

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.

@makeplane
Copy link
Copy Markdown

makeplane bot commented Jul 15, 2025

Pull Request Linked with Plane Work Items

Comment Automatically Generated by Plane

Copy link
Copy Markdown
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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between bfd4bd5 and 1bd5135.

📒 Files selected for processing (2)
  • packages/editor/src/core/extensions/emoji/emoji.ts (2 hunks)
  • packages/editor/src/core/extensions/emoji/find-suggestion-match.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/editor/src/core/extensions/emoji/emoji.ts (1)
packages/editor/src/core/extensions/emoji/find-suggestion-match.ts (1)
  • customFindSuggestionMatch (19-107)
🔇 Additional comments (3)
packages/editor/src/core/extensions/emoji/find-suggestion-match.ts (2)

1-18: Well-structured type definitions and imports.

The Trigger interface and SuggestionMatch type provide clear contracts for the function's configuration and return value.


34-107: Excellent implementation addressing the core issue.

The approach of processing the entire text block as a single piece effectively solves the problem where text decorations (bold/italic) would break emoji detection. The comprehensive validation checks and edge case handling ensure robust functionality.

packages/editor/src/core/extensions/emoji/emoji.ts (1)

18-18: Clean integration of the custom suggestion matcher.

The integration is minimal and correctly replaces the default suggestion matching behavior with the custom implementation that handles text blocks holistically.

Also applies to: 347-347

Copy link
Copy Markdown
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: 0

♻️ Duplicate comments (1)
packages/editor/src/core/extensions/emoji/find-suggestion-match.ts (1)

58-64: Critical security issue: Regex injection vulnerability persists.

The regex construction for prefix validation still contains the unescaped special characters issue flagged in the previous review. This could cause incorrect matching or runtime errors if allowedPrefixes contains regex metacharacters.

Apply this fix to properly escape the prefix characters:

  // Check if the trigger character has an allowed prefix
  const prefixChar = lastTriggerIndex > 0 ? textBeforeCursor[lastTriggerIndex - 1] : "\0";
- const matchPrefixIsAllowed = new RegExp(`^[${allowedPrefixes?.join("")}\0]?$`).test(prefixChar);
+ const escapedPrefixes = allowedPrefixes?.map(p => escapeForRegEx(p)).join("") || "";
+ const matchPrefixIsAllowed = new RegExp(`^[${escapedPrefixes}\0]?$`).test(prefixChar);
🧹 Nitpick comments (4)
packages/editor/src/core/extensions/emoji/find-suggestion-match.ts (4)

28-30: Complex regex construction needs validation.

The regex patterns are quite complex and handle multiple scenarios. The construction logic could benefit from clearer documentation or refactoring for maintainability.

Consider breaking this into separate functions for better readability:

- const regexp = allowSpaces
-   ? new RegExp(`${prefix}${escapedChar}.*?(?=\\s${finalEscapedChar}|$)`, "gm")
-   : new RegExp(`${prefix}(?:^)?${escapedChar}[^\\s${finalEscapedChar}]*`, "gm");
+ const regexp = allowSpaces 
+   ? createSpacesAllowedRegex(prefix, escapedChar, finalEscapedChar)
+   : createNoSpacesRegex(prefix, escapedChar, finalEscapedChar);

Then implement helper functions with clear documentation about what each pattern matches.


82-85: Edge case handling modifies match array directly.

The code directly modifies the match[0] array element, which could be confusing and potentially cause issues if the match object is used elsewhere.

Consider creating a new variable instead of modifying the match array:

  // Edge case handling; if spaces are allowed and we're directly in between
  // two triggers
+ let matchText = match[0];
+ let matchLength = match[0].length;
  if (allowSpaces && suffix.test(blockText.slice(to - 1, to + 1))) {
-   match[0] += " ";
+   matchText += " ";
+   matchLength += 1;
    to += 1;
  }

Then update the return statement to use matchText instead of match[0].


19-106: Function is quite long and handles multiple responsibilities.

The customFindSuggestionMatch function is doing a lot of work in a single function. Consider breaking it down into smaller, focused functions for better maintainability and testability.

Consider refactoring into smaller functions:

function validatePosition($position: ResolvedPos): { blockText: string; relativePos: number; blockStart: number } | null {
  // Position validation logic
}

function findTriggerIndex(text: string, char: string): number {
  // Trigger finding logic
}

function validatePrefix(textBeforeCursor: string, triggerIndex: number, allowedPrefixes: string[] | null): boolean {
  // Prefix validation logic
}

function createMatch(/* parameters */): SuggestionMatch {
  // Match creation logic
}

This would make the main function more readable and each piece more testable.


91-93: Code block detection is appropriate but could be more robust.

The code block detection only checks the parent type's spec.code property. Consider if additional context validation is needed for other restricted contexts.

You might want to add documentation about what other contexts should be excluded or consider making this configurable:

  // Additional check: make sure we're not inside a code block or other restricted context
  const $from = $position.doc.resolve(from);
- if ($from.parent.type.spec.code) {
+ if ($from.parent.type.spec.code || /* other restricted contexts */) {
    return null;
  }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1bd5135 and fffc5c7.

📒 Files selected for processing (1)
  • packages/editor/src/core/extensions/emoji/find-suggestion-match.ts (1 hunks)
🔇 Additional comments (3)
packages/editor/src/core/extensions/emoji/find-suggestion-match.ts (3)

1-3: LGTM!

Clean imports with necessary utilities from the tiptap library.


4-11: LGTM!

Well-structured interface definition with clear property types and naming.


13-17: LGTM!

Appropriate type alias for the function's return value with clear null handling.

@iam-vipin iam-vipin requested a review from aaryan610 July 15, 2025 15:19
@aaryan610 aaryan610 changed the title [WIKI-547] fix: update find suggestion logic [WIKI-547] fix: update find suggestion logic for emoji extension Jul 16, 2025
Copy link
Copy Markdown
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: 3

🧹 Nitpick comments (1)
packages/editor/src/core/helpers/find-suggestion-match.ts (1)

40-42: Update outdated comment about JavaScript lookbehinds.

The comment states that JavaScript doesn't have lookbehinds, but modern JavaScript (ES2018+) does support them. While the current implementation is fine and more compatible, the comment should be updated for accuracy.

Apply this diff to update the comment:

-  // JavaScript doesn't have lookbehinds. This hacks a check that first character
-  // is a space or the start of the line
+  // Check that the first character before the match is a space or the start of the line
+  // This approach is more compatible than using lookbehinds
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 455c114 and af405f8.

📒 Files selected for processing (2)
  • packages/editor/src/core/extensions/emoji/emoji.ts (2 hunks)
  • packages/editor/src/core/helpers/find-suggestion-match.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/editor/src/core/extensions/emoji/emoji.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
packages/editor/src/core/helpers/find-suggestion-match.ts (2)

17-31: Excellent implementation of paragraph-level text extraction!

This approach correctly addresses the core issue by extracting text from the entire paragraph using textBetween, which handles text across different nodes/marks. This ensures that formatted text (bold, italic, etc.) doesn't break the emoji suggestion detection.


1-73: ✅ Integration Verified: customFindSuggestionMatch properly integrated in the emoji extension

  • In packages/editor/src/core/extensions/emoji/emoji.ts:
    customFindSuggestionMatch is imported from @/helpers/find-suggestion-match.
    • It’s assigned to findSuggestionMatch in the Suggestion configuration.

  • In packages/editor/src/core/extensions/emoji/suggestion.ts:
    • The query prop is correctly passed through to the EmojiList items renderer.

All checks confirm the function is imported and used as intended.

@pushya22 pushya22 merged commit 6bb79df into preview Jul 17, 2025
5 of 6 checks passed
@pushya22 pushya22 deleted the fix-emoji_popover_trigger branch July 17, 2025 07:37
lifeiscontent pushed a commit that referenced this pull request Aug 18, 2025
* fix: update find suggestion logic

* refactor: remove logs

* refactor : make logic simpler

* feat: check for one char to show suggestion

* refactor : import types from extension

* refactor: add early return

* refactor : put custom suggestion in helper

* fix : char

* fix: types
@coderabbitai coderabbitai bot mentioned this pull request Aug 27, 2025
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants