@a3s-lab/office 0.15.0 → 0.17.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.
Files changed (35) hide show
  1. package/COLLABORATION_ROADMAP.md +15 -5
  2. package/README.md +28 -2
  3. package/dist/0~6090.js +7 -8
  4. package/dist/0~spreadsheet-editor.js +2347 -406
  5. package/dist/2180.js +370 -34
  6. package/dist/4104.js +657 -22
  7. package/dist/5184.js +1 -1
  8. package/dist/8715.js +156 -156
  9. package/dist/internal/collaboration/office-spreadsheet-collaboration-records.d.ts +2 -0
  10. package/dist/internal/collaboration/office-spreadsheet-collaboration-validation-support.d.ts +6 -0
  11. package/dist/internal/features/work/editors/spreadsheet-auto-filter.d.ts +1 -0
  12. package/dist/internal/features/work/editors/spreadsheet-command-catalog.d.ts +59 -1
  13. package/dist/internal/features/work/editors/spreadsheet-command-controller.d.ts +12 -0
  14. package/dist/internal/features/work/editors/spreadsheet-editor-ribbon.d.ts +4 -2
  15. package/dist/internal/features/work/editors/spreadsheet-font-size-command.d.ts +18 -0
  16. package/dist/internal/features/work/editors/spreadsheet-font-size.d.ts +4 -0
  17. package/dist/internal/features/work/editors/spreadsheet-table-command.d.ts +3 -0
  18. package/dist/internal/features/work/editors/spreadsheet-table-conversion.d.ts +7 -0
  19. package/dist/internal/features/work/editors/spreadsheet-table-dialog.d.ts +8 -0
  20. package/dist/internal/features/work/editors/spreadsheet-table-limits.d.ts +1 -0
  21. package/dist/internal/features/work/editors/spreadsheet-table-reconciliation.d.ts +21 -0
  22. package/dist/internal/features/work/editors/spreadsheet-table-render.d.ts +16 -0
  23. package/dist/internal/features/work/editors/spreadsheet-table-ribbon.d.ts +8 -0
  24. package/dist/internal/features/work/editors/spreadsheet-table-style.d.ts +31 -0
  25. package/dist/internal/features/work/editors/spreadsheet-table.d.ts +55 -0
  26. package/dist/internal/features/work/editors/use-spreadsheet-table.d.ts +23 -0
  27. package/dist/internal/features/work/work-types.d.ts +100 -0
  28. package/dist/internal/features/work/work-xlsx-interop.d.ts +2 -0
  29. package/dist/internal/features/work/work-xlsx-table-filters.d.ts +3 -0
  30. package/dist/internal/features/work/work-xlsx-tables.d.ts +4 -0
  31. package/dist/office-kernel.wasm +0 -0
  32. package/dist/styles.css +204 -3
  33. package/dist/work-spreadsheet-package-scan.worker.js +3 -2
  34. package/docs/latest/en/browser-editor-architecture.md +43 -0
  35. package/package.json +6 -1
package/dist/5184.js CHANGED
@@ -25,7 +25,7 @@ const WORK_TEMPLATES = [
25
25
  id: 'blank-spreadsheet',
26
26
  kind: 'spreadsheet',
27
27
  name: '空白表格',
28
- description: '公式、筛选与多工作表',
28
+ description: '公式、表格、筛选与多工作表',
29
29
  accent: '#16a36a'
30
30
  },
31
31
  {
package/dist/8715.js CHANGED
@@ -1,4 +1,160 @@
1
1
  import { createOfficeId as createWorkId, directChild, attribute } from "./5184.js";
2
+ const CELL_REFERENCE = /\$?([A-Z]{1,3})\$?([1-9]\d*)/i;
3
+ const CELL_OR_RANGE = new RegExp(`^${CELL_REFERENCE.source}(?::${CELL_REFERENCE.source})?$`, 'i');
4
+ const COLUMN_RANGE = /^\$?([A-Z]{1,3}):\$?([A-Z]{1,3})$/i;
5
+ const ROW_RANGE = /^\$?([1-9]\d*):\$?([1-9]\d*)$/;
6
+ const DEFINED_NAME = /^[\p{L}_\\][\p{L}\p{N}_.\\]*$/u;
7
+ function isValidSpreadsheetDefinedName(value) {
8
+ const name = value.trim();
9
+ if (!name || Array.from(name).length > 255 || !DEFINED_NAME.test(name) || /^_xlnm\./i.test(name)) return false;
10
+ if (/^[A-Z]{1,3}[1-9]\d*$/i.test(name) || /^R\d+C\d+$/i.test(name)) return false;
11
+ return true;
12
+ }
13
+ function normalizeSpreadsheetPrintArea(value) {
14
+ const parts = splitRangeList(value.trim().replace(/^=/, ''));
15
+ if (!parts.length) return null;
16
+ const normalized = parts.map((part)=>{
17
+ const reference = unqualifiedReference(part);
18
+ if (!CELL_OR_RANGE.test(reference) && !COLUMN_RANGE.test(reference) && !ROW_RANGE.test(reference)) return null;
19
+ return reference.replace(/[A-Z]+/gi, (column)=>column.toUpperCase());
20
+ });
21
+ return normalized.every((part)=>Boolean(part)) ? normalized.join(',') : null;
22
+ }
23
+ function normalizeSpreadsheetPrintTitleRows(value) {
24
+ const match = ROW_RANGE.exec(unqualifiedReference(value.trim().replace(/^=/, '')));
25
+ if (!match) return null;
26
+ const start = Number(match[1]);
27
+ const end = Number(match[2]);
28
+ return `$${Math.min(start, end)}:$${Math.max(start, end)}`;
29
+ }
30
+ function normalizeSpreadsheetPrintTitleColumns(value) {
31
+ const match = COLUMN_RANGE.exec(unqualifiedReference(value.trim().replace(/^=/, '')));
32
+ if (!match) return null;
33
+ const start = decodeColumn(match[1]);
34
+ const end = decodeColumn(match[2]);
35
+ return `$${encodeColumn(Math.min(start, end))}:$${encodeColumn(Math.max(start, end))}`;
36
+ }
37
+ function parseSpreadsheetPrintTitles(value) {
38
+ let rows;
39
+ let columns;
40
+ for (const part of splitRangeList(value.trim().replace(/^=/, ''))){
41
+ const rowReference = normalizeSpreadsheetPrintTitleRows(part);
42
+ if (rowReference) {
43
+ if (rows) return null;
44
+ const match = ROW_RANGE.exec(rowReference);
45
+ rows = [
46
+ Number(match[1]) - 1,
47
+ Number(match[2]) - 1
48
+ ];
49
+ continue;
50
+ }
51
+ const columnReference = normalizeSpreadsheetPrintTitleColumns(part);
52
+ if (!columnReference || columns) return null;
53
+ const match = COLUMN_RANGE.exec(columnReference);
54
+ columns = [
55
+ decodeColumn(match[1]),
56
+ decodeColumn(match[2])
57
+ ];
58
+ }
59
+ return rows || columns ? {
60
+ rows,
61
+ columns
62
+ } : null;
63
+ }
64
+ function parseSpreadsheetCellRanges(value) {
65
+ const parts = splitRangeList(value.trim().replace(/^=/, ''));
66
+ if (!parts.length) return null;
67
+ const ranges = parts.map((part)=>{
68
+ const cells = CELL_OR_RANGE.exec(unqualifiedReference(part));
69
+ if (!cells) return null;
70
+ const first = decodeCell(cells[1], cells[2]);
71
+ const second = cells[3] && cells[4] ? decodeCell(cells[3], cells[4]) : first;
72
+ return {
73
+ row: [
74
+ Math.min(first.row, second.row),
75
+ Math.max(first.row, second.row)
76
+ ],
77
+ column: [
78
+ Math.min(first.column, second.column),
79
+ Math.max(first.column, second.column)
80
+ ]
81
+ };
82
+ });
83
+ return ranges.every((range)=>Boolean(range)) ? ranges : null;
84
+ }
85
+ function formatSpreadsheetCellRanges(ranges) {
86
+ return ranges.map((range)=>{
87
+ const start = encodeCell(range.row[0], range.column[0]);
88
+ const end = encodeCell(range.row[1], range.column[1]);
89
+ return start === end ? start : `${start}:${end}`;
90
+ }).join(',');
91
+ }
92
+ function qualifySpreadsheetRange(value, sheetName) {
93
+ const prefix = `'${sheetName.replaceAll("'", "''")}'!`;
94
+ return splitRangeList(value).map((part)=>part.includes('!') ? part.trim() : `${prefix}${part.trim()}`).join(',');
95
+ }
96
+ function stripSpreadsheetSheetQualifier(value, sheetName) {
97
+ const quotedPrefix = `'${sheetName.replaceAll("'", "''")}'!`;
98
+ const plainPrefix = `${sheetName}!`;
99
+ return splitRangeList(value.trim().replace(/^=/, '')).map((part)=>{
100
+ const reference = part.trim();
101
+ if (reference.toLowerCase().startsWith(quotedPrefix.toLowerCase())) return reference.slice(quotedPrefix.length);
102
+ if (reference.toLowerCase().startsWith(plainPrefix.toLowerCase())) return reference.slice(plainPrefix.length);
103
+ return reference;
104
+ }).join(',');
105
+ }
106
+ function splitRangeList(value) {
107
+ const parts = [];
108
+ let current = '';
109
+ let quoted = false;
110
+ for(let index = 0; index < value.length; index += 1){
111
+ const character = value[index];
112
+ if ("'" === character) {
113
+ if (quoted && "'" === value[index + 1]) {
114
+ current += "''";
115
+ index += 1;
116
+ continue;
117
+ }
118
+ quoted = !quoted;
119
+ }
120
+ if (',' !== character || quoted) current += character;
121
+ else {
122
+ if (current.trim()) parts.push(current.trim());
123
+ current = '';
124
+ }
125
+ }
126
+ if (current.trim()) parts.push(current.trim());
127
+ return parts;
128
+ }
129
+ function unqualifiedReference(value) {
130
+ const reference = value.trim().replace(/^=/, '');
131
+ const separator = reference.lastIndexOf('!');
132
+ return separator >= 0 ? reference.slice(separator + 1) : reference;
133
+ }
134
+ function decodeCell(column, row) {
135
+ return {
136
+ row: Math.max(0, Number(row) - 1),
137
+ column: decodeColumn(column)
138
+ };
139
+ }
140
+ function decodeColumn(value) {
141
+ let result = 0;
142
+ for (const character of value.toUpperCase())result = 26 * result + character.charCodeAt(0) - 64;
143
+ return Math.max(0, result - 1);
144
+ }
145
+ function encodeCell(row, column) {
146
+ return `${encodeColumn(column)}${Math.max(0, row) + 1}`;
147
+ }
148
+ function encodeColumn(column) {
149
+ let value = Math.max(0, column) + 1;
150
+ let label = '';
151
+ while(value > 0){
152
+ value -= 1;
153
+ label = String.fromCharCode(65 + value % 26) + label;
154
+ value = Math.floor(value / 26);
155
+ }
156
+ return label;
157
+ }
2
158
  function sparseArrayIndexes(values) {
3
159
  if (!values) return [];
4
160
  return Object.keys(values).flatMap((key)=>{
@@ -323,162 +479,6 @@ function formatPivotNumber(value) {
323
479
  function matchesPivotReportFilters(values, pivot) {
324
480
  return (pivot.reportFilters ?? []).every((filter)=>void 0 === filter.selectedItem || spreadsheetPivotFilterValueKey(normalizeSpreadsheetPivotFilterValue(values[filter.fieldIndex])) === spreadsheetPivotFilterValueKey(filter.selectedItem));
325
481
  }
326
- const CELL_REFERENCE = /\$?([A-Z]{1,3})\$?([1-9]\d*)/i;
327
- const CELL_OR_RANGE = new RegExp(`^${CELL_REFERENCE.source}(?::${CELL_REFERENCE.source})?$`, 'i');
328
- const COLUMN_RANGE = /^\$?([A-Z]{1,3}):\$?([A-Z]{1,3})$/i;
329
- const ROW_RANGE = /^\$?([1-9]\d*):\$?([1-9]\d*)$/;
330
- const DEFINED_NAME = /^[\p{L}_\\][\p{L}\p{N}_.\\]*$/u;
331
- function isValidSpreadsheetDefinedName(value) {
332
- const name = value.trim();
333
- if (!name || name.length > 255 || !DEFINED_NAME.test(name) || /^_xlnm\./i.test(name)) return false;
334
- if (/^[A-Z]{1,3}[1-9]\d*$/i.test(name) || /^R\d+C\d+$/i.test(name)) return false;
335
- return true;
336
- }
337
- function normalizeSpreadsheetPrintArea(value) {
338
- const parts = splitRangeList(value.trim().replace(/^=/, ''));
339
- if (!parts.length) return null;
340
- const normalized = parts.map((part)=>{
341
- const reference = unqualifiedReference(part);
342
- if (!CELL_OR_RANGE.test(reference) && !COLUMN_RANGE.test(reference) && !ROW_RANGE.test(reference)) return null;
343
- return reference.replace(/[A-Z]+/gi, (column)=>column.toUpperCase());
344
- });
345
- return normalized.every((part)=>Boolean(part)) ? normalized.join(',') : null;
346
- }
347
- function normalizeSpreadsheetPrintTitleRows(value) {
348
- const match = ROW_RANGE.exec(unqualifiedReference(value.trim().replace(/^=/, '')));
349
- if (!match) return null;
350
- const start = Number(match[1]);
351
- const end = Number(match[2]);
352
- return `$${Math.min(start, end)}:$${Math.max(start, end)}`;
353
- }
354
- function normalizeSpreadsheetPrintTitleColumns(value) {
355
- const match = COLUMN_RANGE.exec(unqualifiedReference(value.trim().replace(/^=/, '')));
356
- if (!match) return null;
357
- const start = decodeColumn(match[1]);
358
- const end = decodeColumn(match[2]);
359
- return `$${encodeColumn(Math.min(start, end))}:$${encodeColumn(Math.max(start, end))}`;
360
- }
361
- function parseSpreadsheetPrintTitles(value) {
362
- let rows;
363
- let columns;
364
- for (const part of splitRangeList(value.trim().replace(/^=/, ''))){
365
- const rowReference = normalizeSpreadsheetPrintTitleRows(part);
366
- if (rowReference) {
367
- if (rows) return null;
368
- const match = ROW_RANGE.exec(rowReference);
369
- rows = [
370
- Number(match[1]) - 1,
371
- Number(match[2]) - 1
372
- ];
373
- continue;
374
- }
375
- const columnReference = normalizeSpreadsheetPrintTitleColumns(part);
376
- if (!columnReference || columns) return null;
377
- const match = COLUMN_RANGE.exec(columnReference);
378
- columns = [
379
- decodeColumn(match[1]),
380
- decodeColumn(match[2])
381
- ];
382
- }
383
- return rows || columns ? {
384
- rows,
385
- columns
386
- } : null;
387
- }
388
- function parseSpreadsheetCellRanges(value) {
389
- const parts = splitRangeList(value.trim().replace(/^=/, ''));
390
- if (!parts.length) return null;
391
- const ranges = parts.map((part)=>{
392
- const cells = CELL_OR_RANGE.exec(unqualifiedReference(part));
393
- if (!cells) return null;
394
- const first = decodeCell(cells[1], cells[2]);
395
- const second = cells[3] && cells[4] ? decodeCell(cells[3], cells[4]) : first;
396
- return {
397
- row: [
398
- Math.min(first.row, second.row),
399
- Math.max(first.row, second.row)
400
- ],
401
- column: [
402
- Math.min(first.column, second.column),
403
- Math.max(first.column, second.column)
404
- ]
405
- };
406
- });
407
- return ranges.every((range)=>Boolean(range)) ? ranges : null;
408
- }
409
- function formatSpreadsheetCellRanges(ranges) {
410
- return ranges.map((range)=>{
411
- const start = encodeCell(range.row[0], range.column[0]);
412
- const end = encodeCell(range.row[1], range.column[1]);
413
- return start === end ? start : `${start}:${end}`;
414
- }).join(',');
415
- }
416
- function qualifySpreadsheetRange(value, sheetName) {
417
- const prefix = `'${sheetName.replaceAll("'", "''")}'!`;
418
- return splitRangeList(value).map((part)=>part.includes('!') ? part.trim() : `${prefix}${part.trim()}`).join(',');
419
- }
420
- function stripSpreadsheetSheetQualifier(value, sheetName) {
421
- const quotedPrefix = `'${sheetName.replaceAll("'", "''")}'!`;
422
- const plainPrefix = `${sheetName}!`;
423
- return splitRangeList(value.trim().replace(/^=/, '')).map((part)=>{
424
- const reference = part.trim();
425
- if (reference.toLowerCase().startsWith(quotedPrefix.toLowerCase())) return reference.slice(quotedPrefix.length);
426
- if (reference.toLowerCase().startsWith(plainPrefix.toLowerCase())) return reference.slice(plainPrefix.length);
427
- return reference;
428
- }).join(',');
429
- }
430
- function splitRangeList(value) {
431
- const parts = [];
432
- let current = '';
433
- let quoted = false;
434
- for(let index = 0; index < value.length; index += 1){
435
- const character = value[index];
436
- if ("'" === character) {
437
- if (quoted && "'" === value[index + 1]) {
438
- current += "''";
439
- index += 1;
440
- continue;
441
- }
442
- quoted = !quoted;
443
- }
444
- if (',' !== character || quoted) current += character;
445
- else {
446
- if (current.trim()) parts.push(current.trim());
447
- current = '';
448
- }
449
- }
450
- if (current.trim()) parts.push(current.trim());
451
- return parts;
452
- }
453
- function unqualifiedReference(value) {
454
- const reference = value.trim().replace(/^=/, '');
455
- const separator = reference.lastIndexOf('!');
456
- return separator >= 0 ? reference.slice(separator + 1) : reference;
457
- }
458
- function decodeCell(column, row) {
459
- return {
460
- row: Math.max(0, Number(row) - 1),
461
- column: decodeColumn(column)
462
- };
463
- }
464
- function decodeColumn(value) {
465
- let result = 0;
466
- for (const character of value.toUpperCase())result = 26 * result + character.charCodeAt(0) - 64;
467
- return Math.max(0, result - 1);
468
- }
469
- function encodeCell(row, column) {
470
- return `${encodeColumn(column)}${Math.max(0, row) + 1}`;
471
- }
472
- function encodeColumn(column) {
473
- let value = Math.max(0, column) + 1;
474
- let label = '';
475
- while(value > 0){
476
- value -= 1;
477
- label = String.fromCharCode(65 + value % 26) + label;
478
- value = Math.floor(value / 26);
479
- }
480
- return label;
481
- }
482
482
  const MAXIMUM_SOURCE_CELLS = 100000;
483
483
  const MAXIMUM_OUTPUT_CELLS = 20000;
484
484
  const MAXIMUM_XLSX_ROW = 1048575;
@@ -8,6 +8,8 @@ export declare const SPREADSHEET_RECORD_CHARTS = "charts";
8
8
  export declare const SPREADSHEET_RECORD_CHART_ORDER = "chartOrder";
9
9
  export declare const SPREADSHEET_RECORD_PIVOTS = "pivotTables";
10
10
  export declare const SPREADSHEET_RECORD_PIVOT_ORDER = "pivotOrder";
11
+ export declare const SPREADSHEET_RECORD_TABLES = "tables";
12
+ export declare const SPREADSHEET_RECORD_TABLE_ORDER = "tableOrder";
11
13
  export declare function initializeSpreadsheetSheetRecord(record: Y.Map<unknown>, sheet: WorkSpreadsheetSheet): void;
12
14
  export declare function patchSpreadsheetSheetRecord(record: Y.Map<unknown>, previous: WorkSpreadsheetSheet | undefined, next: WorkSpreadsheetSheet): void;
13
15
  export declare function readSpreadsheetSheetRecord(record: Y.Map<unknown>, id: string): WorkSpreadsheetSheet;
@@ -0,0 +1,6 @@
1
+ export declare function requiredCoordinate(value: unknown, maximum: number, label: string, sheetId: string): number;
2
+ export declare function requiredInputRecord(value: unknown, label: string): Record<string, unknown>;
3
+ export declare function requiredIdentifier(value: unknown, label: string): string;
4
+ export declare function requiredNonEmptyString(value: unknown, label: string): string;
5
+ export declare function validateJsonRecord(value: Record<string, unknown>, label: string): Record<string, unknown>;
6
+ export declare function invalidWorkOfficeSpreadsheetInput(expected: string): never;
@@ -5,5 +5,6 @@ export interface SpreadsheetAutoFilterRange {
5
5
  column: [number, number];
6
6
  }
7
7
  export declare function spreadsheetAutoFilterRange(sheet: WorkSpreadsheetSheet, selection: Selection): SpreadsheetAutoFilterRange | null;
8
+ export declare function spreadsheetSelectionOrCurrentRegion(sheet: WorkSpreadsheetSheet, selection: Selection): SpreadsheetAutoFilterRange | null;
8
9
  export declare function spreadsheetAutoFilterHeaderColumn(sheet: WorkSpreadsheetSheet | undefined, selection: Selection): number | null;
9
10
  export declare function toggleSpreadsheetAutoFilter(content: WorkSpreadsheetContent, sheetId: string, selection: Selection): WorkSpreadsheetContent | null;
@@ -21,7 +21,13 @@ export declare const spreadsheetRibbonTabs: readonly [{
21
21
  readonly id: "view";
22
22
  readonly label: "视图";
23
23
  }];
24
- export type SpreadsheetRibbonTabId = (typeof spreadsheetRibbonTabs)[number]['id'];
24
+ export declare const spreadsheetTableDesignRibbonTab: {
25
+ readonly id: "tableDesign";
26
+ readonly label: "表格设计";
27
+ readonly compactLabel: "设计";
28
+ readonly contextual: true;
29
+ };
30
+ export type SpreadsheetRibbonTabId = (typeof spreadsheetRibbonTabs)[number]['id'] | typeof spreadsheetTableDesignRibbonTab.id;
25
31
  export interface SpreadsheetCommandShortcut {
26
32
  label: string;
27
33
  aria: string;
@@ -187,6 +193,34 @@ export declare const spreadsheetCommandCatalog: {
187
193
  readonly editor: readonly ["Mod-5"];
188
194
  };
189
195
  };
196
+ readonly growFont: {
197
+ readonly id: "font.grow";
198
+ readonly label: "增大字号";
199
+ readonly location: {
200
+ readonly area: "ribbon";
201
+ readonly tab: "home";
202
+ readonly group: "font";
203
+ };
204
+ readonly shortcut: {
205
+ readonly label: "Cmd/Ctrl+Shift+. 或 Cmd/Ctrl+]";
206
+ readonly aria: "Control+Shift+. Meta+Shift+. Control+] Meta+]";
207
+ readonly editor: readonly ["Mod-Shift-.", "Mod-]"];
208
+ };
209
+ };
210
+ readonly shrinkFont: {
211
+ readonly id: "font.shrink";
212
+ readonly label: "减小字号";
213
+ readonly location: {
214
+ readonly area: "ribbon";
215
+ readonly tab: "home";
216
+ readonly group: "font";
217
+ };
218
+ readonly shortcut: {
219
+ readonly label: "Cmd/Ctrl+Shift+, 或 Cmd/Ctrl+[";
220
+ readonly aria: "Control+Shift+, Meta+Shift+, Control+[ Meta+[";
221
+ readonly editor: readonly ["Mod-Shift-,", "Mod-["];
222
+ };
223
+ };
190
224
  readonly numberFormatGeneral: {
191
225
  readonly id: "number.general";
192
226
  readonly label: "常规";
@@ -388,6 +422,11 @@ export declare const spreadsheetCommandCatalog: {
388
422
  readonly tab: "home";
389
423
  readonly group: "font";
390
424
  };
425
+ readonly shortcut: {
426
+ readonly label: "Cmd/Ctrl+Shift+_";
427
+ readonly aria: "Control+Shift+_ Meta+Shift+_";
428
+ readonly editor: readonly ["Mod-Shift-_", "Mod-Shift-Minus"];
429
+ };
391
430
  };
392
431
  readonly borderAll: {
393
432
  readonly id: "font.borderAll";
@@ -406,6 +445,11 @@ export declare const spreadsheetCommandCatalog: {
406
445
  readonly tab: "home";
407
446
  readonly group: "font";
408
447
  };
448
+ readonly shortcut: {
449
+ readonly label: "Cmd/Ctrl+Shift+&";
450
+ readonly aria: "Control+Shift+& Meta+Shift+&";
451
+ readonly editor: readonly ["Mod-Shift-&", "Mod-Shift-7"];
452
+ };
409
453
  };
410
454
  readonly borderInside: {
411
455
  readonly id: "font.borderInside";
@@ -757,6 +801,20 @@ export declare const spreadsheetCommandCatalog: {
757
801
  readonly group: "charts";
758
802
  };
759
803
  };
804
+ readonly table: {
805
+ readonly id: "insert.table";
806
+ readonly label: "表格";
807
+ readonly location: {
808
+ readonly area: "ribbon";
809
+ readonly tab: "insert";
810
+ readonly group: "tables";
811
+ };
812
+ readonly shortcut: {
813
+ readonly label: "Cmd/Ctrl+T";
814
+ readonly aria: "Control+T Meta+T";
815
+ readonly editor: readonly ["Mod-t"];
816
+ };
817
+ };
760
818
  readonly hyperlink: {
761
819
  readonly id: "insert.hyperlink";
762
820
  readonly label: "超链接";
@@ -9,6 +9,7 @@ import type { SpreadsheetCellFormatRequest } from './spreadsheet-cell-format';
9
9
  import type { SpreadsheetCellRange } from './spreadsheet-cell-range';
10
10
  import type { SpreadsheetCellStyleChoice } from './spreadsheet-cell-style';
11
11
  import type { SpreadsheetCellFillDirection } from './spreadsheet-cell-fill';
12
+ import { type SpreadsheetFontSizeDirection } from './spreadsheet-font-size-command';
12
13
  import type { SpreadsheetDataValidationRequest, SpreadsheetDataValidationTarget } from './spreadsheet-data-validation';
13
14
  import { type SpreadsheetCellMergeCommand } from './spreadsheet-cell-merge';
14
15
  import type { SpreadsheetFormatPainterMode } from './spreadsheet-format-painter';
@@ -18,6 +19,7 @@ import { type SpreadsheetKeyboardSelection, type SpreadsheetSelectionMove, type
18
19
  import type { SpreadsheetPasteContent } from './spreadsheet-paste-special';
19
20
  import { type SpreadsheetDecimalPlacesDirection } from './spreadsheet-number-format-command';
20
21
  import { type SpreadsheetSheetMoveDirection } from './spreadsheet-sheet-model';
22
+ import type { SpreadsheetTableDesignPatch, SpreadsheetTableRequest, SpreadsheetTableTarget } from './spreadsheet-table';
21
23
  export interface SpreadsheetWorkbookCommandPort {
22
24
  autoFillCell: (copyRange: SpreadsheetCommandRange, applyRange: SpreadsheetCommandRange, direction: SpreadsheetCellFillDirection) => void;
23
25
  batchCallApis: (apiCalls: Array<{
@@ -127,6 +129,10 @@ export interface SpreadsheetHyperlinkCommandPort {
127
129
  canOpen: boolean;
128
130
  open: (request: SpreadsheetHyperlinkCell) => boolean;
129
131
  }
132
+ export interface SpreadsheetTableCommandPort {
133
+ canOpen: boolean;
134
+ open: (target: SpreadsheetTableTarget) => boolean;
135
+ }
130
136
  export interface SpreadsheetNavigationCommandPort {
131
137
  canOpenFind: boolean;
132
138
  canOpenGoTo: boolean;
@@ -144,12 +150,14 @@ export interface SpreadsheetEditorCommands {
144
150
  activateFormatPainter: (mode: SpreadsheetFormatPainterMode) => boolean;
145
151
  addSheet: () => boolean;
146
152
  adjustDecimalPlaces: (direction: SpreadsheetDecimalPlacesDirection) => boolean;
153
+ adjustFontSize: (direction: SpreadsheetFontSizeDirection) => boolean;
147
154
  applyCellStyle: (preset: SpreadsheetCellStyleChoice) => boolean;
148
155
  applyCellFormat: (request: SpreadsheetCellFormatRequest) => boolean;
149
156
  applyDataValidation: (request: SpreadsheetDataValidationRequest) => boolean;
150
157
  applyAutoSum: (functionName: SpreadsheetAutoSumFunction) => boolean;
151
158
  applyFormatPainter: (target: SpreadsheetCommandSelection) => boolean;
152
159
  applyHyperlink: (request: SpreadsheetHyperlinkRequest) => boolean;
160
+ applyTable: (request: SpreadsheetTableRequest) => boolean;
153
161
  cancelFormatPainter: () => boolean;
154
162
  clearSelectedCells: (mode?: SpreadsheetCellClearMode) => boolean;
155
163
  copySelection: () => boolean;
@@ -170,6 +178,7 @@ export interface SpreadsheetEditorCommands {
170
178
  openGoTo: () => boolean;
171
179
  openHyperlink: () => boolean;
172
180
  openPasteSpecial: () => boolean;
181
+ openTable: () => boolean;
173
182
  pasteCells: (values: readonly (readonly unknown[])[]) => boolean;
174
183
  pasteSelection: () => boolean;
175
184
  pasteSpecial: (content: SpreadsheetPasteContent) => boolean;
@@ -190,6 +199,8 @@ export interface SpreadsheetEditorCommands {
190
199
  setZoom: (percent: number) => boolean;
191
200
  sortSelectedCells: (direction: SpreadsheetSortDirection) => boolean;
192
201
  toggleAutoFilter: () => boolean;
202
+ updateTable: (sheetId: string, tableId: string, patch: SpreadsheetTableDesignPatch) => boolean;
203
+ convertTableToRange: (sheetId: string, tableId: string) => boolean;
193
204
  undo: () => boolean;
194
205
  }
195
206
  export type SpreadsheetEditorCanCommands = OfficeEditorCanCommands<SpreadsheetEditorCommands>;
@@ -210,6 +221,7 @@ export interface SpreadsheetCommandContext {
210
221
  navigation: SpreadsheetNavigationCommandPort;
211
222
  onChange: (content: WorkSpreadsheetContent) => void;
212
223
  selection: SpreadsheetCommandSelection | null;
224
+ table: SpreadsheetTableCommandPort;
213
225
  targetSheetGridSize?: SpreadsheetGridSize | null;
214
226
  targetSheetId: string;
215
227
  toolbarCell: Cell | null;
@@ -1,5 +1,5 @@
1
1
  import type { Cell, Selection } from '@fortune-sheet/core';
2
- import type { WorkSpreadsheetContent } from '../work-types';
2
+ import type { WorkSpreadsheetContent, WorkSpreadsheetTable } from '../work-types';
3
3
  import type { SpreadsheetResolvedCellBorders } from './spreadsheet-cell-border';
4
4
  import { type SpreadsheetRibbonTabId } from './spreadsheet-command-catalog';
5
5
  import type { SpreadsheetEditorCanCommands, SpreadsheetEditorCommands } from './spreadsheet-command-controller';
@@ -7,8 +7,10 @@ import type { SpreadsheetFormatPainterMode } from './spreadsheet-format-painter'
7
7
  import type { SpreadsheetWorkbookPanelView } from './spreadsheet-workbook-panel';
8
8
  import { type WorkOfficeFileAction } from './work-office-chrome';
9
9
  export type { SpreadsheetRibbonTabId } from './spreadsheet-command-catalog';
10
- export declare function SpreadsheetEditorRibbon({ activeTab, autoFilterActive, can, commands, content, fileActions, findOpen, formatPainterMode, freezePanesActive, freezePanesSelection, gridLinesVisible, panelId, onTabChange, onTogglePanel, panel, toolbarCell, toolbarCellBorders, }: {
10
+ export declare function SpreadsheetEditorRibbon({ activeTab, activeTable, activeTableSheetId, autoFilterActive, can, commands, content, fileActions, findOpen, formatPainterMode, freezePanesActive, freezePanesSelection, gridLinesVisible, panelId, onTabChange, onTogglePanel, panel, toolbarCell, toolbarCellBorders, }: {
11
11
  activeTab: SpreadsheetRibbonTabId;
12
+ activeTable?: WorkSpreadsheetTable | null;
13
+ activeTableSheetId?: string;
12
14
  autoFilterActive?: boolean;
13
15
  can: SpreadsheetEditorCanCommands;
14
16
  commands: SpreadsheetEditorCommands;
@@ -0,0 +1,18 @@
1
+ import type { Cell } from '@fortune-sheet/core';
2
+ import type { WorkSpreadsheetContent } from '../work-types';
3
+ import type { SpreadsheetCommandContext, SpreadsheetEditorCommands } from './spreadsheet-command-controller';
4
+ import { type SpreadsheetCellRange, type SpreadsheetCellRangeInput } from './spreadsheet-cell-range';
5
+ import { type SpreadsheetFontSizeDirection } from './spreadsheet-font-size';
6
+ import { type OfficeEditorExtension } from './office-editor-extension';
7
+ export { nextSpreadsheetFontSize } from './spreadsheet-font-size';
8
+ export type { SpreadsheetFontSizeDirection } from './spreadsheet-font-size';
9
+ export declare const MAX_SPREADSHEET_FONT_SIZE_CELLS = 10000;
10
+ export interface SpreadsheetFontSizeApiCall {
11
+ name: 'setCellFormatByRange';
12
+ args: ['fs', number, SpreadsheetCellRange, {
13
+ id: string;
14
+ }];
15
+ }
16
+ export declare function createSpreadsheetFontSizeExtension(): OfficeEditorExtension<SpreadsheetCommandContext, SpreadsheetEditorCommands>;
17
+ export declare function canAdjustSpreadsheetFontSize(content: WorkSpreadsheetContent, sheetId: string, range: SpreadsheetCellRangeInput, direction: SpreadsheetFontSizeDirection): boolean;
18
+ export declare function spreadsheetFontSizeApiCalls(cells: readonly (readonly (Cell | null)[])[], range: SpreadsheetCellRangeInput, sheetId: string, direction: SpreadsheetFontSizeDirection): SpreadsheetFontSizeApiCall[];
@@ -0,0 +1,4 @@
1
+ export declare const DEFAULT_SPREADSHEET_FONT_SIZE = 10;
2
+ export declare const spreadsheetFontSizes: readonly [9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 28, 36, 48, 72];
3
+ export type SpreadsheetFontSizeDirection = 'grow' | 'shrink';
4
+ export declare function nextSpreadsheetFontSize(current: number, direction: SpreadsheetFontSizeDirection): number | null;
@@ -0,0 +1,3 @@
1
+ import type { SpreadsheetCommandContext, SpreadsheetEditorCommands } from './spreadsheet-command-controller';
2
+ import { type OfficeEditorExtension } from './office-editor-extension';
3
+ export declare function createSpreadsheetTableExtension(): OfficeEditorExtension<SpreadsheetCommandContext, SpreadsheetEditorCommands>;
@@ -0,0 +1,7 @@
1
+ import type { WorkSpreadsheetContent, WorkSpreadsheetTable } from '../work-types';
2
+ export declare function canMaterializeSpreadsheetTableAppearance(table: WorkSpreadsheetTable): boolean;
3
+ /**
4
+ * Convert to Range removes ListObject semantics, so the render-only style must
5
+ * become native cell formatting to preserve the appearance users confirmed.
6
+ */
7
+ export declare function materializeSpreadsheetTableAppearance(content: WorkSpreadsheetContent, sheetId: string, table: WorkSpreadsheetTable): WorkSpreadsheetContent | null;
@@ -0,0 +1,8 @@
1
+ import type { SpreadsheetTableDialogSource, SpreadsheetTableDialogValue } from './spreadsheet-table';
2
+ export declare function SpreadsheetTableDialog({ source, restoreFocusTarget, onApply, onClose, onValidate, }: {
3
+ source: SpreadsheetTableDialogSource;
4
+ restoreFocusTarget: () => HTMLElement | null;
5
+ onApply: (value: SpreadsheetTableDialogValue) => boolean;
6
+ onClose: () => void;
7
+ onValidate: (value: SpreadsheetTableDialogValue) => string | null;
8
+ }): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare const MAX_SPREADSHEET_TABLE_CELLS = 100000;
@@ -0,0 +1,21 @@
1
+ import type { Op } from '@fortune-sheet/core';
2
+ import type { WorkSpreadsheetSheet } from '../work-types';
3
+ export type SpreadsheetTableStructureChange = {
4
+ axis: 'column' | 'row';
5
+ count: number;
6
+ direction: 'lefttop' | 'rightbottom';
7
+ index: number;
8
+ kind: 'insert';
9
+ } | {
10
+ axis: 'column' | 'row';
11
+ end: number;
12
+ kind: 'delete';
13
+ start: number;
14
+ };
15
+ export declare function canApplySpreadsheetTableStructureChange(sheet: WorkSpreadsheetSheet | undefined, change: SpreadsheetTableStructureChange): boolean;
16
+ /**
17
+ * Reconciles Fortune's cell and whole-row/column operation stream with the
18
+ * browser-owned ListObject model. Fortune preserves unknown sheet metadata,
19
+ * but it cannot update table ranges, column identities, or filter offsets.
20
+ */
21
+ export declare function reconcileSpreadsheetTablesAfterFortune(sheets: WorkSpreadsheetSheet[], sourceSheets: WorkSpreadsheetSheet[], operations?: readonly Op[]): WorkSpreadsheetSheet[];
@@ -0,0 +1,16 @@
1
+ import type { Cell } from '@fortune-sheet/core';
2
+ import type { SpreadsheetTableCellRenderStyle } from './spreadsheet-table-style';
3
+ export interface SpreadsheetTableRenderCellInfo {
4
+ column: number;
5
+ endX: number;
6
+ endY: number;
7
+ row: number;
8
+ startX: number;
9
+ startY: number;
10
+ }
11
+ export interface SpreadsheetTableConditionalStyle {
12
+ cellColor?: string;
13
+ textColor?: string;
14
+ }
15
+ export declare function beginSpreadsheetTableCellRender(_cell: Cell | null, tableStyle: SpreadsheetTableCellRenderStyle | null, conditionalStyle: SpreadsheetTableConditionalStyle | undefined, context: CanvasRenderingContext2D): void;
16
+ export declare function finishSpreadsheetTableCellRender(_cell: Cell | null, cellInfo: SpreadsheetTableRenderCellInfo, tableStyle: SpreadsheetTableCellRenderStyle | null, context: CanvasRenderingContext2D): void;
@@ -0,0 +1,8 @@
1
+ import type { WorkSpreadsheetTable } from '../work-types';
2
+ import type { SpreadsheetEditorCanCommands, SpreadsheetEditorCommands } from './spreadsheet-command-controller';
3
+ export declare function SpreadsheetTableDesignRibbon({ can, commands, sheetId, table, }: {
4
+ can: SpreadsheetEditorCanCommands;
5
+ commands: SpreadsheetEditorCommands;
6
+ sheetId: string;
7
+ table: WorkSpreadsheetTable;
8
+ }): import("react").JSX.Element;