@jvs-milkdown/components 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,12 +2,15 @@ import type { Ctx } from '@jvs-milkdown/ctx'
2
2
  import type { Node } from '@jvs-milkdown/prose/model'
3
3
  import type { EditorView } from '@jvs-milkdown/prose/view'
4
4
 
5
+ import { computePosition } from '@floating-ui/dom'
6
+ import { CellSelection } from '@jvs-milkdown/prose/tables'
5
7
  import {
6
8
  defineComponent,
7
9
  ref,
8
10
  type VNodeRef,
9
11
  h,
10
12
  onMounted,
13
+ onBeforeUnmount,
11
14
  type Ref,
12
15
  } from 'vue'
13
16
 
@@ -61,33 +64,54 @@ export const TableBlock = defineComponent<TableBlockProps>({
61
64
  },
62
65
  setup({ view, node, ctx, getPos, config, onMount }) {
63
66
  const contentWrapperRef = ref<HTMLElement>()
67
+ let contentMounted = false
64
68
  const contentWrapperFunctionRef: VNodeRef = (div) => {
65
69
  if (div == null) return
66
70
  if (div instanceof HTMLElement) {
67
71
  contentWrapperRef.value = div
68
- onMount(div)
72
+ if (!contentMounted) {
73
+ onMount(div)
74
+ contentMounted = true
75
+ }
69
76
  } else {
70
77
  contentWrapperRef.value = undefined
71
78
  }
72
79
  }
73
- const colHandleRef = ref<HTMLDivElement>()
74
- const rowHandleRef = ref<HTMLDivElement>()
75
- const xLineHandleRef = ref<HTMLDivElement>()
76
- const yLineHandleRef = ref<HTMLDivElement>()
77
80
  const tableWrapperRef = ref<HTMLDivElement>()
78
81
  const dragPreviewRef = ref<HTMLDivElement>()
79
82
  const hoverIndex = ref<CellIndex>([0, 0])
80
83
  const lineHoverIndex = ref<CellIndex>([-1, -1])
81
84
  const dragInfo = ref<DragInfo>()
82
85
 
86
+ // --- Column resize state ---
87
+ const resizingCol = ref(-1)
88
+ const colWidths = ref<number[]>([])
89
+
90
+ const syncColWidths = () => {
91
+ if (resizingCol.value >= 0) return
92
+ const firstRow = node.value.firstChild
93
+ if (!firstRow) return
94
+ const colCount = firstRow.content.childCount
95
+ const widths: number[] = []
96
+ const hasBounds = colBounds.value.length === colCount
97
+ for (let i = 0; i < colCount; i++) {
98
+ const cell = firstRow.content.child(i)
99
+ const w = cell.attrs.colwidth
100
+ if (Array.isArray(w) && w[0]) {
101
+ widths.push(w[0])
102
+ } else if (hasBounds) {
103
+ widths.push(Math.round(colBounds.value[i]!.width))
104
+ } else {
105
+ widths.push(0)
106
+ }
107
+ }
108
+ colWidths.value = widths
109
+ }
110
+
83
111
  const refs: Refs = {
84
112
  dragPreviewRef,
85
113
  tableWrapperRef,
86
114
  contentWrapperRef,
87
- yLineHandleRef,
88
- xLineHandleRef,
89
- colHandleRef,
90
- rowHandleRef,
91
115
  hoverIndex,
92
116
  lineHoverIndex,
93
117
  dragInfo,
@@ -98,20 +122,270 @@ export const TableBlock = defineComponent<TableBlockProps>({
98
122
  const {
99
123
  onAddRow,
100
124
  onAddCol,
125
+ addRowByIndex,
126
+ addColByIndex,
101
127
  selectCol,
102
128
  selectRow,
103
129
  deleteSelected,
104
130
  onAlign,
131
+ onMergeCells,
132
+ onSplitCell,
105
133
  } = useOperation(refs, ctx, getPos)
106
134
 
135
+ // --- Floating cell toolbar state ---
136
+ const cellToolbarRef = ref<HTMLDivElement>()
137
+ const showCellToolbar = ref(false)
138
+ const canMerge = ref(false)
139
+ const canSplit = ref(false)
140
+
141
+ const updateCellToolbar = () => {
142
+ const { selection } = view.state
143
+ const tablePos = getPos()
144
+ if (tablePos == null) {
145
+ showCellToolbar.value = false
146
+ return
147
+ }
148
+ const tableEnd = tablePos + node.value.nodeSize
149
+ if (selection.from < tablePos || selection.from > tableEnd) {
150
+ showCellToolbar.value = false
151
+ return
152
+ }
153
+
154
+ if (selection instanceof CellSelection) {
155
+ // Compute merge/split availability
156
+ let _cellCount = 0
157
+ let hasMerged = false
158
+ selection.forEachCell((cell) => {
159
+ _cellCount++
160
+ if ((cell.attrs.rowspan ?? 1) > 1 || (cell.attrs.colspan ?? 1) > 1) {
161
+ hasMerged = true
162
+ }
163
+ })
164
+ canMerge.value = _cellCount > 1
165
+ canSplit.value = hasMerged
166
+ } else {
167
+ // TextSelection: only show toolbar for CellSelection-based actions
168
+ showCellToolbar.value = false
169
+ return
170
+ }
171
+
172
+ if (!canMerge.value && !canSplit.value) {
173
+ showCellToolbar.value = false
174
+ return
175
+ }
176
+
177
+ showCellToolbar.value = true
178
+
179
+ // Position toolbar above the first selected cell using floating-ui
180
+ requestAnimationFrame(() => {
181
+ const toolbar = cellToolbarRef.value
182
+ const content = contentWrapperRef.value
183
+ if (!toolbar || !content) return
184
+
185
+ const selectedCells = content.querySelectorAll('.selectedCell')
186
+ let refEl: Element | null =
187
+ selectedCells.length > 0 ? selectedCells[0]! : null
188
+
189
+ if (!refEl && !(view.state.selection instanceof CellSelection)) {
190
+ const { $from } = view.state.selection
191
+ for (let d = $from.depth; d > 0; d--) {
192
+ const node = $from.node(d)
193
+ if (
194
+ node.type.name === 'table_cell' ||
195
+ node.type.name === 'table_header'
196
+ ) {
197
+ const cellPos = $from.before(d)
198
+ const dom = view.nodeDOM(cellPos)
199
+ if (dom instanceof HTMLElement) refEl = dom
200
+ break
201
+ }
202
+ }
203
+ }
204
+
205
+ if (!refEl) return
206
+
207
+ computePosition(refEl, toolbar, { placement: 'top' })
208
+ .then(({ x, y }) => {
209
+ toolbar.style.left = `${x}px`
210
+ toolbar.style.top = `${y}px`
211
+ toolbar.dataset.show = 'true'
212
+ })
213
+ .catch(console.error)
214
+ })
215
+ }
216
+
217
+ const colBounds = ref<{ left: number; width: number }[]>([])
218
+ const rowBounds = ref<{ top: number; height: number }[]>([])
219
+
220
+ let ro: ResizeObserver | null = null
221
+ let mo: MutationObserver | null = null
222
+
223
+ const updateBounds = () => {
224
+ const content = contentWrapperRef.value
225
+ if (!content) return
226
+
227
+ const firstRow = content.querySelector('tr')
228
+ const tableRect = content.getBoundingClientRect()
229
+
230
+ if (firstRow) {
231
+ colBounds.value = Array.from(firstRow.children).map((c) => {
232
+ const rect = c.getBoundingClientRect()
233
+ return { left: rect.left - tableRect.left, width: rect.width }
234
+ })
235
+ }
236
+
237
+ const rows = content.querySelectorAll('tr')
238
+ rowBounds.value = Array.from(rows).map((c) => {
239
+ const rect = c.getBoundingClientRect()
240
+ return { top: rect.top - tableRect.top, height: rect.height }
241
+ })
242
+ syncColWidths()
243
+ }
244
+
245
+ const startResize = (e: PointerEvent, colIndex: number) => {
246
+ if (!view.editable) return
247
+ e.preventDefault()
248
+ e.stopPropagation()
249
+ const startX = e.clientX
250
+ const startWidth = colBounds.value[colIndex]?.width ?? 100
251
+ resizingCol.value = colIndex
252
+
253
+ const onMove = (ev: PointerEvent) => {
254
+ const delta = ev.clientX - startX
255
+ const newWidth = Math.max(50, startWidth + delta)
256
+ colWidths.value = colWidths.value.map((w, i) =>
257
+ i === colIndex ? newWidth : w
258
+ )
259
+ }
260
+
261
+ const onUp = (ev: PointerEvent) => {
262
+ document.removeEventListener('pointermove', onMove)
263
+ document.removeEventListener('pointerup', onUp)
264
+
265
+ const delta = ev.clientX - startX
266
+ const newWidth = Math.max(50, startWidth + delta)
267
+
268
+ // Commit via ProseMirror transaction
269
+ const tablePos = getPos()
270
+ if (tablePos == null) {
271
+ resizingCol.value = -1
272
+ return
273
+ }
274
+ const tableNode = node.value
275
+ let tr = view.state.tr
276
+ let pos = tablePos + 1
277
+
278
+ tableNode.forEach((row) => {
279
+ let cellIdx = 0
280
+ row.forEach((cell, _offset, cellNodePos) => {
281
+ if (cellIdx === colIndex) {
282
+ const absPos = tablePos + 1 + cellNodePos
283
+ const colwidth = [Math.round(newWidth)]
284
+ tr = tr.setNodeMarkup(absPos, undefined, {
285
+ ...cell.attrs,
286
+ colwidth,
287
+ })
288
+ }
289
+ cellIdx++
290
+ })
291
+ pos += row.nodeSize
292
+ })
293
+
294
+ resizingCol.value = -1
295
+ if (tr.docChanged) view.dispatch(tr)
296
+ }
297
+
298
+ document.addEventListener('pointermove', onMove)
299
+ document.addEventListener('pointerup', onUp)
300
+ }
301
+
302
+ const activeColIndex = ref(-1)
303
+ const activeRowIndex = ref(-1)
304
+
305
+ // Listen for ProseMirror state updates
306
+ const dispatchListener = () => {
307
+ updateCellToolbar()
308
+
309
+ // Update active handler button groups based on selection
310
+ const { selection } = view.state
311
+ if (selection instanceof CellSelection) {
312
+ if (selection.isColSelection()) {
313
+ const { $head } = selection
314
+ activeColIndex.value = $head.index($head.depth - 1)
315
+ activeRowIndex.value = -1
316
+ } else if (selection.isRowSelection()) {
317
+ activeColIndex.value = -1
318
+ // Simple approach for row index: derive from hoverIndex which is updated by pointer? Or compute.
319
+ // recoveryStateBetweenUpdate updates hoverIndex.
320
+ } else {
321
+ activeColIndex.value = -1
322
+ activeRowIndex.value = -1
323
+ }
324
+ } else {
325
+ activeColIndex.value = -1
326
+ activeRowIndex.value = -1
327
+ }
328
+ }
329
+
107
330
  onMounted(() => {
108
331
  requestAnimationFrame(() => {
109
- // This is a wordaround to keep the popover open when click the select col/row button
110
332
  if (view.editable) recoveryStateBetweenUpdate(refs, view, node.value)
333
+ syncColWidths()
334
+ })
335
+ view.dom.addEventListener('keyup', dispatchListener)
336
+ view.dom.addEventListener('pointerup', dispatchListener)
337
+ updateCellToolbar()
338
+
339
+ ro = new ResizeObserver(() => {
340
+ requestAnimationFrame(updateBounds)
111
341
  })
342
+ mo = new MutationObserver((mutations) => {
343
+ let shouldUpdate = false
344
+ for (const mut of mutations) {
345
+ if (mut.type === 'childList') {
346
+ for (const node of mut.addedNodes) {
347
+ if (
348
+ node instanceof HTMLElement &&
349
+ ['TR', 'TD', 'TH', 'TBODY'].includes(node.nodeName)
350
+ )
351
+ shouldUpdate = true
352
+ }
353
+ for (const node of mut.removedNodes) {
354
+ if (
355
+ node instanceof HTMLElement &&
356
+ ['TR', 'TD', 'TH', 'TBODY'].includes(node.nodeName)
357
+ )
358
+ shouldUpdate = true
359
+ }
360
+ } else if (mut.type === 'attributes') {
361
+ shouldUpdate = true
362
+ }
363
+ }
364
+ if (shouldUpdate) {
365
+ requestAnimationFrame(updateBounds)
366
+ }
367
+ })
368
+
369
+ if (contentWrapperRef.value) {
370
+ ro.observe(contentWrapperRef.value)
371
+ mo.observe(contentWrapperRef.value, {
372
+ childList: true,
373
+ subtree: true,
374
+ attributes: true,
375
+ })
376
+ }
377
+ })
378
+
379
+ onBeforeUnmount(() => {
380
+ view.dom.removeEventListener('keyup', dispatchListener)
381
+ view.dom.removeEventListener('pointerup', dispatchListener)
382
+ if (ro) ro.disconnect()
383
+ if (mo) mo.disconnect()
112
384
  })
113
385
 
114
386
  return () => {
387
+ updateCellToolbar()
388
+
115
389
  return (
116
390
  <div
117
391
  onDragstart={(e) => e.preventDefault()}
@@ -119,63 +393,204 @@ export const TableBlock = defineComponent<TableBlockProps>({
119
393
  onDragleave={(e) => e.preventDefault()}
120
394
  onPointermove={pointerMove}
121
395
  onPointerleave={pointerLeave}
396
+ class="milkdown-table-wrapper-outer"
122
397
  >
398
+ {/* Floating cell toolbar (merge/split) */}
123
399
  <div
124
- data-show="false"
400
+ ref={cellToolbarRef}
401
+ data-show={showCellToolbar.value ? 'true' : 'false'}
402
+ class="cell-toolbar"
125
403
  contenteditable="false"
126
- draggable="true"
127
- data-role="col-drag-handle"
128
- class="handle cell-handle"
129
- onDragstart={dragCol}
130
- onClick={selectCol}
131
404
  onPointerdown={(e: PointerEvent) => e.stopPropagation()}
132
- onPointermove={(e: PointerEvent) => e.stopPropagation()}
133
- ref={colHandleRef}
134
405
  >
135
- <Icon icon={config.renderButton('col_drag_handle')} />
136
- <div
137
- data-show="false"
138
- class="button-group"
139
- onPointermove={(e: PointerEvent) => e.stopPropagation()}
140
- >
141
- <button type="button" onPointerdown={onAlign('left')}>
142
- <Icon icon={config.renderButton('align_col_left')} />
406
+ {canMerge.value && (
407
+ <button
408
+ type="button"
409
+ class="cell-toolbar-btn"
410
+ onPointerdown={onMergeCells}
411
+ >
412
+ <Icon icon={config.renderButton('merge_cells')} />
143
413
  </button>
144
- <button type="button" onPointerdown={onAlign('center')}>
145
- <Icon icon={config.renderButton('align_col_center')} />
414
+ )}
415
+ {canSplit.value && (
416
+ <button
417
+ type="button"
418
+ class="cell-toolbar-btn"
419
+ onPointerdown={onSplitCell}
420
+ >
421
+ <Icon icon={config.renderButton('split_cell')} />
146
422
  </button>
147
- <button type="button" onPointerdown={onAlign('right')}>
148
- <Icon icon={config.renderButton('align_col_right')} />
149
- </button>
150
- <button type="button" onPointerdown={deleteSelected}>
151
- <Icon icon={config.renderButton('delete_col')} />
152
- </button>
153
- </div>
154
- </div>
155
- <div
156
- data-show="false"
157
- contenteditable="false"
158
- draggable="true"
159
- data-role="row-drag-handle"
160
- class="handle cell-handle"
161
- onDragstart={dragRow}
162
- onClick={selectRow}
163
- onPointerdown={(e: PointerEvent) => e.stopPropagation()}
164
- onPointermove={(e: PointerEvent) => e.stopPropagation()}
165
- ref={rowHandleRef}
166
- >
167
- <Icon icon={config.renderButton('row_drag_handle')} />
168
- <div
169
- data-show="false"
170
- class="button-group"
171
- onPointermove={(e: PointerEvent) => e.stopPropagation()}
172
- >
173
- <button type="button" onPointerdown={deleteSelected}>
174
- <Icon icon={config.renderButton('delete_row')} />
175
- </button>
176
- </div>
423
+ )}
177
424
  </div>
425
+
178
426
  <div class="table-wrapper" ref={tableWrapperRef}>
427
+ {/* Fixed Col Drag Handles */}
428
+ <div contenteditable="false" class="fixed-handles-col">
429
+ {colBounds.value.map((bound, i) => (
430
+ <div
431
+ key={`col-${i}`}
432
+ class="handle cell-handle fixed"
433
+ data-role="col-drag-handle"
434
+ draggable="true"
435
+ style={{ left: `${bound.left}px`, width: `${bound.width}px` }}
436
+ onDragstart={(e) => {
437
+ hoverIndex.value = [0, i]
438
+ dragCol(e)
439
+ }}
440
+ onClick={(e) => {
441
+ hoverIndex.value = [0, i]
442
+ selectCol(e)
443
+ activeColIndex.value = i
444
+ activeRowIndex.value = -1
445
+ }}
446
+ onPointerdown={(e: PointerEvent) => e.stopPropagation()}
447
+ onPointermove={(e: PointerEvent) => e.stopPropagation()}
448
+ >
449
+ <div
450
+ class="button-group"
451
+ data-show={activeColIndex.value === i ? 'true' : 'false'}
452
+ onPointermove={(e: PointerEvent) => e.stopPropagation()}
453
+ >
454
+ <button
455
+ type="button"
456
+ onPointerdown={(e) => {
457
+ hoverIndex.value = [0, i]
458
+ onAlign('left')(e)
459
+ }}
460
+ >
461
+ <Icon icon={config.renderButton('align_col_left')} />
462
+ </button>
463
+ <button
464
+ type="button"
465
+ onPointerdown={(e) => {
466
+ hoverIndex.value = [0, i]
467
+ onAlign('center')(e)
468
+ }}
469
+ >
470
+ <Icon icon={config.renderButton('align_col_center')} />
471
+ </button>
472
+ <button
473
+ type="button"
474
+ onPointerdown={(e) => {
475
+ hoverIndex.value = [0, i]
476
+ onAlign('right')(e)
477
+ }}
478
+ >
479
+ <Icon icon={config.renderButton('align_col_right')} />
480
+ </button>
481
+ <button
482
+ type="button"
483
+ onPointerdown={(e) => {
484
+ hoverIndex.value = [0, i]
485
+ deleteSelected(e)
486
+ }}
487
+ >
488
+ <Icon icon={config.renderButton('delete_col')} />
489
+ </button>
490
+ </div>
491
+ </div>
492
+ ))}
493
+ </div>
494
+
495
+ {/* Add Col Dots */}
496
+ <div contenteditable="false" class="add-dots-col">
497
+ {[
498
+ ...colBounds.value.map((b) => b.left),
499
+ colBounds.value.length
500
+ ? colBounds.value[colBounds.value.length - 1].left +
501
+ colBounds.value[colBounds.value.length - 1].width
502
+ : 0,
503
+ ].map((left, i) => (
504
+ <div
505
+ key={`add-col-${i}`}
506
+ class="add-dot"
507
+ style={{ left: `${left}px` }}
508
+ onClick={() => addColByIndex(i)}
509
+ onPointerdown={(e: PointerEvent) => e.stopPropagation()}
510
+ >
511
+ <Icon icon={config.renderButton('add_col')} />
512
+ </div>
513
+ ))}
514
+ </div>
515
+
516
+ {/* Column Resize Handles */}
517
+ <div contenteditable="false" class="resize-handles-col">
518
+ {colBounds.value.map((bound, i) => (
519
+ <div
520
+ key={`resize-${i}`}
521
+ class={[
522
+ 'col-resize-handle',
523
+ resizingCol.value === i ? 'active' : '',
524
+ ].join(' ')}
525
+ style={{
526
+ left: `${bound.left + bound.width - 3}px`,
527
+ }}
528
+ onPointerdown={(e: PointerEvent) => startResize(e, i)}
529
+ />
530
+ ))}
531
+ </div>
532
+
533
+ {/* Fixed Row Drag Handles */}
534
+ <div contenteditable="false" class="fixed-handles-row">
535
+ {rowBounds.value.map((bound, i) => (
536
+ <div
537
+ key={`row-${i}`}
538
+ class="handle cell-handle fixed"
539
+ data-role="row-drag-handle"
540
+ draggable="true"
541
+ style={{ top: `${bound.top}px`, height: `${bound.height}px` }}
542
+ onDragstart={(e) => {
543
+ hoverIndex.value = [i, 0]
544
+ dragRow(e)
545
+ }}
546
+ onClick={(e) => {
547
+ hoverIndex.value = [i, 0]
548
+ selectRow(e)
549
+ activeRowIndex.value = i
550
+ activeColIndex.value = -1
551
+ }}
552
+ onPointerdown={(e: PointerEvent) => e.stopPropagation()}
553
+ >
554
+ <div
555
+ class="button-group"
556
+ data-show={activeRowIndex.value === i ? 'true' : 'false'}
557
+ onPointermove={(e: PointerEvent) => e.stopPropagation()}
558
+ >
559
+ <button
560
+ type="button"
561
+ onPointerdown={(e) => {
562
+ hoverIndex.value = [i, 0]
563
+ deleteSelected(e)
564
+ }}
565
+ >
566
+ <Icon icon={config.renderButton('delete_row')} />
567
+ </button>
568
+ </div>
569
+ </div>
570
+ ))}
571
+ </div>
572
+
573
+ {/* Add Row Dots */}
574
+ <div contenteditable="false" class="add-dots-row">
575
+ {[
576
+ ...rowBounds.value.map((b) => b.top),
577
+ rowBounds.value.length
578
+ ? rowBounds.value[rowBounds.value.length - 1].top +
579
+ rowBounds.value[rowBounds.value.length - 1].height
580
+ : 0,
581
+ ].map((top, i) => (
582
+ <div
583
+ key={`add-row-${i}`}
584
+ class="add-dot"
585
+ style={{ top: `${top}px` }}
586
+ onClick={() => addRowByIndex(i)}
587
+ onPointerdown={(e: PointerEvent) => e.stopPropagation()}
588
+ >
589
+ <Icon icon={config.renderButton('add_row')} />
590
+ </div>
591
+ ))}
592
+ </div>
593
+
179
594
  <div
180
595
  data-show="false"
181
596
  class="drag-preview"
@@ -186,31 +601,17 @@ export const TableBlock = defineComponent<TableBlockProps>({
186
601
  <tbody></tbody>
187
602
  </table>
188
603
  </div>
189
- <div
190
- data-show="false"
191
- contenteditable="false"
192
- data-display-type="tool"
193
- data-role="x-line-drag-handle"
194
- class="handle line-handle"
195
- ref={xLineHandleRef}
196
- >
197
- <button type="button" onClick={onAddRow} class="add-button">
198
- <Icon icon={config.renderButton('add_row')} />
199
- </button>
200
- </div>
201
- <div
202
- data-show="false"
203
- contenteditable="false"
204
- data-display-type="tool"
205
- data-role="y-line-drag-handle"
206
- class="handle line-handle"
207
- ref={yLineHandleRef}
208
- >
209
- <button type="button" onClick={onAddCol} class="add-button">
210
- <Icon icon={config.renderButton('add_col')} />
211
- </button>
212
- </div>
213
- <table ref={contentWrapperFunctionRef} class="children"></table>
604
+
605
+ <table ref={contentWrapperFunctionRef} class="children">
606
+ <colgroup>
607
+ {colWidths.value.map((w, i) => (
608
+ <col
609
+ key={i}
610
+ style={w > 0 ? { width: `${w}px` } : undefined}
611
+ />
612
+ ))}
613
+ </colgroup>
614
+ </table>
214
615
  </div>
215
616
  </div>
216
617
  )
@@ -16,10 +16,6 @@ import {
16
16
  createDragRowHandler,
17
17
  } from '../dnd/create-drag-handler'
18
18
  import { createDragOverHandler } from '../dnd/drag-over-handler'
19
- import {
20
- computeColHandlePositionByIndex,
21
- computeRowHandlePositionByIndex,
22
- } from './utils'
23
19
 
24
20
  export function useDragHandlers(
25
21
  refs: Refs,
@@ -56,10 +52,6 @@ export function useDragHandlers(
56
52
  if (!info) return
57
53
  if (!ctx) return
58
54
  if (preview.dataset.show === 'false') return
59
- const colHandle = refs.colHandleRef.value
60
- if (!colHandle) return
61
- const rowHandle = refs.rowHandleRef.value
62
- if (!rowHandle) return
63
55
 
64
56
  yHandle.dataset.show = 'false'
65
57
  xHandle.dataset.show = 'false'
@@ -79,10 +71,7 @@ export function useDragHandlers(
79
71
  })
80
72
  commands.call(moveColCommand.key, payload)
81
73
  const index: CellIndex = [0, info.endIndex]
82
- computeColHandlePositionByIndex({
83
- refs,
84
- index,
85
- })
74
+ refs.hoverIndex.value = index
86
75
  } else {
87
76
  commands.call(selectRowCommand.key, {
88
77
  pos: payload.pos,
@@ -90,10 +79,7 @@ export function useDragHandlers(
90
79
  })
91
80
  commands.call(moveRowCommand.key, payload)
92
81
  const index: CellIndex = [info.endIndex, 0]
93
- computeRowHandlePositionByIndex({
94
- refs,
95
- index,
96
- })
82
+ refs.hoverIndex.value = index
97
83
  }
98
84
 
99
85
  requestAnimationFrame(() => {