1- import { ref , toRaw } from 'vue'
1+ import { nextTick , ref , toRaw } from 'vue'
2+
3+ const CONTEXT_MENU_MARGIN = 8
24
35const initialContextMenu = ( ) => ( {
46 visible : false ,
@@ -45,13 +47,52 @@ export const useChatEditing = ({
4547 locateMessageByServerId
4648} ) => {
4749 const contextMenu = ref ( initialContextMenu ( ) )
50+ const contextMenuElement = ref ( null )
4851 const messageEditModal = ref ( initialMessageEditModal ( ) )
4952 const messageFieldsModal = ref ( initialMessageFieldsModal ( ) )
5053
5154 const closeContextMenu = ( ) => {
5255 contextMenu . value = initialContextMenu ( )
5356 }
5457
58+ const repositionContextMenu = ( ) => {
59+ if ( ! process . client || ! contextMenu . value . visible ) return
60+ const menuEl = contextMenuElement . value
61+ if ( ! menuEl ) return
62+
63+ const rect = menuEl . getBoundingClientRect ( )
64+ const viewportWidth = Math . max ( window . innerWidth || 0 , document . documentElement ?. clientWidth || 0 )
65+ const viewportHeight = Math . max ( window . innerHeight || 0 , document . documentElement ?. clientHeight || 0 )
66+ if ( ! viewportWidth || ! viewportHeight ) return
67+
68+ const maxX = Math . max ( CONTEXT_MENU_MARGIN , viewportWidth - rect . width - CONTEXT_MENU_MARGIN )
69+ const maxY = Math . max ( CONTEXT_MENU_MARGIN , viewportHeight - rect . height - CONTEXT_MENU_MARGIN )
70+ const currentX = Number ( contextMenu . value . x || 0 )
71+ const currentY = Number ( contextMenu . value . y || 0 )
72+ const nextX = Math . min ( Math . max ( currentX , CONTEXT_MENU_MARGIN ) , maxX )
73+ const nextY = Math . min ( Math . max ( currentY , CONTEXT_MENU_MARGIN ) , maxY )
74+
75+ if ( nextX !== currentX || nextY !== currentY ) {
76+ contextMenu . value = {
77+ ...contextMenu . value ,
78+ x : nextX ,
79+ y : nextY
80+ }
81+ }
82+ }
83+
84+ const scheduleContextMenuReposition = ( ) => {
85+ if ( ! process . client ) return
86+ void nextTick ( ( ) => {
87+ const run = ( ) => repositionContextMenu ( )
88+ if ( typeof window . requestAnimationFrame === 'function' ) {
89+ window . requestAnimationFrame ( run )
90+ } else {
91+ run ( )
92+ }
93+ } )
94+ }
95+
5596 const loadContextMenuEditStatus = async ( params ) => {
5697 if ( ! process . client ) return
5798 const account = String ( params ?. account || '' ) . trim ( )
@@ -67,16 +108,19 @@ export const useChatEditing = ({
67108 const current = String ( contextMenu . value ?. message ?. id || '' ) . trim ( )
68109 if ( contextMenu . value . visible && current === messageId ) {
69110 contextMenu . value . editStatus = response || { modified : false }
111+ scheduleContextMenuReposition ( )
70112 }
71113 } catch {
72114 const current = String ( contextMenu . value ?. message ?. id || '' ) . trim ( )
73115 if ( contextMenu . value . visible && current === messageId ) {
74116 contextMenu . value . editStatus = null
117+ scheduleContextMenuReposition ( )
75118 }
76119 } finally {
77120 const current = String ( contextMenu . value ?. message ?. id || '' ) . trim ( )
78121 if ( contextMenu . value . visible && current === messageId ) {
79122 contextMenu . value . editStatusLoading = false
123+ scheduleContextMenuReposition ( )
80124 }
81125 }
82126 }
@@ -126,6 +170,8 @@ export const useChatEditing = ({
126170 void loadContextMenuEditStatus ( { account, username, message_id : messageId } )
127171 }
128172 } catch { }
173+
174+ scheduleContextMenuReposition ( )
129175 }
130176
131177 const prettyJson = ( value ) => {
@@ -519,6 +565,7 @@ export const useChatEditing = ({
519565
520566 return {
521567 contextMenu,
568+ contextMenuElement,
522569 messageEditModal,
523570 messageFieldsModal,
524571 closeContextMenu,
0 commit comments