@veltra/sheet 2.4.0 → 2.5.1

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.
Files changed (147) hide show
  1. package/dist/components/sheet/formula-bar.js +50 -7
  2. package/dist/components/sheet/style2.css +2 -2
  3. package/dist/index.d.ts +2 -19
  4. package/dist/index.js +2 -15
  5. package/dist/types/index.d.ts +1 -3
  6. package/package.json +5 -6
  7. package/src/components/sheet/__test__/formula-bar.test.ts +29 -0
  8. package/src/components/sheet/formula-bar.vue +67 -6
  9. package/src/components/sheet/style.scss +1 -1
  10. package/src/index.ts +1 -27
  11. package/src/types/index.ts +0 -2
  12. package/dist/components/report/binding-badge.js +0 -118
  13. package/dist/components/report/designer/cell-coords.js +0 -46
  14. package/dist/components/report/designer/col-widths.js +0 -29
  15. package/dist/components/report/designer/conditional-rules/helpers.js +0 -139
  16. package/dist/components/report/designer/drill-dialog.js +0 -258
  17. package/dist/components/report/designer/drop-highlight-overlay.js +0 -76
  18. package/dist/components/report/designer/float-panel.js +0 -434
  19. package/dist/components/report/designer/role.js +0 -17
  20. package/dist/components/report/designer/rule-preview.js +0 -33
  21. package/dist/components/report/designer/rule-row.js +0 -253
  22. package/dist/components/report/designer/rules-dialog.js +0 -118
  23. package/dist/components/report/designer/topology-overlay.js +0 -122
  24. package/dist/components/report/designer/topology.js +0 -64
  25. package/dist/components/report/designer/use-grid-overlay.js +0 -75
  26. package/dist/components/report/designer-hub.js +0 -177
  27. package/dist/components/report/field-panel-helpers.js +0 -33
  28. package/dist/components/report/field-panel.js +0 -132
  29. package/dist/components/report/filter-bar.js +0 -74
  30. package/dist/components/report/hub-connection-form.js +0 -145
  31. package/dist/components/report/hub-dataset-editor.js +0 -409
  32. package/dist/components/report/preview-grid-size.js +0 -32
  33. package/dist/components/report/print.js +0 -39
  34. package/dist/components/report/report-designer.js +0 -428
  35. package/dist/components/report/report-viewer.js +0 -253
  36. package/dist/components/report/style.d.ts +0 -17
  37. package/dist/components/report/style.js +0 -18
  38. package/dist/components/report/style2.css +0 -965
  39. package/dist/components/report/use-report-designer.js +0 -387
  40. package/dist/components/report/use-report-viewer.js +0 -140
  41. package/dist/report/binding.d.ts +0 -83
  42. package/dist/report/binding.js +0 -334
  43. package/dist/report/connector.d.ts +0 -66
  44. package/dist/report/connector.js +0 -159
  45. package/dist/report/drill.d.ts +0 -48
  46. package/dist/report/drill.js +0 -78
  47. package/dist/report/export-xlsx.d.ts +0 -13
  48. package/dist/report/export-xlsx.js +0 -13
  49. package/dist/report/filter-bar.d.ts +0 -10
  50. package/dist/report/filter-bar.js +0 -31
  51. package/dist/report/index.d.ts +0 -14
  52. package/dist/report/params.d.ts +0 -13
  53. package/dist/report/params.js +0 -61
  54. package/dist/report/print.d.ts +0 -23
  55. package/dist/report/print.js +0 -197
  56. package/dist/report/render/aggregate.js +0 -193
  57. package/dist/report/render/builder.d.ts +0 -12
  58. package/dist/report/render/builder.js +0 -139
  59. package/dist/report/render/coordinate.d.ts +0 -25
  60. package/dist/report/render/coordinate.js +0 -733
  61. package/dist/report/render/index.d.ts +0 -14
  62. package/dist/report/render/index.js +0 -21
  63. package/dist/report/render/style-resolver.js +0 -50
  64. package/dist/report/render/template-index.d.ts +0 -24
  65. package/dist/report/render/template-index.js +0 -137
  66. package/dist/report/rules/evaluate.d.ts +0 -25
  67. package/dist/report/rules/evaluate.js +0 -82
  68. package/dist/report/rules/index.d.ts +0 -2
  69. package/dist/report/template.d.ts +0 -63
  70. package/dist/report/template.js +0 -83
  71. package/dist/report/types.d.ts +0 -103
  72. package/dist/types/report-designer.d.ts +0 -51
  73. package/dist/types/report-viewer.d.ts +0 -57
  74. package/src/components/report/__test__/binding-badge.test.ts +0 -92
  75. package/src/components/report/__test__/conditional-rules-helpers.test.ts +0 -88
  76. package/src/components/report/__test__/field-panel-helpers.test.ts +0 -65
  77. package/src/components/report/__test__/float-panel-position.test.ts +0 -45
  78. package/src/components/report/__test__/preview-grid-size.test.ts +0 -63
  79. package/src/components/report/__test__/report-designer.test.ts +0 -559
  80. package/src/components/report/__test__/report-drill.test.ts +0 -692
  81. package/src/components/report/__test__/report-viewer.test.ts +0 -400
  82. package/src/components/report/__test__/topology.test.ts +0 -143
  83. package/src/components/report/__test__/use-report-designer.test.ts +0 -804
  84. package/src/components/report/binding-badge.ts +0 -122
  85. package/src/components/report/designer/cell-coords.ts +0 -95
  86. package/src/components/report/designer/col-widths.ts +0 -56
  87. package/src/components/report/designer/conditional-rules/helpers.ts +0 -189
  88. package/src/components/report/designer/drill-dialog.vue +0 -245
  89. package/src/components/report/designer/drop-highlight-overlay.vue +0 -75
  90. package/src/components/report/designer/float-panel.vue +0 -444
  91. package/src/components/report/designer/role.ts +0 -32
  92. package/src/components/report/designer/rule-preview.vue +0 -40
  93. package/src/components/report/designer/rule-row.vue +0 -252
  94. package/src/components/report/designer/rules-dialog.vue +0 -110
  95. package/src/components/report/designer/topology-overlay.vue +0 -128
  96. package/src/components/report/designer/topology.ts +0 -124
  97. package/src/components/report/designer/use-grid-overlay.ts +0 -114
  98. package/src/components/report/designer-hub.vue +0 -198
  99. package/src/components/report/field-panel-helpers.ts +0 -44
  100. package/src/components/report/field-panel.vue +0 -136
  101. package/src/components/report/filter-bar.vue +0 -77
  102. package/src/components/report/hub-connection-form.vue +0 -124
  103. package/src/components/report/hub-dataset-editor.vue +0 -387
  104. package/src/components/report/index.ts +0 -2
  105. package/src/components/report/preview-grid-size.ts +0 -33
  106. package/src/components/report/print.ts +0 -44
  107. package/src/components/report/report-designer.vue +0 -454
  108. package/src/components/report/report-viewer.vue +0 -289
  109. package/src/components/report/style-designer.scss +0 -653
  110. package/src/components/report/style-hub.scss +0 -292
  111. package/src/components/report/style-viewer.scss +0 -144
  112. package/src/components/report/style.scss +0 -3
  113. package/src/components/report/style.ts +0 -20
  114. package/src/components/report/use-report-designer.ts +0 -603
  115. package/src/components/report/use-report-viewer.ts +0 -227
  116. package/src/report/__test__/binding.test.ts +0 -320
  117. package/src/report/__test__/connector.test.ts +0 -239
  118. package/src/report/__test__/drill.test.ts +0 -194
  119. package/src/report/__test__/export-xlsx.test.ts +0 -96
  120. package/src/report/__test__/filter-bar.test.ts +0 -58
  121. package/src/report/__test__/params.test.ts +0 -156
  122. package/src/report/__test__/print.test.ts +0 -170
  123. package/src/report/__test__/render.test.ts +0 -856
  124. package/src/report/__test__/rules.test.ts +0 -131
  125. package/src/report/__test__/template.test.ts +0 -366
  126. package/src/report/binding.ts +0 -474
  127. package/src/report/connector.ts +0 -206
  128. package/src/report/drill.ts +0 -112
  129. package/src/report/export-xlsx.ts +0 -15
  130. package/src/report/filter-bar.ts +0 -36
  131. package/src/report/index.ts +0 -16
  132. package/src/report/params.ts +0 -96
  133. package/src/report/print.ts +0 -234
  134. package/src/report/render/__test__/aggregate.test.ts +0 -16
  135. package/src/report/render/__test__/coordinate.test.ts +0 -405
  136. package/src/report/render/aggregate.ts +0 -289
  137. package/src/report/render/builder.ts +0 -211
  138. package/src/report/render/coordinate.ts +0 -1239
  139. package/src/report/render/index.ts +0 -30
  140. package/src/report/render/style-resolver.ts +0 -68
  141. package/src/report/render/template-index.ts +0 -200
  142. package/src/report/rules/evaluate.ts +0 -113
  143. package/src/report/rules/index.ts +0 -7
  144. package/src/report/template.ts +0 -145
  145. package/src/report/types.ts +0 -116
  146. package/src/types/report-designer.ts +0 -55
  147. package/src/types/report-viewer.ts +0 -54
@@ -1,733 +0,0 @@
1
- import { sameAddress } from "./template-index.js";
2
- import { cellKey, createRange } from "@veltra/sheet-core";
3
- //#region src/report/render/coordinate.ts
4
- function isRowExpanding(binding) {
5
- return binding.expand === "down" && (binding.aggregate === "group" || binding.aggregate === "list");
6
- }
7
- function isColExpanding(binding) {
8
- return binding.expand === "right" && (binding.aggregate === "group" || binding.aggregate === "list");
9
- }
10
- function mergeSpanEnabled(binding) {
11
- return binding?.mergeSpan !== false;
12
- }
13
- function filterRows(rows, filter) {
14
- if (Object.keys(filter).length === 0) return rows;
15
- return rows.filter((row) => Object.entries(filter).every(([field, value]) => row[field] === value));
16
- }
17
- function distinctFieldValues(rows, field) {
18
- const seen = /* @__PURE__ */ new Set();
19
- const values = [];
20
- for (const row of rows) {
21
- const key = JSON.stringify(row[field]);
22
- if (seen.has(key)) continue;
23
- seen.add(key);
24
- values.push(row[field]);
25
- }
26
- return values;
27
- }
28
- function sortValues(values, sort) {
29
- if (sort === "asc") return [...values].sort((a, b) => String(a).localeCompare(String(b), "zh-CN"));
30
- if (sort === "desc") return [...values].sort((a, b) => String(b).localeCompare(String(a), "zh-CN"));
31
- return values;
32
- }
33
- function singleCellRange(row, col) {
34
- return {
35
- start: {
36
- row,
37
- col
38
- },
39
- end: {
40
- row,
41
- col
42
- }
43
- };
44
- }
45
- function rangeRows(range) {
46
- return range.end.row - range.start.row + 1;
47
- }
48
- function rangeCols(range) {
49
- return range.end.col - range.start.col + 1;
50
- }
51
- function mergeFilters(rowFilter, colFilter) {
52
- return {
53
- ...rowFilter,
54
- ...colFilter
55
- };
56
- }
57
- function parentFilterForBinding(binding, index, rowFilter, colFilter) {
58
- const filter = {};
59
- if (binding.rowParent) {
60
- const parent = index.bindingAt(binding.rowParent);
61
- if (parent && parent.dataset === binding.dataset) Object.assign(filter, rowFilter);
62
- }
63
- if (binding.colParent) {
64
- const parent = index.bindingAt(binding.colParent);
65
- if (parent && parent.dataset === binding.dataset) Object.assign(filter, colFilter);
66
- }
67
- return filter;
68
- }
69
- /** 枚举扩展格实例 */
70
- function enumerateExpansionInstances(binding, data, filter) {
71
- const rows = filterRows(data[binding.dataset] ?? [], filter);
72
- if (!isRowExpanding(binding) && !isColExpanding(binding)) return [{
73
- index: 0,
74
- filter
75
- }];
76
- if (binding.aggregate === "group") return sortValues(distinctFieldValues(rows, binding.field), binding.sort).map((value, index) => ({
77
- index,
78
- value,
79
- filter: {
80
- ...filter,
81
- [binding.field]: value
82
- }
83
- }));
84
- if (binding.aggregate === "list") return rows.map((_, index) => ({
85
- index,
86
- filter
87
- }));
88
- return [{
89
- index: 0,
90
- filter
91
- }];
92
- }
93
- function isRowSubtreeRoot(binding, index) {
94
- if (!isRowExpanding(binding)) return false;
95
- if (!binding.rowParent) return true;
96
- const parent = index.bindingAt(binding.rowParent);
97
- return !parent || !isRowExpanding(parent);
98
- }
99
- function isColSubtreeRoot(binding, index) {
100
- if (!isColExpanding(binding)) return false;
101
- if (!binding.colParent) return true;
102
- const parent = index.bindingAt(binding.colParent);
103
- return !parent || !isColExpanding(parent);
104
- }
105
- function isNestedRowExpander(binding, index) {
106
- return isRowExpanding(binding) && binding.aggregate === "group" && !!binding.rowParent && !isRowSubtreeRoot(binding, index);
107
- }
108
- function isNestedColExpander(binding, index) {
109
- return isColExpanding(binding) && binding.aggregate === "group" && !!binding.colParent && !isColSubtreeRoot(binding, index);
110
- }
111
- function rowSubtreeRows(rootAddr, index) {
112
- let maxRow = rootAddr.row;
113
- const walk = (addr) => {
114
- maxRow = Math.max(maxRow, addr.row);
115
- for (const child of index.rowChildren.get(cellKey(addr)) ?? []) walk(child);
116
- };
117
- walk(rootAddr);
118
- return index.logicalRows.filter((row) => row >= rootAddr.row && row <= maxRow);
119
- }
120
- function colSubtreeCols(rootAddr, index) {
121
- let maxCol = rootAddr.col;
122
- const walk = (addr) => {
123
- maxCol = Math.max(maxCol, addr.col);
124
- for (const child of index.colChildren.get(cellKey(addr)) ?? []) walk(child);
125
- };
126
- walk(rootAddr);
127
- return index.logicalCols.filter((col) => col >= rootAddr.col && col <= maxCol);
128
- }
129
- function columnsOnRow(index, row) {
130
- const cols = /* @__PURE__ */ new Set();
131
- for (const entry of index.bindingsOnRow(row)) cols.add(entry.addr.col);
132
- for (const cell of index.staticCells.values()) if (cell.row === row) cols.add(cell.col);
133
- return [...cols].sort((a, b) => a - b);
134
- }
135
- function findRowSubtreeRootOnRow(index, row) {
136
- for (const entry of index.bindingsOnRow(row)) if (isRowSubtreeRoot(entry.binding, index)) return entry.addr;
137
- return null;
138
- }
139
- /** 扩展带终止行:新的纵向子树根,或无父格的汇总行(如总计) */
140
- function isExpansionBandTerminatorRow(index, row, rootRow) {
141
- if (row <= rootRow) return false;
142
- const rowRoot = findRowSubtreeRootOnRow(index, row);
143
- if (rowRoot && rowRoot.row !== rootRow) return true;
144
- return !isCompanionRow(index, row);
145
- }
146
- /** 扩展带内随行:全部绑定均带 rowParent(纯静态行不算带内行) */
147
- function isCompanionRow(index, row) {
148
- const bindings = index.bindingsOnRow(row);
149
- if (bindings.length === 0) return false;
150
- return bindings.every(({ binding }) => binding.rowParent !== void 0);
151
- }
152
- /** 纵向扩展带覆盖的模板行:子树行 + 紧随其后的带内汇总行 */
153
- function expansionBandRows(rootAddr, index) {
154
- const subtreeRows = rowSubtreeRows(rootAddr, index);
155
- const maxSubtreeRow = Math.max(...subtreeRows);
156
- const rows = new Set(subtreeRows);
157
- for (const row of index.logicalRows) {
158
- if (row <= maxSubtreeRow) continue;
159
- if (isExpansionBandTerminatorRow(index, row, rootAddr.row)) break;
160
- if (!isCompanionRow(index, row)) break;
161
- rows.add(row);
162
- }
163
- return index.logicalRows.filter((row) => rows.has(row));
164
- }
165
- function findNestedColChild(rootAddr, index) {
166
- for (const child of index.colChildren.get(cellKey(rootAddr)) ?? []) {
167
- const binding = index.bindingAt(child);
168
- if (binding && isColExpanding(binding) && child.row > rootAddr.row) return child;
169
- }
170
- return null;
171
- }
172
- var CoordinateEngine = class {
173
- index;
174
- data;
175
- constructor(index, data) {
176
- this.index = index;
177
- this.data = data;
178
- }
179
- compute() {
180
- const placements = [];
181
- const consumedRows = /* @__PURE__ */ new Set();
182
- let physRow = 0;
183
- let maxCol = 0;
184
- for (const logicalRow of this.index.logicalRows) {
185
- if (consumedRows.has(logicalRow)) continue;
186
- const rowRoot = findRowSubtreeRootOnRow(this.index, logicalRow);
187
- if (rowRoot) {
188
- const result = this.layoutRowSubtree(rowRoot, emptyCtx(), physRow, 0);
189
- placements.push(...result.placements);
190
- physRow += result.rowSpan;
191
- maxCol = Math.max(maxCol, result.colSpan);
192
- for (const row of expansionBandRows(rowRoot, this.index)) consumedRows.add(row);
193
- continue;
194
- }
195
- const result = this.layoutStandaloneRow(logicalRow, emptyCtx(), physRow, 0);
196
- placements.push(...result.placements);
197
- physRow += result.rowSpan;
198
- maxCol = Math.max(maxCol, result.colSpan);
199
- }
200
- return {
201
- rowCount: physRow,
202
- colCount: Math.max(maxCol, this.baseColCount()),
203
- placements,
204
- mappedMerges: mapTemplateMerges(this.index, placements)
205
- };
206
- }
207
- baseColCount() {
208
- if (this.index.logicalCols.length === 0) return 0;
209
- return Math.max(...this.index.logicalCols) + 1;
210
- }
211
- layoutRowSubtree(rootAddr, ctx, physRowStart, physColStart) {
212
- const rootBinding = this.index.bindingAt(rootAddr);
213
- const parentFilter = parentFilterForBinding(rootBinding, this.index, ctx.rowFilter, ctx.colFilter);
214
- const instances = enumerateExpansionInstances(rootBinding, this.data, mergeFilters(parentFilter, ctx.rowFilter));
215
- const bandRows = expansionBandRows(rootAddr, this.index);
216
- if (instances.length === 0) return {
217
- rowSpan: 0,
218
- colSpan: 0,
219
- placements: []
220
- };
221
- if (rootBinding.aggregate === "list") {
222
- const listCtx = {
223
- rowFilter: mergeFilters(parentFilter, ctx.rowFilter),
224
- colFilter: ctx.colFilter,
225
- rowPath: ctx.rowPath,
226
- colPath: ctx.colPath
227
- };
228
- const rowResult = this.layoutTemplateRow(rootAddr.row, listCtx, physRowStart, physColStart, rootAddr, instances.length);
229
- const placements = [...rowResult.placements];
230
- let totalRowSpan = instances.length;
231
- for (const templateRow of bandRows) {
232
- if (templateRow === rootAddr.row) continue;
233
- const companionResult = this.layoutTemplateRow(templateRow, listCtx, physRowStart + totalRowSpan, physColStart, null, 1);
234
- placements.push(...companionResult.placements);
235
- totalRowSpan += companionResult.rowSpan;
236
- }
237
- return {
238
- rowSpan: totalRowSpan,
239
- colSpan: rowResult.colSpan,
240
- placements
241
- };
242
- }
243
- const placements = [];
244
- let totalRowSpan = 0;
245
- let maxColSpan = 0;
246
- for (const instance of instances) {
247
- const instanceCtx = {
248
- rowFilter: instance.filter,
249
- colFilter: ctx.colFilter,
250
- rowPath: [...ctx.rowPath, instance.index],
251
- colPath: ctx.colPath
252
- };
253
- const instanceHeight = this.measureSubtreeInstanceHeight(bandRows, rootAddr, instanceCtx);
254
- const groupMergeHeight = this.measureTemplateRowHeight(rootAddr.row, instanceCtx, null);
255
- if (this.bandHasMultiRowList(bandRows, instanceCtx)) {
256
- const bandResult = this.layoutMultiRowListBand(bandRows, rootAddr, instanceCtx, physRowStart + totalRowSpan, physColStart, groupMergeHeight);
257
- placements.push(...bandResult.placements);
258
- maxColSpan = Math.max(maxColSpan, bandResult.colSpan);
259
- totalRowSpan += instanceHeight;
260
- continue;
261
- }
262
- let rowOffset = 0;
263
- for (const templateRow of bandRows) {
264
- const rowHeight = this.measureTemplateRowHeight(templateRow, instanceCtx, rootAddr);
265
- const mergeHeight = templateRow === rootAddr.row ? groupMergeHeight : instanceHeight - rowOffset;
266
- const rowResult = this.layoutTemplateRow(templateRow, instanceCtx, physRowStart + totalRowSpan + rowOffset, physColStart, rootAddr, mergeHeight);
267
- placements.push(...rowResult.placements);
268
- rowOffset += rowHeight;
269
- maxColSpan = Math.max(maxColSpan, rowResult.colSpan);
270
- }
271
- totalRowSpan += instanceHeight;
272
- }
273
- return {
274
- rowSpan: totalRowSpan,
275
- colSpan: maxColSpan,
276
- placements
277
- };
278
- }
279
- measureSubtreeInstanceHeight(bandRows, rootAddr, ctx) {
280
- let listDrivenHeight = 0;
281
- let companionHeight = 0;
282
- for (const row of bandRows) {
283
- const listCount = this.listInstanceCountOnRow(row, ctx);
284
- if (listCount > 0) {
285
- listDrivenHeight = Math.max(listDrivenHeight, listCount);
286
- continue;
287
- }
288
- if (row === rootAddr.row) continue;
289
- companionHeight += this.measureTemplateRowHeight(row, ctx, rootAddr);
290
- }
291
- if (listDrivenHeight === 0) return this.measureTemplateRowHeight(rootAddr.row, ctx, null);
292
- return listDrivenHeight + companionHeight;
293
- }
294
- bandHasMultiRowList(bandRows, ctx) {
295
- let count = 0;
296
- for (const row of bandRows) {
297
- if (this.listInstanceCountOnRow(row, ctx) > 0) count++;
298
- if (count > 1) return true;
299
- }
300
- return false;
301
- }
302
- layoutMultiRowListBand(bandRows, rootAddr, ctx, physRowStart, physColStart, groupMergeHeight) {
303
- const listRows = bandRows.filter((row) => this.listInstanceCountOnRow(row, ctx) > 0);
304
- const companionRows = bandRows.filter((row) => !listRows.includes(row));
305
- const listCount = Math.max(...listRows.map((row) => this.listInstanceCountOnRow(row, ctx)), 1);
306
- const placements = [];
307
- let maxColSpan = 0;
308
- for (let listIndex = 0; listIndex < listCount; listIndex++) for (const templateRow of listRows) {
309
- const rowResult = this.layoutTemplateRow(templateRow, ctx, physRowStart + listIndex, physColStart, templateRow === rootAddr.row ? rootAddr : null, groupMergeHeight, false, listIndex, listCount);
310
- placements.push(...rowResult.placements);
311
- maxColSpan = Math.max(maxColSpan, rowResult.colSpan);
312
- }
313
- let rowOffset = listCount;
314
- for (const templateRow of companionRows) {
315
- const rowResult = this.layoutTemplateRow(templateRow, ctx, physRowStart + rowOffset, physColStart, null, 1);
316
- placements.push(...rowResult.placements);
317
- maxColSpan = Math.max(maxColSpan, rowResult.colSpan);
318
- rowOffset += rowResult.rowSpan;
319
- }
320
- return {
321
- rowSpan: rowOffset,
322
- colSpan: maxColSpan,
323
- placements
324
- };
325
- }
326
- measureTemplateRowHeight(templateRow, ctx, rootAddr) {
327
- for (const entry of this.index.bindingsOnRow(templateRow)) if (isNestedRowExpander(entry.binding, this.index)) return this.measureNestedRowBandHeight(entry.addr, entry.binding, templateRow, ctx);
328
- const listCount = this.listInstanceCountOnRow(templateRow, ctx);
329
- if (listCount > 0) return listCount;
330
- if (rootAddr && templateRow === rootAddr.row) return 0;
331
- return 1;
332
- }
333
- measureNestedRowBandHeight(groupAddr, groupBinding, templateRow, ctx) {
334
- const parentFilter = parentFilterForBinding(groupBinding, this.index, ctx.rowFilter, ctx.colFilter);
335
- const instances = enumerateExpansionInstances(groupBinding, this.data, mergeFilters(parentFilter, ctx.rowFilter));
336
- if (instances.length === 0) return 0;
337
- let total = 0;
338
- for (const instance of instances) {
339
- const instanceCtx = {
340
- ...ctx,
341
- rowFilter: instance.filter,
342
- rowPath: [...ctx.rowPath, instance.index]
343
- };
344
- total += this.listInstanceCountOnRow(templateRow, instanceCtx) || 1;
345
- }
346
- return total;
347
- }
348
- layoutStandaloneRow(templateRow, ctx, physRowStart, physColStart) {
349
- return this.layoutTemplateRow(templateRow, ctx, physRowStart, physColStart, null, 1, !this.rowUsesPackedColumns(templateRow));
350
- }
351
- rowUsesPackedColumns(templateRow) {
352
- for (const entry of this.index.bindingsOnRow(templateRow)) {
353
- if (isColSubtreeRoot(entry.binding, this.index)) return true;
354
- if (isNestedColExpander(entry.binding, this.index)) return true;
355
- if (entry.binding.colParent) {
356
- const parent = this.index.bindingAt(entry.binding.colParent);
357
- if (parent && isColExpanding(parent)) return true;
358
- }
359
- }
360
- return false;
361
- }
362
- layoutTemplateRow(templateRow, ctx, physRowStart, physColStart, rowSubtreeRoot, groupMergeHeight, preserveLogicalCols = false, fixedListIndex, mergeListCount) {
363
- for (const entry of this.index.bindingsOnRow(templateRow)) if (isNestedRowExpander(entry.binding, this.index)) return this.layoutNestedRowBand(templateRow, entry.addr, entry.binding, ctx, physRowStart, physColStart);
364
- const cols = columnsOnRow(this.index, templateRow);
365
- const placements = [];
366
- let physCol = physColStart;
367
- const packedCols = !preserveLogicalCols && this.rowUsesPackedColumns(templateRow);
368
- const listCount = this.listInstanceCountOnRow(templateRow, ctx);
369
- const rowSpan = fixedListIndex !== void 0 ? 1 : Math.max(listCount, 1);
370
- const leadingGap = cols.length > 0 && cols[0] > physColStart;
371
- for (const col of cols) {
372
- const addr = {
373
- row: templateRow,
374
- col
375
- };
376
- const binding = this.index.bindingAt(addr);
377
- const targetCol = packedCols && !leadingGap ? physCol : col;
378
- if (binding && isColSubtreeRoot(binding, this.index)) {
379
- const colResult = this.layoutColSubtree(addr, ctx, physRowStart, targetCol);
380
- placements.push(...colResult.placements);
381
- if (packedCols) physCol = leadingGap ? targetCol + colResult.colSpan : physCol + colResult.colSpan;
382
- continue;
383
- }
384
- if (binding && isNestedColExpander(binding, this.index)) {
385
- const colResult = this.layoutNestedColBand(addr, binding, ctx, physRowStart, targetCol);
386
- placements.push(...colResult.placements);
387
- if (packedCols) physCol = leadingGap ? targetCol + colResult.colSpan : physCol + colResult.colSpan;
388
- continue;
389
- }
390
- if (binding && this.isInlineColChild(templateRow, col)) continue;
391
- if (binding && binding.colParent && !isColExpanding(binding)) {
392
- const colResult = this.layoutColParentAlignedCell(addr, binding, ctx, physRowStart, targetCol, rowSpan);
393
- placements.push(...colResult.placements);
394
- if (packedCols) physCol = leadingGap ? targetCol + colResult.colSpan : physCol + colResult.colSpan;
395
- continue;
396
- }
397
- if (binding) {
398
- const cellResult = this.layoutBindingCell(addr, binding, ctx, physRowStart, targetCol, rowSpan, rowSubtreeRoot, groupMergeHeight, fixedListIndex, mergeListCount);
399
- placements.push(...cellResult.placements);
400
- if (packedCols) physCol = leadingGap ? targetCol + cellResult.colSpan : physCol + cellResult.colSpan;
401
- continue;
402
- }
403
- if (this.index.cellAt(addr)) {
404
- if (rowSpan > 1) for (let i = 0; i < rowSpan; i++) placements.push(this.makePlacement(addr, singleCellRange(physRowStart + i, targetCol), ctx, void 0, i, false));
405
- else placements.push(this.makePlacement(addr, singleCellRange(physRowStart, targetCol), ctx, void 0, 0, false));
406
- if (packedCols) physCol = leadingGap ? targetCol + 1 : physCol + 1;
407
- }
408
- }
409
- const effectiveColSpan = packedCols ? leadingGap && cols.length > 0 ? Math.max(...cols) + 1 - physColStart : physCol - physColStart : cols.length > 0 ? Math.max(...cols) + 1 - physColStart : 0;
410
- return {
411
- rowSpan: rowSubtreeRoot && templateRow === rowSubtreeRoot.row && listCount === 0 ? 0 : rowSpan,
412
- colSpan: effectiveColSpan,
413
- placements
414
- };
415
- }
416
- layoutNestedRowBand(templateRow, groupAddr, groupBinding, ctx, physRowStart, physColStart) {
417
- const parentFilter = parentFilterForBinding(groupBinding, this.index, ctx.rowFilter, ctx.colFilter);
418
- const instances = enumerateExpansionInstances(groupBinding, this.data, mergeFilters(parentFilter, ctx.rowFilter));
419
- if (instances.length === 0) return {
420
- rowSpan: 0,
421
- colSpan: 0,
422
- placements: []
423
- };
424
- const placements = [];
425
- let rowOffset = 0;
426
- let maxColSpan = 0;
427
- const colOffsets = this.rowLogicalColOffsets(templateRow, physColStart);
428
- for (const instance of instances) {
429
- const instanceCtx = {
430
- ...ctx,
431
- rowFilter: instance.filter,
432
- rowPath: [...ctx.rowPath, instance.index]
433
- };
434
- const detailCount = this.listInstanceCountOnRow(templateRow, instanceCtx) || 1;
435
- if (mergeSpanEnabled(groupBinding)) placements.push(this.makePlacement(groupAddr, createRange({
436
- row: physRowStart + rowOffset,
437
- col: physColStart
438
- }, {
439
- row: physRowStart + rowOffset + detailCount - 1,
440
- col: physColStart
441
- }), instanceCtx, groupBinding, 0, true));
442
- else for (let i = 0; i < detailCount; i++) placements.push(this.makePlacement(groupAddr, singleCellRange(physRowStart + rowOffset + i, physColStart), instanceCtx, groupBinding, i, false));
443
- for (const entry of this.index.bindingsOnRow(templateRow)) {
444
- if (sameAddress(entry.addr, groupAddr)) continue;
445
- if (!isRowExpanding(entry.binding) || entry.binding.aggregate !== "list") continue;
446
- for (let i = 0; i < detailCount; i++) placements.push(this.makePlacement(entry.addr, singleCellRange(physRowStart + rowOffset + i, colOffsets.get(entry.addr.col)), instanceCtx, entry.binding, i, false));
447
- }
448
- for (const col of columnsOnRow(this.index, templateRow)) {
449
- if (this.index.bindingAt({
450
- row: templateRow,
451
- col
452
- })) continue;
453
- if (!this.index.cellAt({
454
- row: templateRow,
455
- col
456
- })) continue;
457
- for (let i = 0; i < detailCount; i++) placements.push(this.makePlacement({
458
- row: templateRow,
459
- col
460
- }, singleCellRange(physRowStart + rowOffset + i, colOffsets.get(col)), instanceCtx, void 0, i, false));
461
- }
462
- maxColSpan = Math.max(maxColSpan, colOffsets.size);
463
- rowOffset += detailCount;
464
- }
465
- return {
466
- rowSpan: rowOffset,
467
- colSpan: maxColSpan,
468
- placements
469
- };
470
- }
471
- layoutBindingCell(addr, binding, ctx, physRowStart, physColStart, rowSpan, rowSubtreeRoot, groupMergeHeight, fixedListIndex, mergeListCount) {
472
- if (rowSubtreeRoot && isRowExpanding(binding) && binding.aggregate === "group" && sameAddress(addr, rowSubtreeRoot)) {
473
- if (fixedListIndex !== void 0 && fixedListIndex > 0) return {
474
- rowSpan: 0,
475
- colSpan: 1,
476
- placements: []
477
- };
478
- const mergeRows = Math.max(fixedListIndex !== void 0 ? mergeListCount ?? groupMergeHeight : groupMergeHeight, 1);
479
- if (!mergeSpanEnabled(binding)) return {
480
- rowSpan: 0,
481
- colSpan: 1,
482
- placements: Array.from({ length: mergeRows }, (_, listIndex) => this.makePlacement(addr, singleCellRange(physRowStart + listIndex, physColStart), ctx, binding, listIndex, false))
483
- };
484
- const range = createRange({
485
- row: physRowStart,
486
- col: physColStart
487
- }, {
488
- row: physRowStart + mergeRows - 1,
489
- col: physColStart
490
- });
491
- return {
492
- rowSpan: 0,
493
- colSpan: 1,
494
- placements: [this.makePlacement(addr, range, ctx, binding, 0, true)]
495
- };
496
- }
497
- if (isRowExpanding(binding) && binding.aggregate === "list") {
498
- if (fixedListIndex !== void 0) return {
499
- rowSpan: 0,
500
- colSpan: 1,
501
- placements: [this.makePlacement(addr, singleCellRange(physRowStart, physColStart), ctx, binding, fixedListIndex, false)]
502
- };
503
- return {
504
- rowSpan: 0,
505
- colSpan: 1,
506
- placements: Array.from({ length: rowSpan }, (_, listIndex) => this.makePlacement(addr, singleCellRange(physRowStart + listIndex, physColStart), ctx, binding, listIndex, false))
507
- };
508
- }
509
- return {
510
- rowSpan: 0,
511
- colSpan: 1,
512
- placements: [this.makePlacement(addr, expandRows(singleCellRange(physRowStart, physColStart), rowSpan), ctx, binding, 0, mergeSpanEnabled(binding) && rowSpan > 1)]
513
- };
514
- }
515
- layoutColSubtree(rootAddr, ctx, physRowStart, physColStart) {
516
- const rootBinding = this.index.bindingAt(rootAddr);
517
- const parentFilter = parentFilterForBinding(rootBinding, this.index, ctx.rowFilter, ctx.colFilter);
518
- const instances = enumerateExpansionInstances(rootBinding, this.data, mergeFilters(parentFilter, ctx.colFilter));
519
- if (instances.length === 0) return {
520
- rowSpan: 0,
521
- colSpan: 0,
522
- placements: []
523
- };
524
- const placements = [];
525
- let totalColSpan = 0;
526
- for (const instance of instances) {
527
- const instanceCtx = {
528
- rowFilter: ctx.rowFilter,
529
- colFilter: instance.filter,
530
- rowPath: ctx.rowPath,
531
- colPath: [...ctx.colPath, instance.index]
532
- };
533
- const width = this.colInstanceWidth(rootAddr, instanceCtx);
534
- const range = createRange({
535
- row: physRowStart,
536
- col: physColStart + totalColSpan
537
- }, {
538
- row: physRowStart,
539
- col: physColStart + totalColSpan + width - 1
540
- });
541
- placements.push(this.makePlacement(rootAddr, range, instanceCtx, rootBinding, rootBinding.aggregate === "list" ? instance.index : 0, mergeSpanEnabled(rootBinding)));
542
- totalColSpan += width;
543
- }
544
- return {
545
- rowSpan: 1,
546
- colSpan: totalColSpan,
547
- placements
548
- };
549
- }
550
- layoutNestedColBand(addr, binding, ctx, physRowStart, physColStart) {
551
- const parentAddr = binding.colParent;
552
- const parentBinding = this.index.bindingAt(parentAddr);
553
- const parentFilter = parentFilterForBinding(parentBinding, this.index, ctx.rowFilter, ctx.colFilter);
554
- const parentInstances = enumerateExpansionInstances(parentBinding, this.data, mergeFilters(parentFilter, ctx.colFilter));
555
- const placements = [];
556
- let colOffset = 0;
557
- for (const parentInstance of parentInstances) {
558
- const bandCtx = {
559
- ...ctx,
560
- colFilter: parentInstance.filter,
561
- colPath: [...ctx.colPath, parentInstance.index]
562
- };
563
- const childFilter = parentFilterForBinding(binding, this.index, bandCtx.rowFilter, bandCtx.colFilter);
564
- const childInstances = enumerateExpansionInstances(binding, this.data, mergeFilters(childFilter, bandCtx.colFilter));
565
- for (const childInstance of childInstances) {
566
- const childCtx = {
567
- ...bandCtx,
568
- colFilter: childInstance.filter,
569
- colPath: [...bandCtx.colPath, childInstance.index]
570
- };
571
- placements.push(this.makePlacement(addr, singleCellRange(physRowStart, physColStart + colOffset), childCtx, binding, 0, false));
572
- colOffset++;
573
- }
574
- }
575
- return {
576
- rowSpan: 1,
577
- colSpan: colOffset,
578
- placements
579
- };
580
- }
581
- colInstanceWidth(rootAddr, ctx) {
582
- const nestedChild = findNestedColChild(rootAddr, this.index);
583
- if (nestedChild) {
584
- const binding = this.index.bindingAt(nestedChild);
585
- const parentFilter = parentFilterForBinding(binding, this.index, ctx.rowFilter, ctx.colFilter);
586
- const instances = enumerateExpansionInstances(binding, this.data, mergeFilters(parentFilter, ctx.colFilter));
587
- return Math.max(instances.length, 1);
588
- }
589
- if (!mergeSpanEnabled(this.index.bindingAt(rootAddr))) return 1;
590
- let width = 0;
591
- for (const col of colSubtreeCols(rootAddr, this.index)) {
592
- if (col <= rootAddr.col) continue;
593
- if (this.index.bindingAt({
594
- row: rootAddr.row,
595
- col
596
- }) || this.index.cellAt({
597
- row: rootAddr.row,
598
- col
599
- })) width++;
600
- }
601
- return Math.max(width, 1);
602
- }
603
- layoutColParentAlignedCell(addr, binding, ctx, physRowStart, physColStart, rowSpan) {
604
- const colParent = binding.colParent;
605
- const parentBinding = this.index.bindingAt(colParent);
606
- const parentFilter = parentFilterForBinding(parentBinding, this.index, ctx.rowFilter, ctx.colFilter);
607
- const instances = enumerateExpansionInstances(parentBinding, this.data, mergeFilters(parentFilter, ctx.colFilter));
608
- if (instances.length === 0) return {
609
- rowSpan: 0,
610
- colSpan: 0,
611
- placements: []
612
- };
613
- const placements = [];
614
- let colOffset = 0;
615
- for (const instance of instances) {
616
- const instanceCtx = {
617
- rowFilter: ctx.rowFilter,
618
- colFilter: instance.filter,
619
- rowPath: ctx.rowPath,
620
- colPath: [...ctx.colPath, instance.index]
621
- };
622
- const width = this.colInstanceWidth(colParent, instanceCtx);
623
- placements.push(this.makePlacement(addr, expandRows(singleCellRange(physRowStart, physColStart + colOffset), rowSpan), instanceCtx, binding, 0, mergeSpanEnabled(binding) && rowSpan > 1));
624
- colOffset += width;
625
- }
626
- return {
627
- rowSpan: 0,
628
- colSpan: colOffset,
629
- placements
630
- };
631
- }
632
- isInlineColChild(row, col) {
633
- const binding = this.index.bindingAt({
634
- row,
635
- col
636
- });
637
- if (!binding?.colParent) return false;
638
- const parent = this.index.bindingAt(binding.colParent);
639
- if (!parent || !isColExpanding(parent)) return false;
640
- return binding.colParent.row === row;
641
- }
642
- listInstanceCountOnRow(templateRow, ctx) {
643
- let count = 0;
644
- for (const entry of this.index.bindingsOnRow(templateRow)) {
645
- if (!isRowExpanding(entry.binding) || entry.binding.aggregate !== "list") continue;
646
- const parentFilter = parentFilterForBinding(entry.binding, this.index, ctx.rowFilter, ctx.colFilter);
647
- const instances = enumerateExpansionInstances(entry.binding, this.data, mergeFilters(parentFilter, ctx.rowFilter));
648
- count = Math.max(count, instances.length);
649
- }
650
- return count;
651
- }
652
- rowLogicalColOffsets(templateRow, physColStart) {
653
- const offsets = /* @__PURE__ */ new Map();
654
- let physCol = physColStart;
655
- for (const col of columnsOnRow(this.index, templateRow)) {
656
- offsets.set(col, physCol);
657
- physCol++;
658
- }
659
- return offsets;
660
- }
661
- makePlacement(logical, physical, ctx, binding, listIndex, mergeSpan) {
662
- return {
663
- logical,
664
- physical,
665
- rowPath: ctx.rowPath,
666
- colPath: ctx.colPath,
667
- mergeSpan,
668
- binding,
669
- listIndex
670
- };
671
- }
672
- };
673
- function emptyCtx() {
674
- return {
675
- rowFilter: {},
676
- colFilter: {},
677
- rowPath: [],
678
- colPath: []
679
- };
680
- }
681
- function expandRows(range, rowSpan) {
682
- if (rowSpan <= 1) return range;
683
- return createRange(range.start, {
684
- row: range.start.row + rowSpan - 1,
685
- col: range.end.col
686
- });
687
- }
688
- /** 将模板合并区域映射到物理网格(基于锚点格的物理落点) */
689
- function mapTemplateMerges(index, placements) {
690
- const layout = {
691
- rowCount: 0,
692
- colCount: 0,
693
- placements,
694
- mappedMerges: []
695
- };
696
- const mapped = [];
697
- for (const merge of index.merges) {
698
- const mappedRange = mapLogicalMerge(merge, layout);
699
- if (mappedRange) mapped.push(mappedRange);
700
- }
701
- return mapped;
702
- }
703
- function mapLogicalMerge(merge, layout) {
704
- const startHits = placementsAt(layout, merge.start);
705
- if (startHits.length === 0) return null;
706
- const startPlacement = startHits[0];
707
- const endHits = placementsAt(layout, merge.end);
708
- if (endHits.length > 0) return createRange(startPlacement.physical.start, endHits[endHits.length - 1].physical.end);
709
- const logicalRowSpan = merge.end.row - merge.start.row;
710
- const logicalColSpan = merge.end.col - merge.start.col;
711
- return createRange(startPlacement.physical.start, {
712
- row: startPlacement.physical.start.row + logicalRowSpan,
713
- col: startPlacement.physical.start.col + logicalColSpan
714
- });
715
- }
716
- /** 计算扩展坐标系:逻辑格 → 物理区间映射(纯计算、无快照输出) */
717
- function computeExpansionLayout(index, data) {
718
- return new CoordinateEngine(index, data).compute();
719
- }
720
- /** 按逻辑地址查找全部物理落点 */
721
- function placementsAt(layout, addr) {
722
- return layout.placements.filter((p) => sameAddress(p.logical, addr));
723
- }
724
- /** 物理区间行高(含合并) */
725
- function physicalRowSpan(placement) {
726
- return rangeRows(placement.physical);
727
- }
728
- /** 物理区间列宽(含合并) */
729
- function physicalColSpan(placement) {
730
- return rangeCols(placement.physical);
731
- }
732
- //#endregion
733
- export { computeExpansionLayout, enumerateExpansionInstances, mapTemplateMerges, physicalColSpan, physicalRowSpan, placementsAt };