vue2-excel-grid 1.7.0 → 1.7.2

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": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "Excel-style grid component for Vue 2.6.14 with virtual scrolling",
5
5
  "license": "MIT",
6
6
  "author": "Fozilbek Raimberdiyev",
@@ -13,20 +13,17 @@
13
13
  <span>{{ t.localSyncSavedAt }}: {{ savedAtText }}</span>
14
14
  <span>{{ snapshot.data.length }} {{ t.localSyncRows }}</span>
15
15
  </div>
16
- <div class="eg-lsm-table-wrap">
17
- <table class="eg-lsm-table">
18
- <thead>
19
- <tr>
20
- <th v-for="col in columns" :key="col.key">{{ col.title || col.key }}</th>
21
- </tr>
22
- </thead>
23
- <tbody>
24
- <tr v-for="(row, ri) in previewRows" :key="ri">
25
- <td v-for="col in columns" :key="col.key">{{ resolveCellDisplay(row, col) }}</td>
26
- </tr>
27
- </tbody>
28
- </table>
29
- <div v-if="hiddenRowCount > 0" class="eg-lsm-more">{{ moreRowsText }}</div>
16
+ <div class="eg-lsm-grid-wrap">
17
+ <component
18
+ :is="gridOptions"
19
+ :data="snapshot.data"
20
+ :columns="columns"
21
+ :height="360"
22
+ :locale="locale"
23
+ :theme="theme"
24
+ locked
25
+ :toolbar="false"
26
+ />
30
27
  </div>
31
28
  </template>
32
29
  </div>
@@ -69,18 +66,27 @@
69
66
  // and lets the host Restore it back into the grid or delete it. Not exported
70
67
  // from src/index.js (same "internal-only" convention as EgDatePicker.vue /
71
68
  // EgCheckbox.vue) — purpose-built for ExcelGrid.vue, not meant for standalone use.
72
- const PREVIEW_ROW_LIMIT = 200
73
-
69
+ //
70
+ // The preview itself is a real, nested ExcelGrid instance (locked/read-only,
71
+ // no toolbar) rather than a hand-rolled <table> — this gets column
72
+ // formatting/select-labels/date-formatting/virtual scrolling for free and
73
+ // correctly resolves function-based col.options against the preview grid's
74
+ // OWN row indices (impossible for a detached snapshot row via the live
75
+ // grid's own resolver). `gridOptions` is ExcelGrid.vue's own `$options`,
76
+ // passed down by the parent instance instead of importing ExcelGrid.vue
77
+ // here directly — that import would be circular (ExcelGrid.vue -> this file
78
+ // -> ExcelGrid.vue).
74
79
  import { getMessages } from '../utils/i18n.js'
75
80
 
76
81
  export default {
77
82
  name: 'EgLocalSyncModal',
78
83
  props: {
79
84
  visible: { type: Boolean, default: false },
85
+ gridOptions: { type: Object, required: true },
80
86
  columns: { type: Array, default: () => [] },
81
87
  snapshot: { type: Object, default: null }, // { data, updatedAt } | null
82
- resolveCellDisplay: { type: Function, required: true },
83
- locale: { type: String, default: 'en' }
88
+ locale: { type: String, default: 'en' },
89
+ theme: { type: String, default: 'excel' }
84
90
  },
85
91
  data() {
86
92
  return { confirmingClear: false }
@@ -90,17 +96,6 @@ export default {
90
96
  savedAtText() {
91
97
  if (!this.snapshot) return ''
92
98
  return new Date(this.snapshot.updatedAt).toLocaleString()
93
- },
94
- previewRows() {
95
- if (!this.snapshot) return []
96
- return this.snapshot.data.slice(0, PREVIEW_ROW_LIMIT)
97
- },
98
- hiddenRowCount() {
99
- if (!this.snapshot) return 0
100
- return Math.max(0, this.snapshot.data.length - PREVIEW_ROW_LIMIT)
101
- },
102
- moreRowsText() {
103
- return (this.t.localSyncMoreRows || '').replace('{n}', this.hiddenRowCount)
104
99
  }
105
100
  },
106
101
  watch: {
@@ -133,7 +128,7 @@ export default {
133
128
  border: 1px solid var(--eg-color-border-cell, var(--eg-color-border-cell-default));
134
129
  border-radius: var(--eg-radius, var(--eg-radius-default));
135
130
  box-shadow: var(--eg-shadow-dialog, var(--eg-shadow-dialog-default));
136
- width: min(720px, 92vw);
131
+ width: min(1200px, 94vw);
137
132
  max-height: 82vh;
138
133
  display: flex;
139
134
  flex-direction: column;
@@ -184,40 +179,10 @@ export default {
184
179
  color: var(--eg-color-text-secondary, var(--eg-color-text-secondary-default));
185
180
  margin-bottom: 10px;
186
181
  }
187
- .eg-lsm-table-wrap {
182
+ .eg-lsm-grid-wrap {
188
183
  border: 1px solid var(--eg-color-border-cell, var(--eg-color-border-cell-default));
189
184
  border-radius: var(--eg-radius, var(--eg-radius-default));
190
- overflow: auto;
191
- max-height: 45vh;
192
- }
193
- .eg-lsm-table {
194
- width: 100%;
195
- border-collapse: collapse;
196
- font-size: var(--eg-font-size, var(--eg-font-size-default));
197
- color: var(--eg-color-text, var(--eg-color-text-default));
198
- }
199
- .eg-lsm-table th,
200
- .eg-lsm-table td {
201
- padding: 6px 10px;
202
- border-bottom: 1px solid var(--eg-color-border-cell, var(--eg-color-border-cell-default));
203
- text-align: left;
204
- white-space: nowrap;
205
- }
206
- .eg-lsm-table th {
207
- position: sticky;
208
- top: 0;
209
- background: var(--eg-color-header-bg, var(--eg-color-header-bg-default));
210
- font-weight: 600;
211
- z-index: 1;
212
- }
213
- .eg-lsm-table tbody tr:last-child td {
214
- border-bottom: none;
215
- }
216
- .eg-lsm-more {
217
- padding: 8px 10px;
218
- font-size: 12px;
219
- color: var(--eg-color-text-muted, var(--eg-color-text-muted-default));
220
- text-align: center;
185
+ overflow: hidden;
221
186
  }
222
187
  .eg-lsm-footer {
223
188
  display: flex;
@@ -817,10 +817,11 @@
817
817
  <eg-local-sync-modal
818
818
  v-if="localSyncKey"
819
819
  :visible="localSyncModal.visible"
820
+ :grid-options="_selfComponentDef"
820
821
  :columns="_localSyncPreviewColumns"
821
822
  :snapshot="localSyncModal.snapshot"
822
- :resolve-cell-display="_previewCellDisplay"
823
823
  :locale="locale"
824
+ :theme="internalTheme"
824
825
  @close="closeLocalSyncModal"
825
826
  @save="_onLocalSyncModalSave"
826
827
  @restore="restoreLocalSnapshot"
@@ -980,7 +981,14 @@ const DEFAULT_TOOLBAR_LIST = ['undoRedo', 'export', 'import', 'print', 'localSyn
980
981
  const COL_DRAG_TRANSITION = 'transform 200ms cubic-bezier(0.2, 0, 0, 1)'
981
982
  const THEME_LIST = ['excel', 'material', 'antd', 'fluent', 'carbon']
982
983
 
983
- export default {
984
+ // Kept as a named const (rather than an inline `export default {}`) so the
985
+ // local-sync preview modal can receive the plain component definition
986
+ // itself as a prop — see `_selfComponentDef` below. Importing ExcelGrid.vue
987
+ // from EgLocalSyncModal.vue to nest a grid inside it would be a circular
988
+ // import (ExcelGrid.vue -> EgLocalSyncModal.vue -> ExcelGrid.vue); passing
989
+ // this reference down avoids that entirely, and avoids passing `this.$options`
990
+ // (an instance's merged/runtime-contaminated options, not a clean definition).
991
+ const ExcelGridComponent = {
984
992
  name: 'ExcelGrid',
985
993
 
986
994
  components: { EgCheckbox, EgSelect, EgTreeSelect, EgDatePicker, EgLocalSyncModal },
@@ -1679,6 +1687,13 @@ export default {
1679
1687
  return this.leafCols.filter(col => col.type !== 'action')
1680
1688
  },
1681
1689
 
1690
+ // Passed to EgLocalSyncModal so it can render the snapshot preview as a
1691
+ // real, nested ExcelGrid instance — see the comment on ExcelGridComponent
1692
+ // above for why this is the module-level const and not `this.$options`.
1693
+ _selfComponentDef() {
1694
+ return ExcelGridComponent
1695
+ },
1696
+
1682
1697
  _sizeConf() { return SIZE_CONFIG[this.internalSize] || SIZE_CONFIG.middle },
1683
1698
 
1684
1699
  sizeOptions() { return Object.keys(SIZE_CONFIG) },
@@ -6316,46 +6331,6 @@ export default {
6316
6331
  this.localSyncModal.visible = false
6317
6332
  },
6318
6333
 
6319
- // Best-effort display resolver for the modal's read-only preview table.
6320
- // Deliberately NOT the same as getCellDisplayValue(ci, val, ri): that
6321
- // method resolves column formatter/select-options against the LIVE grid
6322
- // (this._dataRaw[ri] at the live row index ri) — meaningless for a
6323
- // detached IndexedDB snapshot row that may not even correspond to the
6324
- // same row position in the current data. This takes the row object
6325
- // directly instead. Function-based (dependent/cascading) col.options
6326
- // can't be safely resolved without that live per-row context, so those
6327
- // fall back to showing the raw stored value — a deliberate, explainable
6328
- // limitation for a preview, not a bug.
6329
- _previewCellDisplay(row, col) {
6330
- const val = row ? row[col.key] : null
6331
- if (!col) return val == null ? '' : val
6332
- if (typeof col.formatter === 'function') {
6333
- try {
6334
- const out = col.formatter(val, row, null, col, col._flatIndex)
6335
- return out == null ? '' : out
6336
- } catch (e) {
6337
- return val == null ? '' : val
6338
- }
6339
- }
6340
- if (col.type === 'checkbox') return val ? '✓' : ''
6341
- if ((col.type === 'select' || col.type === 'treeSelect') && Array.isArray(col.options)) {
6342
- const { valueKey, labelKey } = this.treeOptionKeys(col)
6343
- const v = val == null ? '' : String(val)
6344
- if (col.type === 'treeSelect') {
6345
- const found = this._treeFindLabel(col.options, this.treeOptionKeys(col), v)
6346
- return found != null ? found : v
6347
- }
6348
- const found = col.options.find(o => String(typeof o === 'string' ? o : o[valueKey]) === v)
6349
- if (!found) return v
6350
- return typeof found === 'string' ? found : (found[labelKey] != null ? found[labelKey] : v)
6351
- }
6352
- if (col.type === 'date') {
6353
- const d = parseDateValue(val)
6354
- return d ? formatDate(d, col.format || 'YYYY-MM-DD') : (val == null ? '' : val)
6355
- }
6356
- return val == null ? '' : val
6357
- },
6358
-
6359
6334
  toggleLock() {
6360
6335
  this.internalLocked = !this.internalLocked
6361
6336
  this.$emit('update:locked', this.internalLocked)
@@ -6448,6 +6423,8 @@ export default {
6448
6423
  }
6449
6424
  }
6450
6425
  }
6426
+
6427
+ export default ExcelGridComponent
6451
6428
  </script>
6452
6429
 
6453
6430
  <style scoped>
package/src/utils/i18n.js CHANGED
@@ -51,7 +51,6 @@ const messages = {
51
51
  localSyncEmpty: 'No local copy saved yet',
52
52
  localSyncSavedAt: 'Last saved',
53
53
  localSyncRows: 'rows',
54
- localSyncMoreRows: 'and {n} more row(s)',
55
54
  localSyncSave: 'Save',
56
55
  localSyncSaveHint: 'Save the current table into the local copy',
57
56
  localSyncRestore: 'Restore',
@@ -123,7 +122,6 @@ const messages = {
123
122
  localSyncEmpty: 'Локальная копия пока не сохранена',
124
123
  localSyncSavedAt: 'Последнее сохранение',
125
124
  localSyncRows: 'строк',
126
- localSyncMoreRows: 'и ещё {n} строк(и)',
127
125
  localSyncSave: 'Сохранить',
128
126
  localSyncSaveHint: 'Сохранить текущую таблицу в локальную копию',
129
127
  localSyncRestore: 'Восстановить',
@@ -195,7 +193,6 @@ const messages = {
195
193
  localSyncEmpty: 'Hali lokal saqlangan nusxa yo\'q',
196
194
  localSyncSavedAt: 'Oxirgi saqlangan',
197
195
  localSyncRows: 'qator',
198
- localSyncMoreRows: 'va yana {n} ta qator',
199
196
  localSyncSave: 'Saqlash',
200
197
  localSyncSaveHint: 'Joriy jadvalni lokal nusxaga saqlash',
201
198
  localSyncRestore: 'Tiklash',
@@ -267,7 +264,6 @@ const messages = {
267
264
  localSyncEmpty: 'Ҳали лакал сақланган нусха йўқ',
268
265
  localSyncSavedAt: 'Охирги сақланган',
269
266
  localSyncRows: 'қатор',
270
- localSyncMoreRows: 'ва яна {n} та қатор',
271
267
  localSyncSave: 'Сақлаш',
272
268
  localSyncSaveHint: 'Жорий жадвални лакал нусхага сақлаш',
273
269
  localSyncRestore: 'Тиклаш',