vue2-excel-grid 2.6.1 → 2.6.3

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue2-excel-grid",
3
- "version": "2.6.1",
3
+ "version": "2.6.3",
4
4
  "description": "Excel-style grid component for Vue 2.6.14 with virtual scrolling",
5
5
  "license": "MIT",
6
6
  "author": "Fozilbek Raimberdiyev",
@@ -993,6 +993,9 @@ const ROW_HEADER_WIDTH = 50
993
993
  const DEFAULT_COL_WIDTH = 100
994
994
  const OUTLINE_GUTTER = 20
995
995
  const FIT_COLUMNS_MIN_WIDTH = 40
996
+ const ROW_LIST_EDGE_PAD = 8 // birinchi/oxirgi qator bilan tepa/pastki border orasidagi bo'sh joy (px)
997
+ const FILL_DRAG_EDGE_ZONE = 24 // px from .eg-scroll-body's edge that triggers continuous auto-scroll while fill-dragging
998
+ const FILL_DRAG_MAX_SPEED = 18 // px/frame, at the very edge (scales down to 0 at the zone's outer boundary)
996
999
 
997
1000
  // Classifies a col.width spec so resolveColWidth() knows how to turn it into a
998
1001
  // concrete px number. Plain numbers/px strings resolve instantly with no DOM
@@ -1873,7 +1876,7 @@ const ExcelGridComponent = {
1873
1876
  // findVisibleRange() uses binary search against this cached array → O(log n) per scroll.
1874
1877
  // Invalidated only when row count, custom heights, or hidden rows change.
1875
1878
  cumulativeHeights() {
1876
- return buildCumulativeHeights(this.totalRows, this._rowH, this.rowHeights, this.hiddenRowSet)
1879
+ return buildCumulativeHeights(this.totalRows, this._rowH, this.rowHeights, this.hiddenRowSet, ROW_LIST_EDGE_PAD, ROW_LIST_EDGE_PAD)
1877
1880
  },
1878
1881
 
1879
1882
  // height prop omitted → fit header + filter row + all (visible) rows + footer exactly.
@@ -2631,6 +2634,14 @@ const ExcelGridComponent = {
2631
2634
  this._dragScrollRAF = null
2632
2635
  this._dragCleanupTimer = null
2633
2636
 
2637
+ // Fill-handle drag edge auto-scroll (see _updateFillDragAutoScroll) — same
2638
+ // idle-when-0 convention as _dragScrollV/_dragScrollRAF above, just for
2639
+ // both axes since a fill can extend down OR right.
2640
+ this._fillDragScrollV = 0
2641
+ this._fillDragScrollH = 0
2642
+ this._fillDragScrollRAF = null
2643
+ this._fillDragLastEvent = null
2644
+
2634
2645
  // localSyncKey — the last `data` reference a version was actually saved
2635
2646
  // for. Initialized to the current (mount-time) value so an untouched grid
2636
2647
  // that's merely tab-switched away from doesn't spam a "nothing happened"
@@ -2715,6 +2726,7 @@ const ExcelGridComponent = {
2715
2726
  clearTimeout(this._widthSyncChainResetTimer)
2716
2727
  clearTimeout(this._bufferWriteTimer)
2717
2728
  if (this._dragScrollRAF) cancelAnimationFrame(this._dragScrollRAF)
2729
+ if (this._fillDragScrollRAF) cancelAnimationFrame(this._fillDragScrollRAF)
2718
2730
  document.removeEventListener('mousemove', this.onGlobalMouseMove)
2719
2731
  document.removeEventListener('mouseup', this.onGlobalMouseUp)
2720
2732
  document.removeEventListener('keydown', this.onGlobalKeyDown)
@@ -3449,7 +3461,7 @@ const ExcelGridComponent = {
3449
3461
  },
3450
3462
 
3451
3463
  getRowGroupBtnStyle(group) {
3452
- const top = getRowTop(group.startIndex, this._rowH, this.rowHeights) - this.scrollTop
3464
+ const top = getRowTop(group.startIndex, this._rowH, this.rowHeights, ROW_LIST_EDGE_PAD) - this.scrollTop
3453
3465
  return {
3454
3466
  position: 'absolute',
3455
3467
  top: top + 'px',
@@ -4088,7 +4100,7 @@ const ExcelGridComponent = {
4088
4100
  scrollToCell(ri, ci) {
4089
4101
  const scrollBody = this.$refs.scrollBody
4090
4102
  if (!scrollBody) return
4091
- const rowTop = getRowTop(ri, this._rowH, this.rowHeights)
4103
+ const rowTop = getRowTop(ri, this._rowH, this.rowHeights, ROW_LIST_EDGE_PAD)
4092
4104
  const rowBottom = rowTop + this.getRowH(ri)
4093
4105
 
4094
4106
  if (rowTop < scrollBody.scrollTop) scrollBody.scrollTop = rowTop
@@ -5105,9 +5117,14 @@ const ExcelGridComponent = {
5105
5117
  this.isMouseDown = false
5106
5118
  },
5107
5119
 
5108
- handleFillDragMove(e) {
5120
+ // Resolves which (row, col) the mouse is currently over, given the
5121
+ // scroll body's CURRENT scrollTop/scrollLeft — called both directly from
5122
+ // mousemove and repeatedly from the edge-auto-scroll rAF loop below (as
5123
+ // scrollTop changes on its own, the row under a STATIONARY cursor changes
5124
+ // with it).
5125
+ _fillDragTargetFromEvent(e) {
5109
5126
  const scrollBody = this.$refs.scrollBody
5110
- if (!scrollBody) return
5127
+ if (!scrollBody) return null
5111
5128
  const rect = scrollBody.getBoundingClientRect()
5112
5129
  const relY = e.clientY - rect.top + scrollBody.scrollTop
5113
5130
  const relX = e.clientX - rect.left + scrollBody.scrollLeft
@@ -5132,12 +5149,78 @@ const ExcelGridComponent = {
5132
5149
  if (relX < left) { col = i; break }
5133
5150
  col = i
5134
5151
  }
5152
+ return { row, col }
5153
+ },
5154
+
5155
+ handleFillDragMove(e) {
5156
+ this._fillDragLastEvent = e
5157
+ const target = this._fillDragTargetFromEvent(e)
5158
+ if (!target) return
5159
+ this.fillDrag.currentRow = target.row
5160
+ this.fillDrag.currentCol = target.col
5161
+ // Covers the common case of a single big mousemove jump landing the
5162
+ // cursor (and its computed target row/col) outside the visible window.
5163
+ this.scrollToCell(target.row, target.col)
5164
+ // Covers the — far more common in practice — case of the cursor
5165
+ // PINNED at the container's edge (it usually can't travel further,
5166
+ // since the grid typically fills its host layout down to that edge):
5167
+ // keep scrolling for as long as it stays there. Same rAF/edge-zone
5168
+ // pattern as _updateDragAutoScroll (column-drag reordering) below.
5169
+ this._updateFillDragAutoScroll(e.clientX, e.clientY)
5170
+ },
5171
+
5172
+ // Edge auto-scroll for fill-handle dragging — vertical AND horizontal
5173
+ // (column-drag's _updateDragAutoScroll is horizontal-only). Speed scales
5174
+ // with how deep into the 24px edge zone the cursor sits.
5175
+ _updateFillDragAutoScroll(clientX, clientY) {
5176
+ const sb = this.$refs.scrollBody
5177
+ if (!sb) { this._fillDragScrollV = 0; this._fillDragScrollH = 0; return }
5178
+ const rect = sb.getBoundingClientRect()
5179
+ const ZONE = FILL_DRAG_EDGE_ZONE
5180
+
5181
+ let v = 0
5182
+ if (clientY < rect.top + ZONE) v = -Math.ceil((rect.top + ZONE - clientY) / 4)
5183
+ else if (clientY > rect.bottom - ZONE) v = Math.ceil((clientY - (rect.bottom - ZONE)) / 4)
5184
+ this._fillDragScrollV = Math.max(-FILL_DRAG_MAX_SPEED, Math.min(FILL_DRAG_MAX_SPEED, v))
5185
+
5186
+ let h = 0
5187
+ if (clientX < rect.left + ZONE) h = -Math.ceil((rect.left + ZONE - clientX) / 4)
5188
+ else if (clientX > rect.right - ZONE) h = Math.ceil((clientX - (rect.right - ZONE)) / 4)
5189
+ this._fillDragScrollH = Math.max(-FILL_DRAG_MAX_SPEED, Math.min(FILL_DRAG_MAX_SPEED, h))
5190
+
5191
+ if ((this._fillDragScrollV !== 0 || this._fillDragScrollH !== 0) && !this._fillDragScrollRAF) {
5192
+ const step = () => {
5193
+ this._fillDragScrollRAF = null
5194
+ if (!this.fillDrag.active) return
5195
+ const body = this.$refs.scrollBody
5196
+ if (body) {
5197
+ if (this._fillDragScrollV) body.scrollTop = Math.max(0, Math.min(body.scrollHeight - body.clientHeight, body.scrollTop + this._fillDragScrollV))
5198
+ if (this._fillDragScrollH) body.scrollLeft = Math.max(0, Math.min(body.scrollWidth - body.clientWidth, body.scrollLeft + this._fillDragScrollH))
5199
+ // The cursor itself hasn't moved, but the content under it has —
5200
+ // re-derive the fill target at the new scroll position.
5201
+ if (this._fillDragLastEvent) {
5202
+ const target = this._fillDragTargetFromEvent(this._fillDragLastEvent)
5203
+ if (target) { this.fillDrag.currentRow = target.row; this.fillDrag.currentCol = target.col }
5204
+ }
5205
+ }
5206
+ if (this._fillDragScrollV !== 0 || this._fillDragScrollH !== 0) this._fillDragScrollRAF = requestAnimationFrame(step)
5207
+ }
5208
+ this._fillDragScrollRAF = requestAnimationFrame(step)
5209
+ }
5210
+ },
5135
5211
 
5136
- this.fillDrag.currentRow = row
5137
- this.fillDrag.currentCol = col
5212
+ _stopFillDragAutoScroll() {
5213
+ this._fillDragScrollV = 0
5214
+ this._fillDragScrollH = 0
5215
+ this._fillDragLastEvent = null
5216
+ if (this._fillDragScrollRAF) {
5217
+ cancelAnimationFrame(this._fillDragScrollRAF)
5218
+ this._fillDragScrollRAF = null
5219
+ }
5138
5220
  },
5139
5221
 
5140
5222
  async commitFillDrag() {
5223
+ this._stopFillDragAutoScroll()
5141
5224
  if (this.internalLocked) { this.fillDrag.active = false; return }
5142
5225
  const src = this.fillDrag.sourceRange
5143
5226
  if (!src) { this.fillDrag.active = false; return }
@@ -75,15 +75,18 @@ export function calcVisibleRows(scrollTop, containerHeight, totalRows, rowHeight
75
75
  * @param {number} defaultHeight
76
76
  * @param {Object} rowHeightsMap - sparse { index: px } overrides
77
77
  * @param {Set} hiddenSet - Set of hidden row indices (height = 0)
78
+ * @param {number} padTop - extra px baked into cum[0] (and every entry after it)
79
+ * @param {number} padBottom - extra px baked into the final (total-height) entry only
78
80
  * @returns {number[]} length = totalRows + 1
79
81
  */
80
- export function buildCumulativeHeights(totalRows, defaultHeight, rowHeightsMap = {}, hiddenSet = new Set()) {
82
+ export function buildCumulativeHeights(totalRows, defaultHeight, rowHeightsMap = {}, hiddenSet = new Set(), padTop = 0, padBottom = 0) {
81
83
  const cum = new Array(totalRows + 1)
82
- cum[0] = 0
84
+ cum[0] = padTop
83
85
  for (let i = 0; i < totalRows; i++) {
84
86
  const h = hiddenSet.has(i) ? 0 : (rowHeightsMap[i] !== undefined ? rowHeightsMap[i] : defaultHeight)
85
87
  cum[i + 1] = cum[i] + h
86
88
  }
89
+ cum[totalRows] += padBottom
87
90
  return cum
88
91
  }
89
92
 
@@ -131,9 +134,10 @@ export function findVisibleRange(scrollTop, containerHeight, totalRows, cumulati
131
134
 
132
135
  /**
133
136
  * Get the top offset of a row
137
+ * @param {number} padTop - extra px offset added on top (see buildCumulativeHeights)
134
138
  */
135
- export function getRowTop(rowIndex, rowHeight, rowHeights = []) {
136
- let top = 0
139
+ export function getRowTop(rowIndex, rowHeight, rowHeights = [], padTop = 0) {
140
+ let top = padTop
137
141
  for (let i = 0; i < rowIndex; i++) {
138
142
  top += rowHeights[i] !== undefined ? rowHeights[i] : rowHeight
139
143
  }