vue2-excel-grid 2.5.0 → 2.6.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.
- package/dist/vue2-excel-grid.esm.js +450 -351
- package/dist/vue2-excel-grid.umd.js +2 -2
- package/package.json +1 -1
- package/src/components/ExcelGrid.vue +114 -18
package/package.json
CHANGED
|
@@ -992,6 +992,7 @@ const SIZE_CONFIG = {
|
|
|
992
992
|
const ROW_HEADER_WIDTH = 50
|
|
993
993
|
const DEFAULT_COL_WIDTH = 100
|
|
994
994
|
const OUTLINE_GUTTER = 20
|
|
995
|
+
const FIT_COLUMNS_MIN_WIDTH = 40
|
|
995
996
|
|
|
996
997
|
// Classifies a col.width spec so resolveColWidth() knows how to turn it into a
|
|
997
998
|
// concrete px number. Plain numbers/px strings resolve instantly with no DOM
|
|
@@ -1257,6 +1258,29 @@ const ExcelGridComponent = {
|
|
|
1257
1258
|
/** Auto-fit all column widths to content (same as double-clicking each resize handle). Re-applies on data/columns change. */
|
|
1258
1259
|
autoWidth: { type: Boolean, default: false },
|
|
1259
1260
|
|
|
1261
|
+
/**
|
|
1262
|
+
* Forces every visible leaf column to fit within a single viewport —
|
|
1263
|
+
* no horizontal scroll. Column widths are still resolved (`col.width`,
|
|
1264
|
+
* `%`/`px`/other CSS lengths, `DEFAULT_COL_WIDTH` when omitted) but only
|
|
1265
|
+
* as RELATIVE WEIGHTS: all resolved widths are scaled by one shared
|
|
1266
|
+
* factor so their sum exactly fills the available width, keeping each
|
|
1267
|
+
* column's proportion to the others. Each column still gets at least
|
|
1268
|
+
* `40px` — if there are enough columns that even that minimum doesn't
|
|
1269
|
+
* fit, horizontal scroll returns for that (rare) case rather than
|
|
1270
|
+
* shrinking columns illegibly thin.
|
|
1271
|
+
*
|
|
1272
|
+
* Highest-priority width control: overrides `col.width` as an absolute
|
|
1273
|
+
* value, `autoWidth`, manual column resize (drag handle — disabled
|
|
1274
|
+
* while this is on), and double-click auto-fit. Pinned columns count
|
|
1275
|
+
* toward the fit too — the goal is the whole row fitting, regardless
|
|
1276
|
+
* of pin state.
|
|
1277
|
+
* @type {Boolean}
|
|
1278
|
+
* @default false
|
|
1279
|
+
* @example
|
|
1280
|
+
* <excel-grid :columns="columns" v-model="data" fit-columns />
|
|
1281
|
+
*/
|
|
1282
|
+
fitColumns: { type: Boolean, default: false },
|
|
1283
|
+
|
|
1260
1284
|
/**
|
|
1261
1285
|
* Allow columns to be reordered by dragging their headers.
|
|
1262
1286
|
* On drop, emits 'update:columns' (compatible with .sync) and 'column-reorder'.
|
|
@@ -2409,6 +2433,26 @@ const ExcelGridComponent = {
|
|
|
2409
2433
|
if (v) this._applyAutoWidth()
|
|
2410
2434
|
},
|
|
2411
2435
|
|
|
2436
|
+
fitColumns(v) {
|
|
2437
|
+
if (v) {
|
|
2438
|
+
this._applyFitColumns()
|
|
2439
|
+
} else {
|
|
2440
|
+
// Back to normal per-column resolution (same as the columns
|
|
2441
|
+
// watcher's non-fit branch, without keyToWidth — fitColumns already
|
|
2442
|
+
// discarded any remembered manual-resize widths when it turned on).
|
|
2443
|
+
const newColWidths = {}
|
|
2444
|
+
const newRelativeSpecs = {}
|
|
2445
|
+
this.leafCols.forEach(col => {
|
|
2446
|
+
newColWidths[col._flatIndex] = this.resolveColWidth(col.width, this._relativeWidthContainer)
|
|
2447
|
+
const parsed = parseColWidthSpec(col.width)
|
|
2448
|
+
if (parsed.type !== 'px') newRelativeSpecs[col._flatIndex] = col.width
|
|
2449
|
+
})
|
|
2450
|
+
this.colWidths = newColWidths
|
|
2451
|
+
this.relativeColSpecs = newRelativeSpecs
|
|
2452
|
+
this._applyAutoWidth()
|
|
2453
|
+
}
|
|
2454
|
+
},
|
|
2455
|
+
|
|
2412
2456
|
columns: {
|
|
2413
2457
|
immediate: true,
|
|
2414
2458
|
handler(cols) {
|
|
@@ -2431,21 +2475,30 @@ const ExcelGridComponent = {
|
|
|
2431
2475
|
this.headerRows = buildHeaderRows(cols, this.headerDepth)
|
|
2432
2476
|
this._maskCache = {}
|
|
2433
2477
|
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2478
|
+
if (this.fitColumns) {
|
|
2479
|
+
// fitColumns is the highest-priority width control — it overrides
|
|
2480
|
+
// even remembered manual-resize widths (keyToWidth above), so it
|
|
2481
|
+
// deliberately does NOT participate in that preservation logic.
|
|
2482
|
+
this.colWidths = {}
|
|
2483
|
+
this.relativeColSpecs = {}
|
|
2484
|
+
this._applyFitColumns()
|
|
2485
|
+
} else {
|
|
2486
|
+
// Rebuild colWidths by new flat index, using col.key to look up saved widths
|
|
2487
|
+
const newColWidths = {}
|
|
2488
|
+
const newRelativeSpecs = {}
|
|
2489
|
+
this.leafCols.forEach(col => {
|
|
2490
|
+
if (keyToWidth[col.key] !== undefined) {
|
|
2491
|
+
newColWidths[col._flatIndex] = keyToWidth[col.key]
|
|
2492
|
+
if (keyToSpec[col.key] !== undefined) newRelativeSpecs[col._flatIndex] = keyToSpec[col.key]
|
|
2493
|
+
} else {
|
|
2494
|
+
newColWidths[col._flatIndex] = this.resolveColWidth(col.width, this._relativeWidthContainer)
|
|
2495
|
+
const parsed = parseColWidthSpec(col.width)
|
|
2496
|
+
if (parsed.type !== 'px') newRelativeSpecs[col._flatIndex] = col.width
|
|
2497
|
+
}
|
|
2498
|
+
})
|
|
2499
|
+
this.colWidths = newColWidths
|
|
2500
|
+
this.relativeColSpecs = newRelativeSpecs
|
|
2501
|
+
}
|
|
2449
2502
|
|
|
2450
2503
|
this.computeColumnTotals()
|
|
2451
2504
|
this._recomputeRowFilters()
|
|
@@ -2799,7 +2852,8 @@ const ExcelGridComponent = {
|
|
|
2799
2852
|
const pw = this.$el.parentElement.clientWidth
|
|
2800
2853
|
if (pw !== this.hostContainerWidth && this._widthSyncChainOk()) {
|
|
2801
2854
|
this.hostContainerWidth = pw
|
|
2802
|
-
this.
|
|
2855
|
+
if (this.fitColumns) this._applyFitColumns()
|
|
2856
|
+
else this._resolveRelativeColWidths()
|
|
2803
2857
|
}
|
|
2804
2858
|
}
|
|
2805
2859
|
const sbw = el.offsetWidth - el.clientWidth
|
|
@@ -4378,6 +4432,10 @@ const ExcelGridComponent = {
|
|
|
4378
4432
|
|
|
4379
4433
|
_treeFindLabel(nodes, keys, value) {
|
|
4380
4434
|
for (const node of (nodes || [])) {
|
|
4435
|
+
// A malformed col.options (e.g. a host array with a hole/undefined entry,
|
|
4436
|
+
// often from an unguarded Array.prototype.find() result spread back in)
|
|
4437
|
+
// shouldn't crash the whole grid's render — skip it like a missing option.
|
|
4438
|
+
if (!node) continue
|
|
4381
4439
|
if (String(node[keys.valueKey]) === value) {
|
|
4382
4440
|
return node[keys.labelKey] != null ? node[keys.labelKey] : String(node[keys.valueKey])
|
|
4383
4441
|
}
|
|
@@ -5776,7 +5834,9 @@ const ExcelGridComponent = {
|
|
|
5776
5834
|
// RESIZE (3.5)
|
|
5777
5835
|
// =========================================================
|
|
5778
5836
|
startColResize(e, ci) {
|
|
5779
|
-
|
|
5837
|
+
// fitColumns owns column widths entirely — manual resize would break
|
|
5838
|
+
// its "always fits, never scrolls" invariant.
|
|
5839
|
+
if (this.internalLocked || this.fitColumns) return
|
|
5780
5840
|
const rect = this.$refs.container.getBoundingClientRect()
|
|
5781
5841
|
this.resizing = {
|
|
5782
5842
|
active: true,
|
|
@@ -5861,6 +5921,7 @@ const ExcelGridComponent = {
|
|
|
5861
5921
|
},
|
|
5862
5922
|
|
|
5863
5923
|
autoFitColumn(ci) {
|
|
5924
|
+
if (this.fitColumns) return
|
|
5864
5925
|
const col = this.leafCols[ci]
|
|
5865
5926
|
if (!col) return
|
|
5866
5927
|
let maxLen = (col.title || '').length
|
|
@@ -5876,7 +5937,8 @@ const ExcelGridComponent = {
|
|
|
5876
5937
|
},
|
|
5877
5938
|
|
|
5878
5939
|
_applyAutoWidth() {
|
|
5879
|
-
|
|
5940
|
+
// fitColumns is the higher-priority width control — see its own JSDoc.
|
|
5941
|
+
if (!this.autoWidth || this.fitColumns || !this.leafCols.length) return
|
|
5880
5942
|
this.leafCols.forEach((col, ci) => {
|
|
5881
5943
|
let maxLen = (col.title || '').length
|
|
5882
5944
|
for (let ri = 0; ri < Math.min(this.totalRows, 500); ri++) {
|
|
@@ -5889,6 +5951,40 @@ const ExcelGridComponent = {
|
|
|
5889
5951
|
this._cellStyleCache = Object.create(null)
|
|
5890
5952
|
},
|
|
5891
5953
|
|
|
5954
|
+
// fitColumns prop — ignores col.width as an absolute value, using it only
|
|
5955
|
+
// as a relative WEIGHT so every visible leaf column (pinned or not)
|
|
5956
|
+
// scales by one shared factor to exactly fill _relativeWidthContainer
|
|
5957
|
+
// (the same circular-dependency-safe reference %/CSS-length widths
|
|
5958
|
+
// already resolve against — see its declaration comment). Mirrors
|
|
5959
|
+
// naturalGridWidth's formula in reverse: that computed derives the
|
|
5960
|
+
// grid's natural width FROM the column widths; this derives the column
|
|
5961
|
+
// widths FROM the available width.
|
|
5962
|
+
_applyFitColumns() {
|
|
5963
|
+
if (!this.fitColumns || !this.leafCols.length) return
|
|
5964
|
+
const containerWidth = this._relativeWidthContainer
|
|
5965
|
+
if (!containerWidth) return // not measured yet — re-run once hostContainerWidth arrives
|
|
5966
|
+
const outlineW = this.rowGroups.length ? OUTLINE_GUTTER : 0
|
|
5967
|
+
const available = containerWidth - ROW_HEADER_WIDTH - outlineW - this.vScrollbarW - this.shellBorderW
|
|
5968
|
+
if (available <= 0) return
|
|
5969
|
+
|
|
5970
|
+
const visible = []
|
|
5971
|
+
let totalWeight = 0
|
|
5972
|
+
this.leafCols.forEach((col, ci) => {
|
|
5973
|
+
if (this.isColHidden(ci)) return
|
|
5974
|
+
const w = this.resolveColWidth(col.width, containerWidth)
|
|
5975
|
+
visible.push({ ci, weight: w })
|
|
5976
|
+
totalWeight += w
|
|
5977
|
+
})
|
|
5978
|
+
if (!visible.length || totalWeight <= 0) return
|
|
5979
|
+
|
|
5980
|
+
const scale = available / totalWeight
|
|
5981
|
+
visible.forEach(({ ci, weight }) => {
|
|
5982
|
+
this.$set(this.colWidths, ci, Math.max(FIT_COLUMNS_MIN_WIDTH, weight * scale))
|
|
5983
|
+
this.$delete(this.relativeColSpecs, ci)
|
|
5984
|
+
})
|
|
5985
|
+
this._cellStyleCache = Object.create(null)
|
|
5986
|
+
},
|
|
5987
|
+
|
|
5892
5988
|
ctxHideRow() {
|
|
5893
5989
|
const targetRow = this.contextMenu.row
|
|
5894
5990
|
// Row header: row >= 0 AND col = -1 (no column context)
|