11<script setup>
22import { ref , onMounted , onBeforeUnmount , watch , nextTick , computed , markRaw } from ' vue' ;
3+ import { Selection } from ' prosemirror-state' ;
4+ import { isCellSelection } from ' @extensions/table/tableHelpers/isCellSelection.js' ;
35import { ContextMenuPluginKey } from ' ../../extensions/context-menu/context-menu.js' ;
46import { getPropsByItemId } from ' ./utils.js' ;
57import { shouldBypassContextMenu } from ' ../../utils/contextmenu-helpers.js' ;
@@ -34,6 +36,39 @@ const sections = ref([]);
3436const selectedId = ref (null );
3537const currentContext = ref (null ); // Store context for action execution
3638
39+ const TABLE_SURFACE_SELECTOR = ' .superdoc-table-fragment, .superdoc-table-cell' ;
40+
41+ const hasExpandedSelection = (selection ) => {
42+ return (
43+ Number .isFinite (selection? .from ) &&
44+ Number .isFinite (selection? .to ) &&
45+ Number (selection .from ) !== Number (selection .to )
46+ );
47+ };
48+
49+ const setSelectionNearPos = (editor , pos , options = {}) => {
50+ if (! editor? .state ? .doc || ! Number .isFinite (pos)) return false ;
51+ const doc = editor .state .doc ;
52+ const maxPos = doc .content .size ;
53+ const clampedPos = Math .max (0 , Math .min (pos, maxPos));
54+
55+ try {
56+ const resolved = doc .resolve (clampedPos);
57+ const nextSelection = Selection .near (resolved, 1 );
58+ const tr = editor .state .tr .setSelection (nextSelection);
59+ if (options .addToHistory === false ) {
60+ tr .setMeta (' addToHistory' , false );
61+ }
62+ editor .dispatch ? .(tr);
63+ if (options .focus ) {
64+ editor .focus ? .();
65+ }
66+ return true ;
67+ } catch {
68+ return false ;
69+ }
70+ };
71+
3772// Helper to close menu if editor becomes read-only
3873const handleEditorUpdate = () => {
3974 if (! props .editor ? .isEditable && isOpen .value ) {
@@ -299,7 +334,7 @@ const handleRightClick = async (event) => {
299334 // Update cursor position to the right-click location before opening context menu,
300335 // unless the click lands inside an active selection (keep selection intact).
301336 const editorState = props .editor ? .state ;
302- const hasRangeSelection = editorState? .selection ? . from !== editorState ? . selection ? . to ;
337+ const hasRangeSelection = hasExpandedSelection ( editorState? .selection ) ;
303338 let isClickInsideSelection = false ;
304339
305340 if (hasRangeSelection && Number .isFinite (event .clientX ) && Number .isFinite (event .clientY )) {
@@ -310,12 +345,31 @@ const handleRightClick = async (event) => {
310345 }
311346 }
312347
313- if (! isClickInsideSelection) {
348+ const target = event ? .target ;
349+ const tableSurface = target instanceof Element ? target .closest (TABLE_SURFACE_SELECTOR ) : null ;
350+ const tableCandidatePm = target instanceof Element ? target .closest (' [data-pm-start]' ) : null ;
351+ const tableAnchorPos = Number .isFinite (Number (tableCandidatePm? .dataset ? .pmStart ))
352+ ? Number (tableCandidatePm .dataset .pmStart )
353+ : null ;
354+ const selectionIsCell = isCellSelection (editorState? .selection );
355+
356+ if (tableSurface && Number .isFinite (tableAnchorPos) && ! selectionIsCell && ! hasRangeSelection) {
357+ setSelectionNearPos (props .editor , tableAnchorPos, { focus: true });
358+ } else if (! isClickInsideSelection) {
314359 moveCursorToMouseEvent (event , props .editor );
315360 }
316361
317362 try {
318363 const context = await getEditorContext (props .editor , event );
364+ const reseatForTable =
365+ Boolean (tableSurface) &&
366+ context? .isInTable &&
367+ Number .isFinite (context? .pos ) &&
368+ ! isCellSelection (props .editor ? .state ? .selection ) &&
369+ ! hasExpandedSelection (props .editor ? .state ? .selection );
370+ if (reseatForTable) {
371+ setSelectionNearPos (props .editor , context .pos , { focus: true });
372+ }
319373 currentContext .value = context;
320374 sections .value = getItems ({ ... context, trigger: ' click' });
321375 selectedId .value = flattenedItems .value [0 ]? .id || null ;
@@ -339,6 +393,18 @@ const handleRightClick = async (event) => {
339393
340394const executeCommand = async (item ) => {
341395 if (props .editor ) {
396+ const currentPos = currentContext .value ? .pos ;
397+ const shouldReseatTableSelection =
398+ currentContext .value ? .event ? .type === ' contextmenu' &&
399+ currentContext .value ? .isInTable &&
400+ Number .isFinite (currentPos) &&
401+ ! isCellSelection (props .editor ? .state ? .selection ) &&
402+ ! hasExpandedSelection (props .editor ? .state ? .selection );
403+
404+ if (shouldReseatTableSelection) {
405+ setSelectionNearPos (props .editor , currentPos, { focus: true , addToHistory: false });
406+ }
407+
342408 // First call the action if needed on the item
343409 item .action ? await item .action (props .editor , currentContext .value ) : null ;
344410
0 commit comments