feat/tab complete emnojis#67
Conversation
WalkthroughAdds emoji autocomplete to the chat input. Introduces a new hook for emoji completion, a dropdown UI component for emoji suggestions, integrates keyboard handling in ChatArea, and adds the emoji-datasource dependency to supply emoji data. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant ChatArea
participant useEmojiCompletion as useEmojiCompletion (hook)
participant EmojiDropdown as EmojiAutocompleteDropdown
User->>ChatArea: Type text (e.g., ":sm")
ChatArea->>useEmojiCompletion: handleEmojiCompletion(prefix detection)
useEmojiCompletion-->>ChatArea: matches, currentIndex, updated text/cursor
ChatArea->>EmojiDropdown: render(isVisible, matches, currentIndex)
alt User presses Tab
ChatArea->>useEmojiCompletion: cycle to next match
useEmojiCompletion-->>ChatArea: updated text/cursor, index
ChatArea->>EmojiDropdown: update highlight
end
alt User presses Enter or clicks item
User->>ChatArea: Select current match
ChatArea->>useEmojiCompletion: finalize/reset
ChatArea->>EmojiDropdown: close
else User presses Escape or types non-matching
ChatArea->>useEmojiCompletion: reset
ChatArea->>EmojiDropdown: close
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
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. 🧪 Early access (Sonnet 4.5): enabledWe are currently testing the Sonnet 4.5 model, which is expected to improve code review quality. However, this model may lead to increased noise levels in the review comments. Please disable the early access features if the noise level causes any inconvenience. Note:
Comment |
|
Automated deployment preview for the PR in the Cloudflare Pages. |
8acfc98 to
7aab2cb
Compare
…o feat/tab-complete-emnojis
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/hooks/useEmojiCompletion.ts (1)
113-127: Consider removing redundant length check (optional).The regex pattern
/:([a-zA-Z_]+)$/already requires at least one character after the colon (the+quantifier), so the check on line 125 (if (emojiQuery.length === 0)) is redundant. However, this is harmless and may serve as defensive programming for future regex changes.If you prefer a leaner implementation, you can remove lines 125-127:
- if (emojiQuery.length === 0) { - return null; - } -src/components/ui/EmojiAutocompleteDropdown.tsx (1)
125-170: Consider adding accessibility attributes (recommended).The dropdown renders correctly and handles user interactions well. To improve accessibility, consider adding ARIA attributes such as
role="listbox",role="option", andaria-selectedto support screen readers and keyboard-only navigation.Example enhancement:
<div ref={dropdownRef} + role="listbox" className="fixed z-[9999] bg-discord-dark-300 border border-discord-dark-500 rounded-md shadow-xl max-w-xs min-w-48" style={{ top: position.top, left: position.left, }} > <div className="py-1 max-h-60 overflow-y-auto"> <div className="px-3 py-1 text-xs text-discord-text-muted font-semibold uppercase tracking-wide border-b border-discord-dark-500"> Emojis </div> {displayEmojis.map((emojiItem, index) => ( <div key={`${emojiItem.unified}-${index}`} data-emoji-index={index} + role="option" + aria-selected={index === selectedIndex} className={`px-3 py-2 cursor-pointer flex items-center gap-2 transition-colors duration-150 ${ index === selectedIndex ? "bg-discord-text-link text-white" : "text-discord-text-normal hover:bg-discord-dark-200 hover:text-white" }`} onClick={() => onSelect(emojiItem.emoji)} onMouseEnter={() => setSelectedIndex(index)} >src/components/layout/ChatArea.tsx (1)
354-371: Consider aligning regex patterns for consistency (optional).The Tab key handling logic is sound. However, line 363 uses the regex
/:([a-zA-Z_]*)$/(allowing zero characters after colon), while the hook uses/:([a-zA-Z_]+)$/(requiring at least one character). This inconsistency means typing just:and pressing Tab will attempt emoji completion here but the hook will returnnull. While this doesn't break functionality, aligning the patterns improves clarity.Consider changing line 363 to match the hook's pattern:
- const emojiMatch = textBeforeCursor.match(/:([a-zA-Z_]*)$/); + const emojiMatch = textBeforeCursor.match(/:([a-zA-Z_]+)$/);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (4)
package.json(1 hunks)src/components/layout/ChatArea.tsx(9 hunks)src/components/ui/EmojiAutocompleteDropdown.tsx(1 hunks)src/hooks/useEmojiCompletion.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/layout/ChatArea.tsx (2)
src/hooks/useEmojiCompletion.ts (1)
useEmojiCompletion(59-200)src/components/ui/EmojiAutocompleteDropdown.tsx (1)
EmojiAutocompleteDropdown(23-171)
🔇 Additional comments (16)
package.json (1)
33-33: LGTM! Dependency addition looks good.The
emoji-datasourcepackage at version ^16.0.0 is correctly added to support the new emoji completion feature. Based on learnings, this version provides Unicode Emoji 16.x support with updated emoji metadata and image sets.src/hooks/useEmojiCompletion.ts (5)
1-57: LGTM! Type definitions and emoji data processing are well-structured.The interfaces clearly define the data flow, and the
processedEmojiDatatransformation correctly converts Unicode hex sequences to rendered emoji characters usingString.fromCodePoint. Computing this once at module load is efficient.
59-91: LGTM! State management and helper callbacks are correctly implemented.The hook uses
useStatefor completion state anduseRefto track the previous text for manual edit detection. All callbacks are properly memoized withuseCallbackand have correct dependency arrays.
130-140: LGTM! Emoji matching logic is sound.The filter correctly checks if any
short_namecontains the query (case-insensitive) and limits results to 10 matches. Returningnullwhen no matches are found is appropriate.
142-183: LGTM! Text replacement and cycling logic are correctly implemented.Both the initial emoji insertion and subsequent cycling through matches correctly construct the new text, update cursor position, and maintain internal state. The use of modulo arithmetic for wrapping is appropriate.
188-200: LGTM! Hook return value is complete and well-typed.All state properties and helper functions are correctly exposed, matching the
EmojiCompletionResultinterface definition.src/components/ui/EmojiAutocompleteDropdown.tsx (4)
1-35: LGTM! Component structure and props are well-defined.The
EmojiAutocompleteDropdownPropsinterface clearly defines all necessary props, with sensible defaults for optional properties. The component signature is clean and follows React best practices.
36-57: LGTM! State and scroll effects are correctly implemented.The component properly syncs
selectedIndexwith externalcurrentMatchIndexand smoothly scrolls the selected item into view. While usingquerySelectorcould be replaced with refs for better performance, the impact is negligible for a maximum of 10 items.
59-103: Verify Space key behavior for UX.The keyboard handler correctly prevents default actions and manages navigation. However, the Space key (line 93) closes the dropdown. This might be unexpected if a user wants to exit emoji completion by typing a space (e.g., after
:smile). Consider whether Space should close the dropdown or simply reset completion and insert a space.Additionally, the document-level event listener with
capture: trueis necessary to intercept events before other handlers, but be aware it can interfere with other components. The cleanup is correctly implemented, so this is just a note for maintainability.
109-121: LGTM! Position calculation is appropriate for chat UI.The dropdown is positioned above the input, which is correct for typical chat interfaces where the input is at the bottom of the viewport. However, note that if the input is near the top of the viewport, the dropdown might render off-screen. This is an edge case and unlikely in the typical chat layout, but consider adding viewport boundary checks if this becomes an issue in testing.
src/components/layout/ChatArea.tsx (6)
22-22: LGTM! Imports and hook initialization are correct.The new
useEmojiCompletionhook andEmojiAutocompleteDropdowncomponent are properly imported, and theshowEmojiAutocompletestate is added to manage dropdown visibility. The hook is initialized alongside the existingtabCompletionhook, maintaining consistency.Also applies to: 39-39, 87-87, 131-132
376-382: LGTM! Autocomplete key handling correctly extended.The condition now properly checks for both
showAutocompleteandshowEmojiAutocomplete, allowing either dropdown to handle navigation keys without interference.
460-489: LGTM! Emoji completion handler mirrors tab completion flow.The
handleEmojiCompletionfunction correctly integrates the emoji completion hook, updates the message text and cursor position, and manages dropdown visibility. The pattern is consistent with the existinghandleTabCompletionfunction, which aids maintainability.
491-512: LGTM! Input change handler correctly resets emoji completion.The
handleInputChangefunction properly resets both tab and emoji completion states when the user types, and hides both dropdowns. This maintains consistent behavior across completion types.
585-662: LGTM! Emoji autocomplete handlers are correctly implemented.All three handlers (
handleEmojiAutocompleteSelect,handleEmojiAutocompleteClose,handleEmojiAutocompleteNavigate) correctly manage text replacement, cursor positioning, and state synchronization. The call toupdatePreviousTextin the navigate handler is crucial for preventing false resets during navigation.
1193-1203: LGTM! EmojiAutocompleteDropdown integration is complete.The dropdown is correctly rendered with all necessary props, and the visibility condition (
showEmojiAutocomplete || emojiCompletion.isActive) ensures it displays at the appropriate times. The integration is consistent with the existingAutocompleteDropdownpattern.
* Improved emoji dialog And click again to just add * DRY types in ircclient * Split and refactor chat area a little * lint fix * Use same emoji picker everywhere * tab complete emojis
Summary by CodeRabbit
New Features
Chores