@a3s-lab/office 0.34.0 → 0.36.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/3266.js CHANGED
@@ -1,10 +1,178 @@
1
+ import { formulaHasStructuredReference, sparseArrayEntries as spreadsheet_sparse_sparseArrayEntries, formulaHasExternalReference, spreadsheetFormulaFunctions, editableSpreadsheetFormula, isValidSpreadsheetDefinedName } from "./8715.js";
1
2
  import { workOfficeCollaborationJsonEqual, canonicalWorkOfficeCollaborationJson, isWorkOfficeCollaborationRecord, cloneWorkOfficeCollaborationJson } from "./4650.js";
2
3
  import { initializeWorkOfficeCollaborationMetadata, assertWorkOfficeCollaborationEditable, OfficeCollaborationError as WorkOfficeCollaborationError, readOfficeCollaborationMetadata as readWorkOfficeCollaborationMetadata, registerWorkOfficeCollaborationInitializer, markWorkOfficeCollaborationInitialized, assertWorkOfficeCollaborationOrigin } from "./9787.js";
3
4
  import { directChild, directChildren, descendants, OFFICE_KERNEL_SPREADSHEET_MAX_ROWS, attribute } from "./4121.js";
4
- import { isValidSpreadsheetDefinedName, sparseArrayEntries } from "./8715.js";
5
5
  import { patchWorkOfficeCollaborationFlatJsonMap, readWorkOfficeCollaborationFlatJsonMap } from "./7060.js";
6
6
  import { resolveXlsxColor, createXlsxColorResolver, normalizeXlsxSemanticColorOrigin, xlsxPatternFillKey, XLSX_PATTERN_FILL_CELL_KEY, xlsxCellAddress, xlsxSemanticColorMatchesValue, xlsxGradientFillSemanticColors, xlsxColorElementMatchesOrigin, decodeXlsxCellAddress, xlsxSemanticColorOriginSupported, deleteXlsxPatternFill, xlsxCellStyleOrigin, xlsxRgbColor, xlsxPatternFillSemanticColors, activeXlsxGradientFill, xlsxGradientFillKey, applyXlsxSemanticColorOrigin, deleteXlsxGradientFill, XLSX_GRADIENT_FILL_CELL_KEY, readXlsxSemanticColorOrigin, activeXlsxPatternFill } from "./9333.js";
7
7
  import * as __rspack_external_yjs from "yjs";
8
+ const MAX_SPREADSHEET_TABLE_CALCULATED_FORMULA_LENGTH = 8192;
9
+ const UNSAFE_SPREADSHEET_TABLE_CALCULATED_FUNCTIONS = new Set([
10
+ 'CALL',
11
+ 'DDE',
12
+ 'DDE.REQUEST',
13
+ 'DDE.POKE',
14
+ 'EXEC',
15
+ 'HYPERLINK',
16
+ 'INDIRECT',
17
+ 'OFFSET',
18
+ 'REGISTER.ID',
19
+ 'RTD',
20
+ 'WEBSERVICE'
21
+ ]);
22
+ function normalizeSpreadsheetTableCalculatedFormula(value) {
23
+ if ('string' != typeof value) return;
24
+ const trimmed = value.trim();
25
+ if (!trimmed) return;
26
+ const formula = trimmed.startsWith('=') ? trimmed : `=${trimmed}`;
27
+ if (formula.startsWith('==') || formula.length > MAX_SPREADSHEET_TABLE_CALCULATED_FORMULA_LENGTH || /[\u0000-\u001f\u007f]/u.test(formula) || formulaHasExternalReference(formula) || !formulaHasStructuredReference(formula) || spreadsheetFormulaFunctions(formula).some((name)=>UNSAFE_SPREADSHEET_TABLE_CALCULATED_FUNCTIONS.has(name))) return;
28
+ const editable = editableSpreadsheetFormula(formula).trim();
29
+ return editable || void 0;
30
+ }
31
+ function reconcileSpreadsheetTableCalculatedColumns(sheet, table) {
32
+ return table.columns.map((column, offset)=>{
33
+ const declared = normalizeSpreadsheetTableCalculatedFormula(column.calculatedFormula);
34
+ const observed = spreadsheetTableCurrentRowFormulas(sheet, table, offset);
35
+ const uniqueObserved = new Set(observed);
36
+ if (uniqueObserved.size > 1) return stripCalculatedFormula(column);
37
+ const inferred = uniqueObserved.values().next().value;
38
+ if (declared && inferred && declared !== inferred) return stripCalculatedFormula(column);
39
+ if (declared) return {
40
+ ...column,
41
+ calculatedFormula: declared
42
+ };
43
+ return inferred ? {
44
+ ...column,
45
+ calculatedFormula: inferred
46
+ } : stripCalculatedFormula(column);
47
+ });
48
+ }
49
+ function isSpreadsheetTableCalculatedFormula(value) {
50
+ const formula = normalizeSpreadsheetTableCalculatedFormula(value);
51
+ return Boolean(formula && hasCurrentRowReference(formula));
52
+ }
53
+ function fillSpreadsheetTableCalculatedColumns(sheet, table, rows) {
54
+ const targetRows = Array.from(new Set(rows.filter((row)=>Number.isSafeInteger(row) && row >= table.range.row[0] + Number(table.headerRow) && row <= table.range.row[1] - Number(table.totalsRow)))).sort((left, right)=>left - right);
55
+ if (!targetRows.length) return sheet;
56
+ const formulas = table.columns.map((column)=>isSpreadsheetTableCalculatedFormula(column.calculatedFormula) ? normalizeSpreadsheetTableCalculatedFormula(column.calculatedFormula) : void 0);
57
+ if (!formulas.some(Boolean)) return sheet;
58
+ if (void 0 !== sheet.data) {
59
+ const data = sheet.data.slice();
60
+ const mutableRows = new Map();
61
+ let changed = false;
62
+ for (const rowIndex of targetRows){
63
+ const sourceRow = data[rowIndex];
64
+ let row = mutableRows.get(rowIndex);
65
+ for(let offset = 0; offset < formulas.length; offset += 1){
66
+ const formula = formulas[offset];
67
+ if (!formula) continue;
68
+ const column = table.range.column[0] + offset;
69
+ const current = sourceRow?.[column] ?? null;
70
+ if (!spreadsheetTableCellIsEmpty(current)) continue;
71
+ row ??= cloneSpreadsheetTableRow(sourceRow);
72
+ mutableRows.set(rowIndex, row);
73
+ const styleSource = current ?? nearestSpreadsheetTableCell(sheet, table, rowIndex, column);
74
+ row[column] = spreadsheetCellWithCalculatedFormula(styleSource, formula);
75
+ changed = true;
76
+ }
77
+ if (row) data[rowIndex] = row;
78
+ }
79
+ return changed ? {
80
+ ...sheet,
81
+ data
82
+ } : sheet;
83
+ }
84
+ const entries = [
85
+ ...sheet.celldata ?? []
86
+ ];
87
+ const byCoordinate = new Map(entries.map((entry, index)=>[
88
+ `${entry.r}:${entry.c}`,
89
+ index
90
+ ]));
91
+ let changed = false;
92
+ for (const row of targetRows)for(let offset = 0; offset < formulas.length; offset += 1){
93
+ const formula = formulas[offset];
94
+ if (!formula) continue;
95
+ const column = table.range.column[0] + offset;
96
+ const key = `${row}:${column}`;
97
+ const index = byCoordinate.get(key);
98
+ const current = void 0 === index ? null : entries[index]?.v;
99
+ if (!spreadsheetTableCellIsEmpty(current)) continue;
100
+ const styleSource = current ?? nearestSpreadsheetTableCell(sheet, table, row, column);
101
+ const entry = {
102
+ r: row,
103
+ c: column,
104
+ v: spreadsheetCellWithCalculatedFormula(styleSource, formula)
105
+ };
106
+ if (void 0 === index) {
107
+ byCoordinate.set(key, entries.length);
108
+ entries.push(entry);
109
+ } else entries[index] = entry;
110
+ changed = true;
111
+ }
112
+ if (!changed) return sheet;
113
+ entries.sort((left, right)=>left.r - right.r || left.c - right.c);
114
+ return {
115
+ ...sheet,
116
+ celldata: entries
117
+ };
118
+ }
119
+ function spreadsheetTableCellAt(sheet, row, column) {
120
+ return sheet.data?.[row]?.[column] ?? sheet.celldata?.find((entry)=>entry.r === row && entry.c === column)?.v ?? null;
121
+ }
122
+ function spreadsheetTableCellIsEmpty(cell) {
123
+ return !cell?.f && (cell?.v === void 0 || null === cell.v || '' === cell.v) && (cell?.m === void 0 || null === cell.m || '' === cell.m);
124
+ }
125
+ function spreadsheetCellWithCalculatedFormula(source, formula) {
126
+ const { f: _formula, m: _display, v: _value, ...presentation } = source ?? {};
127
+ return {
128
+ ...presentation,
129
+ f: formula
130
+ };
131
+ }
132
+ function stripCalculatedFormula(column) {
133
+ if (void 0 === column.calculatedFormula) return column;
134
+ const { calculatedFormula: _formula, ...withoutFormula } = column;
135
+ return withoutFormula;
136
+ }
137
+ function hasCurrentRowReference(formula) {
138
+ const source = formula.replace(/"(?:[^"]|"")*"/g, '""');
139
+ return /\[@/i.test(source) || /\[#This Row\]/i.test(source);
140
+ }
141
+ function spreadsheetTableCurrentRowFormulas(sheet, table, columnOffset) {
142
+ const startRow = table.range.row[0] + Number(table.headerRow);
143
+ const endRow = table.range.row[1] - Number(table.totalsRow);
144
+ const column = table.range.column[0] + columnOffset;
145
+ const formulas = [];
146
+ for(let row = startRow; row <= endRow; row += 1){
147
+ const formula = normalizeSpreadsheetTableCalculatedFormula(spreadsheetTableCellAt(sheet, row, column)?.f);
148
+ if (formula && hasCurrentRowReference(formula)) formulas.push(formula);
149
+ }
150
+ return formulas;
151
+ }
152
+ function cloneSpreadsheetTableRow(source) {
153
+ const row = [];
154
+ if (!source) return row;
155
+ row.length = source.length;
156
+ for (const column of spreadsheet_sparse_sparseArrayEntries(source).map(([index])=>index))row[column] = source[column];
157
+ return row;
158
+ }
159
+ function nearestSpreadsheetTableCell(sheet, table, row, column) {
160
+ const start = table.range.row[0] + Number(table.headerRow);
161
+ const end = table.range.row[1] - Number(table.totalsRow);
162
+ for(let distance = 1; distance <= end - start; distance += 1){
163
+ const before = row - distance;
164
+ if (before >= start) {
165
+ const cell = spreadsheetTableCellAt(sheet, before, column);
166
+ if (cell) return cell;
167
+ }
168
+ const after = row + distance;
169
+ if (after <= end) {
170
+ const cell = spreadsheetTableCellAt(sheet, after, column);
171
+ if (cell) return cell;
172
+ }
173
+ }
174
+ return null;
175
+ }
8
176
  function requiredCoordinate(value, maximum, label, sheetId) {
9
177
  if (!Number.isSafeInteger(value) || value < 0 || value >= maximum) invalidWorkOfficeSpreadsheetInput(`a valid ${label} coordinate in sheet '${sheetId}'`);
10
178
  return value;
@@ -258,18 +426,29 @@ function requiredSpreadsheetTableColumns(value, width, label) {
258
426
  const names = new Set();
259
427
  return value.map((candidate)=>{
260
428
  const record = requiredInputRecord(candidate, `${label} column`);
261
- assertExactRecordKeys(record, [
262
- 'name'
429
+ assertOptionalRecordKeys(record, [
430
+ 'name',
431
+ 'calculatedFormula'
263
432
  ], `column for ${label}`);
264
433
  const name = requiredTableColumnName(record.name, label);
265
434
  const normalized = name.toLocaleLowerCase();
266
435
  if (names.has(normalized)) invalidWorkOfficeSpreadsheetInput(`unique column names for ${label}`);
267
436
  names.add(normalized);
268
- return {
437
+ if (void 0 === record.calculatedFormula) return {
269
438
  name
270
439
  };
440
+ const calculatedFormula = normalizeSpreadsheetTableCalculatedFormula(record.calculatedFormula);
441
+ if (!calculatedFormula || calculatedFormula !== record.calculatedFormula) invalidWorkOfficeSpreadsheetInput(`a bounded structured calculated-column formula for ${label}`);
442
+ return {
443
+ name,
444
+ calculatedFormula
445
+ };
271
446
  });
272
447
  }
448
+ function assertOptionalRecordKeys(record, keys, label) {
449
+ const allowed = new Set(keys);
450
+ if (!Object.hasOwn(record, keys[0] ?? '') || Object.keys(record).some((key)=>!allowed.has(key))) invalidWorkOfficeSpreadsheetInput(`a complete ${label} record without unknown fields`);
451
+ }
273
452
  function requiredSpreadsheetTableFilters(value, width, label) {
274
453
  if (!Array.isArray(value)) invalidWorkOfficeSpreadsheetInput(`an array of filters for ${label}`);
275
454
  const columns = new Set();
@@ -744,7 +923,7 @@ function assertCompatibleValue(previous, next, shared, label) {
744
923
  function spreadsheetCells(sheet) {
745
924
  const result = new Map();
746
925
  if (void 0 !== sheet.data) {
747
- for (const [row, values] of sparseArrayEntries(sheet.data))for (const [column, cell] of sparseArrayEntries(values))if (null !== cell) result.set(`${row}:${column}`, cell);
926
+ for (const [row, values] of spreadsheet_sparse_sparseArrayEntries(sheet.data))for (const [column, cell] of spreadsheet_sparse_sparseArrayEntries(values))if (null !== cell) result.set(`${row}:${column}`, cell);
748
927
  return result;
749
928
  }
750
929
  for (const entry of sheet.celldata ?? [])if (null !== entry.v) result.set(`${entry.r}:${entry.c}`, entry.v);
@@ -854,7 +1033,7 @@ function spreadsheetCellEntries(sheet) {
854
1033
  if (!sheet) return [];
855
1034
  const entries = [];
856
1035
  if (void 0 !== sheet.data) {
857
- for (const [row, values] of sparseArrayEntries(sheet.data))for (const [column, cell] of sparseArrayEntries(values))if (null !== cell) entries.push({
1036
+ for (const [row, values] of spreadsheet_sparse_sparseArrayEntries(sheet.data))for (const [column, cell] of spreadsheet_sparse_sparseArrayEntries(values))if (null !== cell) entries.push({
858
1037
  cell,
859
1038
  column,
860
1039
  coordinate: encodedCoordinate(row, column),
@@ -2216,12 +2395,12 @@ function xlsxRichTextCellText(cell) {
2216
2395
  return normalizeXlsxRichTextCell(cell)?.text ?? null;
2217
2396
  }
2218
2397
  function sheetHasXlsxRichTextCells(sheet) {
2219
- for (const [, row] of sparseArrayEntries(sheet.data))for (const [, cell] of sparseArrayEntries(row))if (cell && normalizeXlsxRichTextCell(cell)) return true;
2398
+ for (const [, row] of spreadsheet_sparse_sparseArrayEntries(sheet.data))for (const [, cell] of spreadsheet_sparse_sparseArrayEntries(row))if (cell && normalizeXlsxRichTextCell(cell)) return true;
2220
2399
  return false;
2221
2400
  }
2222
2401
  function xlsxRichTextStyleOrigins(sheet) {
2223
2402
  const origins = [];
2224
- for (const [, row] of sparseArrayEntries(sheet.data))for (const [, cell] of sparseArrayEntries(row))if (cell) for (const run of normalizeXlsxRichTextCell(cell)?.runs ?? []){
2403
+ for (const [, row] of spreadsheet_sparse_sparseArrayEntries(sheet.data))for (const [, cell] of spreadsheet_sparse_sparseArrayEntries(row))if (cell) for (const run of normalizeXlsxRichTextCell(cell)?.runs ?? []){
2225
2404
  const fontColor = normalizeXlsxSemanticColorOrigin(run.a3sXlsxColorOrigin);
2226
2405
  if (fontColor && run.fc && xlsxSemanticColorMatchesValue(fontColor, run.fc)) origins.push({
2227
2406
  fontColor
@@ -2241,7 +2420,7 @@ function writeXlsxRichTextCells(worksheet, sheet, semanticPalette) {
2241
2420
  }));
2242
2421
  let remainingCells = 10000;
2243
2422
  let remainingRuns = 100000;
2244
- for (const [row, values] of sparseArrayEntries(sheet.data))for (const [column, cell] of sparseArrayEntries(values)){
2423
+ for (const [row, values] of spreadsheet_sparse_sparseArrayEntries(sheet.data))for (const [column, cell] of spreadsheet_sparse_sparseArrayEntries(values)){
2245
2424
  if (remainingCells <= 0 || remainingRuns <= 0) return;
2246
2425
  if (!cell) continue;
2247
2426
  const richText = normalizeXlsxRichTextCell(cell);
@@ -2384,4 +2563,4 @@ function work_xlsx_rich_text_nonNegativeInteger(value) {
2384
2563
  function work_xlsx_rich_text_isRecord(value) {
2385
2564
  return 'object' == typeof value && null !== value && !Array.isArray(value);
2386
2565
  }
2387
- export { activeXlsxNativeFill, activeXlsxSemanticColorOrigin, applyImportedXlsxRichText, boundedSpreadsheetDataValidationText, coalesceXlsxRichTextRuns, createWorkOfficeSpreadsheetCollaborationBinding as createOfficeSpreadsheetCollaborationBinding, createXlsxRichTextReadContext, deleteXlsxNativeFills, directXlsxAlignment, directXlsxFontStyle, hasXlsxDirectFontStyle, initializeWorkOfficeSpreadsheetCollaboration as initializeOfficeSpreadsheetCollaboration, isHighSurrogate, isLowSurrogate, isSpreadsheetTextOrientationId, isSpreadsheetUnderlineStyle, normalizeSpreadsheetDataValidationErrorStyle, normalizeSpreadsheetDateValidationBoundary, normalizeXlsxRichTextCell, normalizeXlsxRichTextColor, normalizeXlsxRichTextEditSource, normalizeXlsxRichTextRun, patchSpreadsheetRichTextFontRuns, readWorkOfficeSpreadsheetCollaboration as readOfficeSpreadsheetCollaboration, readXlsxRichTextCells, replaceWorkOfficeSpreadsheetCollaboration as replaceOfficeSpreadsheetCollaboration, sameXlsxRichTextRunStyle, sheetHasXlsxRichTextCells, spreadsheetCellValueWithDiagonalBorder, spreadsheetDateValidationFormula, spreadsheetDiagonalBorderFromCellValue, spreadsheetExplicitTextOrientationFromCell, spreadsheetTextOrientationCellStyle, spreadsheetTextOrientationChoiceFromCell, spreadsheetTextOrientationFromAngle, spreadsheetTextOrientationFromCell, spreadsheetTextOrientationFromChoice, spreadsheetTextOrientationFromXlsx, spreadsheetUnderlineCellValue, spreadsheetUnderlineCellValueFromSheetJs, spreadsheetUnderlineCellValueFromXlsx, spreadsheetUnderlineStyle, spreadsheetVisibleTextRotationFromCell, validXlsxRichText, writeXlsxRichTextCells, xlsxAlignmentMatches, xlsxBooleanAttribute, xlsxBorderLineMatches, xlsxColorMatches, xlsxNativeFillCellKeys, xlsxNativeFillKey, xlsxNativeFillSemanticColors, xlsxRichTextCellText, xlsxRichTextStyleOrigins, xlsxStyleCollectionIndex, xlsxToggleEnabled, xlsxUnderlineStyle };
2566
+ export { activeXlsxNativeFill, activeXlsxSemanticColorOrigin, applyImportedXlsxRichText, boundedSpreadsheetDataValidationText, coalesceXlsxRichTextRuns, createWorkOfficeSpreadsheetCollaborationBinding as createOfficeSpreadsheetCollaborationBinding, createXlsxRichTextReadContext, deleteXlsxNativeFills, directXlsxAlignment, directXlsxFontStyle, fillSpreadsheetTableCalculatedColumns, hasXlsxDirectFontStyle, initializeWorkOfficeSpreadsheetCollaboration as initializeOfficeSpreadsheetCollaboration, isHighSurrogate, isLowSurrogate, isSpreadsheetTextOrientationId, isSpreadsheetUnderlineStyle, normalizeSpreadsheetDataValidationErrorStyle, normalizeSpreadsheetDateValidationBoundary, normalizeSpreadsheetTableCalculatedFormula, normalizeXlsxRichTextCell, normalizeXlsxRichTextColor, normalizeXlsxRichTextEditSource, normalizeXlsxRichTextRun, patchSpreadsheetRichTextFontRuns, readWorkOfficeSpreadsheetCollaboration as readOfficeSpreadsheetCollaboration, readXlsxRichTextCells, reconcileSpreadsheetTableCalculatedColumns, replaceWorkOfficeSpreadsheetCollaboration as replaceOfficeSpreadsheetCollaboration, sameXlsxRichTextRunStyle, sheetHasXlsxRichTextCells, spreadsheetCellValueWithDiagonalBorder, spreadsheetDateValidationFormula, spreadsheetDiagonalBorderFromCellValue, spreadsheetExplicitTextOrientationFromCell, spreadsheetTextOrientationCellStyle, spreadsheetTextOrientationChoiceFromCell, spreadsheetTextOrientationFromAngle, spreadsheetTextOrientationFromCell, spreadsheetTextOrientationFromChoice, spreadsheetTextOrientationFromXlsx, spreadsheetUnderlineCellValue, spreadsheetUnderlineCellValueFromSheetJs, spreadsheetUnderlineCellValueFromXlsx, spreadsheetUnderlineStyle, spreadsheetVisibleTextRotationFromCell, validXlsxRichText, writeXlsxRichTextCells, xlsxAlignmentMatches, xlsxBooleanAttribute, xlsxBorderLineMatches, xlsxColorMatches, xlsxNativeFillCellKeys, xlsxNativeFillKey, xlsxNativeFillSemanticColors, xlsxRichTextCellText, xlsxRichTextStyleOrigins, xlsxStyleCollectionIndex, xlsxToggleEnabled, xlsxUnderlineStyle };
package/dist/4121.js CHANGED
@@ -2905,6 +2905,13 @@ const WORK_TEMPLATES = [
2905
2905
  description: '下拉列表、输入提示与错误警告',
2906
2906
  accent: '#13795b'
2907
2907
  },
2908
+ {
2909
+ id: 'structured-references',
2910
+ kind: 'spreadsheet',
2911
+ name: '结构化引用',
2912
+ description: '表名、当前行公式与插入行自动填充',
2913
+ accent: '#0f7b61'
2914
+ },
2908
2915
  {
2909
2916
  id: 'blank-presentation',
2910
2917
  kind: 'presentation',
@@ -2958,6 +2965,7 @@ function initialTitle(templateId, kind) {
2958
2965
  'proofing-languages': '校对语言示例',
2959
2966
  'quarterly-plan': '季度执行计划',
2960
2967
  'data-validation': '数据验证示例',
2968
+ 'structured-references': '结构化引用示例',
2961
2969
  'strategy-deck': '业务策略汇报',
2962
2970
  'animated-deck': '入场动画示例'
2963
2971
  };
@@ -3257,6 +3265,10 @@ function contentForTemplate(templateId) {
3257
3265
  type: 'spreadsheet',
3258
3266
  sheets: dataValidationTemplateSheets()
3259
3267
  };
3268
+ if ('structured-references' === templateId) return {
3269
+ type: 'spreadsheet',
3270
+ sheets: structuredReferenceTemplateSheets()
3271
+ };
3260
3272
  if ('strategy-deck' === templateId) return strategyPresentation();
3261
3273
  if ('animated-deck' === templateId) return animatedPresentation();
3262
3274
  if ('blank-spreadsheet' === templateId) return {
@@ -3609,6 +3621,251 @@ function dataValidationTemplateSheets() {
3609
3621
  }
3610
3622
  ];
3611
3623
  }
3624
+ function structuredReferenceTemplateSheets() {
3625
+ const sales = emptyMatrix(16, 10);
3626
+ sales[0][0] = styledCell('Sales · 结构化引用', {
3627
+ bl: 1,
3628
+ fs: 16,
3629
+ fc: '#ffffff',
3630
+ bg: '#0f7b61'
3631
+ });
3632
+ sales[1][0] = styledCell('插入表格正文行会自动补齐 Revenue;已填写的手工值不会覆盖。', {
3633
+ fc: '#49645c',
3634
+ fs: 10
3635
+ });
3636
+ [
3637
+ 'Item',
3638
+ 'Units',
3639
+ 'Unit price',
3640
+ 'Revenue'
3641
+ ].forEach((value, column)=>{
3642
+ sales[2][column] = headerCell(value);
3643
+ });
3644
+ const rows = [
3645
+ [
3646
+ 'Landing page',
3647
+ 12,
3648
+ 48,
3649
+ '=[@Units]*[@[Unit price]]'
3650
+ ],
3651
+ [
3652
+ 'API integration',
3653
+ 8,
3654
+ 120,
3655
+ '=[@Units]*[@[Unit price]]'
3656
+ ],
3657
+ [
3658
+ 'QA review',
3659
+ 16,
3660
+ 36,
3661
+ '=[@Units]*[@[Unit price]]'
3662
+ ],
3663
+ [
3664
+ 'Release support',
3665
+ 5,
3666
+ 80,
3667
+ '=[@Units]*[@[Unit price]]'
3668
+ ]
3669
+ ];
3670
+ rows.forEach((row, rowIndex)=>{
3671
+ row.forEach((value, columnIndex)=>{
3672
+ sales[rowIndex + 3][columnIndex] = styledCell(value, {
3673
+ bg: rowIndex % 2 ? '#f3faf7' : '#ffffff',
3674
+ ...columnIndex >= 1 ? {
3675
+ ct: {
3676
+ fa: 1 === columnIndex ? '0' : '#,##0.00',
3677
+ t: 'n'
3678
+ }
3679
+ } : {}
3680
+ });
3681
+ });
3682
+ });
3683
+ sales[7][0] = styledCell('Total', {
3684
+ bl: 1,
3685
+ fc: '#215446',
3686
+ bg: '#dff3ec'
3687
+ });
3688
+ sales[7][1] = styledCell('=SUM(Sales[Units])', {
3689
+ bl: 1,
3690
+ fc: '#215446',
3691
+ bg: '#dff3ec',
3692
+ ct: {
3693
+ fa: '0',
3694
+ t: 'n'
3695
+ }
3696
+ });
3697
+ sales[7][3] = styledCell('=SUM(Sales[Revenue])', {
3698
+ bl: 1,
3699
+ fc: '#215446',
3700
+ bg: '#dff3ec',
3701
+ ct: {
3702
+ fa: '#,##0.00',
3703
+ t: 'n'
3704
+ }
3705
+ });
3706
+ sales[9][0] = styledCell('Reference examples', {
3707
+ bl: 1,
3708
+ fc: '#215446'
3709
+ });
3710
+ sales[10][0] = styledCell('Headers count');
3711
+ sales[10][1] = styledCell('=COUNTA(Sales[#Headers])', {
3712
+ ct: {
3713
+ fa: '0',
3714
+ t: 'n'
3715
+ }
3716
+ });
3717
+ sales[11][0] = styledCell('Data revenue');
3718
+ sales[11][1] = styledCell('=SUM(Sales[Revenue])', {
3719
+ ct: {
3720
+ fa: '#,##0.00',
3721
+ t: 'n'
3722
+ }
3723
+ });
3724
+ sales[12][0] = styledCell('Units + prices');
3725
+ sales[12][1] = styledCell('=SUM(Sales[[Units]:[Unit price]])', {
3726
+ ct: {
3727
+ fa: '#,##0.00',
3728
+ t: 'n'
3729
+ }
3730
+ });
3731
+ sales[13][0] = styledCell('All table cells');
3732
+ sales[13][1] = styledCell('=COUNTA(Sales[#All])', {
3733
+ ct: {
3734
+ fa: '0',
3735
+ t: 'n'
3736
+ }
3737
+ });
3738
+ const table = {
3739
+ id: createWorkId('spreadsheet-table'),
3740
+ name: 'Sales',
3741
+ displayName: 'SalesData',
3742
+ range: {
3743
+ row: [
3744
+ 2,
3745
+ 7
3746
+ ],
3747
+ column: [
3748
+ 0,
3749
+ 3
3750
+ ]
3751
+ },
3752
+ columns: [
3753
+ {
3754
+ name: 'Item'
3755
+ },
3756
+ {
3757
+ name: 'Units'
3758
+ },
3759
+ {
3760
+ name: 'Unit price'
3761
+ },
3762
+ {
3763
+ name: 'Revenue',
3764
+ calculatedFormula: '=[@Units]*[@[Unit price]]'
3765
+ }
3766
+ ],
3767
+ filters: [],
3768
+ headerRow: true,
3769
+ totalsRow: true,
3770
+ style: {
3771
+ family: 'medium',
3772
+ number: 4
3773
+ },
3774
+ showFirstColumn: false,
3775
+ showLastColumn: false,
3776
+ showRowStripes: true,
3777
+ showColumnStripes: false
3778
+ };
3779
+ const salesSheet = {
3780
+ id: createWorkId('sheet'),
3781
+ name: 'Sales',
3782
+ status: 1,
3783
+ order: 0,
3784
+ row: 16,
3785
+ column: 10,
3786
+ data: sales,
3787
+ tables: [
3788
+ table
3789
+ ],
3790
+ config: {
3791
+ columnlen: {
3792
+ 0: 172,
3793
+ 1: 76,
3794
+ 2: 102,
3795
+ 3: 112
3796
+ },
3797
+ rowlen: {
3798
+ 0: 32,
3799
+ 1: 24,
3800
+ 2: 28,
3801
+ 7: 28
3802
+ },
3803
+ merge: {
3804
+ '0_0': {
3805
+ r: 0,
3806
+ c: 0,
3807
+ rs: 1,
3808
+ cs: 4
3809
+ }
3810
+ }
3811
+ }
3812
+ };
3813
+ const summary = emptyMatrix(10, 4);
3814
+ summary[0][0] = styledCell('Summary · qualified references', {
3815
+ bl: 1,
3816
+ fs: 16,
3817
+ fc: '#ffffff',
3818
+ bg: '#215446'
3819
+ });
3820
+ summary[2][0] = styledCell('Revenue from Sales table');
3821
+ summary[2][1] = styledCell('=SUM(Sales!Sales[Revenue])', {
3822
+ ct: {
3823
+ fa: '#,##0.00',
3824
+ t: 'n'
3825
+ }
3826
+ });
3827
+ summary[3][0] = styledCell('Headers from Sales table');
3828
+ summary[3][1] = styledCell('=COUNTA(Sales!Sales[#Headers])', {
3829
+ ct: {
3830
+ fa: '0',
3831
+ t: 'n'
3832
+ }
3833
+ });
3834
+ summary[5][0] = styledCell('Sales!Sales[...] demonstrates a worksheet-qualified table reference.', {
3835
+ fc: '#49645c',
3836
+ fs: 10
3837
+ });
3838
+ return [
3839
+ salesSheet,
3840
+ {
3841
+ id: createWorkId('sheet'),
3842
+ name: 'Summary',
3843
+ status: 0,
3844
+ order: 1,
3845
+ row: 10,
3846
+ column: 4,
3847
+ data: summary,
3848
+ config: {
3849
+ columnlen: {
3850
+ 0: 240,
3851
+ 1: 120
3852
+ },
3853
+ rowlen: {
3854
+ 0: 32,
3855
+ 5: 28
3856
+ },
3857
+ merge: {
3858
+ '0_0': {
3859
+ r: 0,
3860
+ c: 0,
3861
+ rs: 1,
3862
+ cs: 2
3863
+ }
3864
+ }
3865
+ }
3866
+ }
3867
+ ];
3868
+ }
3612
3869
  function dataValidationTemplateItem(overrides) {
3613
3870
  return {
3614
3871
  type: 'dropdown',