feat(ChatMessages): expose registerMessageRef#6275
feat(ChatMessages): expose registerMessageRef#6275
registerMessageRef#6275Conversation
📝 WalkthroughWalkthroughThe Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/content/docs/2.components/chat-messages.md`:
- Line 448: The table cell for the `registerMessageRef` signature is broken by
the unescaped union pipe in `ComponentPublicInstance | null`; update the table
entry for `registerMessageRef(id: string, element: ComponentPublicInstance |
null)` to escape the pipe (e.g., `ComponentPublicInstance \| null`) so the `|`
is not treated as a Markdown column separator and the table renders correctly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 14812679-c85d-4832-a30b-2ea371b946c8
📒 Files selected for processing (2)
docs/content/docs/2.components/chat-messages.mdsrc/runtime/components/ChatMessages.vue
commit: |
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
d1913ee to
4f1fd8e
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/runtime/components/ChatMessages.vue`:
- Line 70: The slot prop type for registerMessageRef is too narrow and the ref
cleanup is missing; update the slot signature for default (and the other
occurrence referenced) so registerMessageRef accepts Element |
ComponentPublicInstance | null, and modify the implementation of
registerMessageRef (the function that currently stores refs in the message refs
map around the code handling lines ~127–132 and the similar block at ~319) to
delete the map entry when the callback receives null (i.e., on unmount) instead
of leaving stale entries; ensure you update both the type declarations and the
runtime logic that adds/removes entries in the refs map (refer to
registerMessageRef and the message refs map usage).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e34604dd-809a-455b-8542-74a84f20f6d7
📒 Files selected for processing (2)
docs/content/docs/2.components/chat-messages.mdsrc/runtime/components/ChatMessages.vue
✅ Files skipped from review due to trivial changes (1)
- docs/content/docs/2.components/chat-messages.md
| [K in keyof ChatMessageSlots]?: ExtendSlotWithVersion<K> | ||
| } & { | ||
| default?(props?: {}): VNode[] | ||
| default?(props: { registerMessageRef: (id: string, element: ComponentPublicInstance | null) => void }): VNode[] |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Vue 3.5 template ref callbacks (:ref="fn"), what argument types are passed for native HTML elements and for component refs? Is null passed on unmount?
💡 Result:
In Vue 3.5 (and earlier Vue 3 versions), template ref callbacks bound via :ref="fn" receive a single argument: - For native HTML elements: the DOM Element instance (e.g., HTMLInputElement). - For component refs: the component public instance (ComponentPublicInstance). Yes, null is passed to the callback when the element/component is unmounted. This behavior is unchanged in Vue 3.5, which primarily introduced useTemplateRef for string-based refs but retains function ref support as before.
Citations:
- 1: https://vuejs.org/guide/essentials/template-refs.html
- 2: https://vuejs.org/guide/essentials/template-refs
- 3: https://v3.vuejs.org/api/special-attributes.html
- 4: https://v3.vuejs.org/api/instance-methods.html
🏁 Script executed:
# Check the ChatMessages.vue file for the relevant code sections
cat -n src/runtime/components/ChatMessages.vue | sed -n '65,75p'Repository: nuxt/ui
Length of output: 524
🏁 Script executed:
# Check the registerMessageRef implementation
cat -n src/runtime/components/ChatMessages.vue | sed -n '125,135p'Repository: nuxt/ui
Length of output: 433
🏁 Script executed:
# Check the slot binding at line 319
cat -n src/runtime/components/ChatMessages.vue | sed -n '315,325p'Repository: nuxt/ui
Length of output: 665
🏁 Script executed:
# Verify file structure - count lines to ensure line numbers are valid
wc -l src/runtime/components/ChatMessages.vueRepository: nuxt/ui
Length of output: 94
Broaden registerMessageRef to handle native refs and cleanup unmounted entries.
Line 70 currently constrains the slot callback to ComponentPublicInstance, but Vue 3 template ref callbacks also receive native Element instances. Additionally, the current implementation at lines 127–132 does not delete stale entries when ref callbacks receive null on unmount. When custom default-slot markup uses native element refs, this can cause type mismatches and retain stale map entries.
Widen the type to Element | ComponentPublicInstance | null and add cleanup logic:
Suggested patch
export type ChatMessagesSlots = {
[K in keyof ChatMessageSlots]?: ExtendSlotWithVersion<K>
} & {
- default?(props: { registerMessageRef: (id: string, element: ComponentPublicInstance | null) => void }): VNode[]
+ default?(props: { registerMessageRef: (id: string, element: Element | ComponentPublicInstance | null) => void }): VNode[]
indicator?(props: { ui: ChatMessages['ui'] }): VNode[]
viewport?(props: { ui: ChatMessages['ui'], onClick: () => void }): VNode[]
}-function registerMessageRef(id: string, element: ComponentPublicInstance | null) {
- const elInstance = element?.$el
- if (elInstance) {
- messagesRefs.value.set(id, elInstance)
- }
-}
+function registerMessageRef(id: string, element: Element | ComponentPublicInstance | null) {
+ if (!element) {
+ messagesRefs.value.delete(id)
+ return
+ }
+
+ const elInstance = '$el' in element ? element.$el : element
+ if (elInstance instanceof HTMLElement) {
+ messagesRefs.value.set(id, elInstance)
+ }
+}Also applies to: 319-319
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/components/ChatMessages.vue` at line 70, The slot prop type for
registerMessageRef is too narrow and the ref cleanup is missing; update the slot
signature for default (and the other occurrence referenced) so
registerMessageRef accepts Element | ComponentPublicInstance | null, and modify
the implementation of registerMessageRef (the function that currently stores
refs in the message refs map around the code handling lines ~127–132 and the
similar block at ~319) to delete the map entry when the callback receives null
(i.e., on unmount) instead of leaving stale entries; ensure you update both the
type declarations and the runtime logic that adds/removes entries in the refs
map (refer to registerMessageRef and the message refs map usage).
| :style="{ '--last-message-height': `${lastMessageHeight}px` }" | ||
| > | ||
| <slot> | ||
| <slot :register-message-ref="registerMessageRef"> |
There was a problem hiding this comment.
Do we really need to expose this in default slot? Isn't it enough to access it through a template ref? 🤔
There was a problem hiding this comment.
Personally, I’d prefer to avoid creating a template ref every time I need one when I’m dealing with simpler cases. I see the template ref as necessary for more complex scenarios.
🔗 Linked issue
❓ Type of change
📚 Description
To be able to reuse the scroll logic even when the default slot is used
📝 Checklist