@a3s-lab/office 0.36.0 → 0.37.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/README.md +13 -6
- package/dist/0~7048.js +93 -1
- package/dist/0~spreadsheet-editor.js +388 -35
- package/dist/3266.js +366 -6
- package/dist/4121.js +1942 -1939
- package/dist/core.js +30 -3
- package/dist/internal/features/work/editors/spreadsheet-table-totals.d.ts +39 -0
- package/dist/internal/features/work/editors/spreadsheet-table.d.ts +11 -1
- package/dist/internal/features/work/work-types.d.ts +14 -0
- package/dist/internal/kernel/office-kernel-spreadsheet-fallback-formula.d.ts +11 -0
- package/dist/office-kernel.wasm +0 -0
- package/dist/office-kernel.worker.js +93 -1
- package/dist/styles.css +120 -0
- package/docs/latest/en/browser-editor-architecture.md +8 -2
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ workflows, and a separate Rust automation plane.
|
|
|
56
56
|
|
|
57
57
|
## Latest on `main`
|
|
58
58
|
|
|
59
|
-
The `0.
|
|
59
|
+
The `0.37.0` release exposes these capabilities as normal user-facing
|
|
60
60
|
Playground templates, with matching implementation detail in the documentation:
|
|
61
61
|
|
|
62
62
|
| Editor | Latest capability | Public entry |
|
|
@@ -68,7 +68,7 @@ Playground templates, with matching implementation detail in the documentation:
|
|
|
68
68
|
| Writer | Native character shading with exact `w:shd` patterns, foreground/background color identity, explicit resets, authoring, and DOCX reopen | Playground **Latest capabilities → 字符底纹** · [Document reference](docs/latest/en/components/document.mdx#native-character-shading) |
|
|
69
69
|
| Writer | Independent Latin, East Asian, and bidi proofing languages plus explicit `w:noProof` inclusion/exclusion | Playground **Latest capabilities → 校对语言** · [Document reference](docs/latest/en/components/document.mdx#native-proofing-languages) |
|
|
70
70
|
| Spreadsheet | Complete common Data Validation input, blank/dropdown, and Stop/Warning/Information error settings with native XLSX round trips | Playground **Latest capabilities → 数据验证** · [Spreadsheet reference](docs/latest/en/components/spreadsheet.mdx#data-validation) |
|
|
71
|
-
| Spreadsheet |
|
|
71
|
+
| Spreadsheet | Native totals-row authoring with per-column aggregates, labels, custom formulas, filtered-row-aware `SUBTOTAL`, automatic calculated-column fill for newly inserted table body rows, and bounded structured-reference calculation across Rust/WASM and JavaScript fallback | Playground **Latest capabilities → 结构化引用** · [Totals-row reference](docs/latest/en/components/spreadsheet.mdx#native-totals-row-authoring) · [Structured-reference calculation](docs/latest/en/components/spreadsheet.mdx#structured-reference-calculation) |
|
|
72
72
|
| PDF | Insert, delete, rotate, reorder, extract, merge, and split pages through a dedicated Web Worker, with Blob-level Undo/Redo and independent binary reopen verification | Playground **Latest capabilities → 组织 PDF 页面** · [PDF reference](docs/latest/en/components/pdf.mdx#page-organization) |
|
|
73
73
|
|
|
74
74
|
All nine entries are reachable from the first Playground viewport. The
|
|
@@ -152,7 +152,7 @@ baseline rather than one specific release.
|
|
|
152
152
|
| Formatting and style rendering | **Partial** — native fonts, colors, borders, alignment, number formats, cell styles, all 17 native non-solid OOXML pattern fills, native linear/path XLSX gradients, and one Format Cells surface that authors none, solid, pattern, or gradient fills with exact geometry and 2–256 ordered stops; static date/time entry, contrast-safe font preview, native XLSX rich-text runs, selected-text font formatting, direct formula-bar/F2 insertion or deletion, and bounded authenticated formatted-HTML paste | Disjoint multi-edit rich-text authoring, broader themes, locale formats, and advanced style effects |
|
|
153
153
|
| Ribbon and shortcuts | **Partial** — common Office-style Home/Data/View commands, grid-scoped shortcuts, and focused Font-dialog aliases | Larger command catalog and platform-specific accelerators |
|
|
154
154
|
| Formulas and recalculation | **Partial** — dependency-aware calculation plus bounded structured references (`Table[Column]`, contiguous ranges, `#All`/`#Headers`/`#Data`/`#Totals`/`#This Row`, and `[@Column]`) in the shared Rust/WASM and JavaScript paths | Wider functions, arrays, volatile semantics, and calculation parity |
|
|
155
|
-
| Tables, pivots, charts, and rules | **Partial** — native tables, bounded structured-reference formulas, calculated-column formulas with automatic fill for newly inserted body rows, pivots, charts, conditional formatting, and common validation rules with complete input/error-setting authoring |
|
|
155
|
+
| Tables, pivots, charts, and rules | **Partial** — native tables, bounded structured-reference formulas, calculated-column formulas with automatic fill for newly inserted body rows, complete common totals-row authoring, pivots, charts, conditional formatting, and common validation rules with complete input/error-setting authoring | Slicers, pivot charts, custom/dependent validation rules, advanced analysis, and broader browser alert flows |
|
|
156
156
|
| Large worksheets | **Supported with boundaries** — maximum-dimension sparse import/editing and viewport-bounded Canvas painting | Highly optimized native grid with hardware-dependent limits |
|
|
157
157
|
| Files and printing | **Partial** — XLS/XLSX/ODS/CSV import, XLSX export, and PDF output | Broader round trips, external data, print fidelity, and legacy conversion |
|
|
158
158
|
| External data, macros, and specialist analysis | **Gap** — active macros are never executed; bounded models are still needed for data connections and solver-like tools | Established data, macro/add-in, scenario, and optimization ecosystems |
|
|
@@ -756,9 +756,15 @@ conflicting column fails closed and drops its automatic rule. XLSX
|
|
|
756
756
|
`<calculatedColumnFormula>` metadata round-trips with the leading `=` restored
|
|
757
757
|
in the controlled model, while unsafe or external formulas are omitted.
|
|
758
758
|
The Playground's **结构化引用** template shows a calculated `Revenue` column,
|
|
759
|
-
an insertion hint,
|
|
760
|
-
totals
|
|
761
|
-
|
|
759
|
+
an insertion hint, an editable totals row, and a worksheet-qualified summary.
|
|
760
|
+
The Table Design totals menu enables or disables the row and assigns each
|
|
761
|
+
column a label, one of ten native aggregate functions, or a bounded custom
|
|
762
|
+
formula. Native aggregates emit filtered-row-aware `SUBTOTAL` formulas; direct
|
|
763
|
+
cell edits reconcile back into table metadata, table structure changes move
|
|
764
|
+
the row without overwriting manual cells, and table renames rewrite only
|
|
765
|
+
generated formulas. Dense and sparse worksheets, Yjs collaboration, and XLSX
|
|
766
|
+
`totalsRowFunction`, `totalsRowLabel`, and `totalsRowFormula` round trips share
|
|
767
|
+
the same model. Slicers and external/query tables remain explicit boundaries.
|
|
762
768
|
|
|
763
769
|
Use `downloadArtifact` to start a browser download or
|
|
764
770
|
`createArtifactBlob` when your application owns upload and persistence.
|
|
@@ -1641,6 +1647,7 @@ keep working without hard-coded return URLs.
|
|
|
1641
1647
|
|
|
1642
1648
|
- [Live Playground](https://a3s-lab.github.io/Office/playground/)
|
|
1643
1649
|
- [Documentation center](https://a3s-lab.github.io/Office/docs/)
|
|
1650
|
+
- [A3S Office 0.37.0 documentation](https://a3s-lab.github.io/Office/docs/0.37.0/)
|
|
1644
1651
|
- [A3S Office 0.36.0 documentation](https://a3s-lab.github.io/Office/docs/0.36.0/)
|
|
1645
1652
|
- [A3S Office 0.34.0 documentation](https://a3s-lab.github.io/Office/docs/0.34.0/)
|
|
1646
1653
|
- [A3S Office 0.33.0 documentation](https://a3s-lab.github.io/Office/docs/0.33.0/)
|
package/dist/0~7048.js
CHANGED
|
@@ -1352,6 +1352,13 @@ const browserScalarFunctionArities = new Map([
|
|
|
1352
1352
|
1
|
|
1353
1353
|
]
|
|
1354
1354
|
],
|
|
1355
|
+
[
|
|
1356
|
+
'SUBTOTAL',
|
|
1357
|
+
[
|
|
1358
|
+
2,
|
|
1359
|
+
255
|
|
1360
|
+
]
|
|
1361
|
+
],
|
|
1355
1362
|
[
|
|
1356
1363
|
'SUM',
|
|
1357
1364
|
[
|
|
@@ -1372,6 +1379,90 @@ function normalizeSpreadsheetFunctionName(name) {
|
|
|
1372
1379
|
while(normalized.startsWith('_XLFN.') || normalized.startsWith('_XLWS.'))normalized = normalized.slice(6);
|
|
1373
1380
|
return normalized;
|
|
1374
1381
|
}
|
|
1382
|
+
function evaluateParserSubtotal(parameters) {
|
|
1383
|
+
const codeValue = parserNumericValue(parameters[0]);
|
|
1384
|
+
if (void 0 === codeValue) return 'VALUE!';
|
|
1385
|
+
const code = Math.trunc(codeValue);
|
|
1386
|
+
const values = parameters.slice(1).flatMap((parameter)=>flattenParserValues(parameter));
|
|
1387
|
+
for (const value of values){
|
|
1388
|
+
const error = parserErrorValue(value);
|
|
1389
|
+
if (error) return error;
|
|
1390
|
+
}
|
|
1391
|
+
switch(code){
|
|
1392
|
+
case 1:
|
|
1393
|
+
case 101:
|
|
1394
|
+
return parserSubtotalNumeric(values, 'average');
|
|
1395
|
+
case 2:
|
|
1396
|
+
case 102:
|
|
1397
|
+
return values.filter((value)=>'number' == typeof value).length;
|
|
1398
|
+
case 3:
|
|
1399
|
+
case 103:
|
|
1400
|
+
return values.filter((value)=>null != value).length;
|
|
1401
|
+
case 4:
|
|
1402
|
+
case 104:
|
|
1403
|
+
return parserSubtotalNumeric(values, 'max');
|
|
1404
|
+
case 5:
|
|
1405
|
+
case 105:
|
|
1406
|
+
return parserSubtotalNumeric(values, 'min');
|
|
1407
|
+
case 6:
|
|
1408
|
+
case 106:
|
|
1409
|
+
return parserSubtotalNumeric(values, 'product');
|
|
1410
|
+
case 7:
|
|
1411
|
+
case 107:
|
|
1412
|
+
return parserSubtotalNumeric(values, 'stddev');
|
|
1413
|
+
case 8:
|
|
1414
|
+
case 108:
|
|
1415
|
+
return parserSubtotalNumeric(values, 'stddevp');
|
|
1416
|
+
case 9:
|
|
1417
|
+
case 109:
|
|
1418
|
+
return parserSubtotalNumeric(values, 'sum');
|
|
1419
|
+
case 10:
|
|
1420
|
+
case 110:
|
|
1421
|
+
return parserSubtotalNumeric(values, 'var');
|
|
1422
|
+
case 11:
|
|
1423
|
+
case 111:
|
|
1424
|
+
return parserSubtotalNumeric(values, 'varp');
|
|
1425
|
+
default:
|
|
1426
|
+
return 'VALUE!';
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
function parserSubtotalNumeric(values, operation) {
|
|
1430
|
+
const numbers = values.filter((value)=>'number' == typeof value && Number.isFinite(value));
|
|
1431
|
+
const count = numbers.length;
|
|
1432
|
+
const sum = numbers.reduce((total, value)=>total + value, 0);
|
|
1433
|
+
if ('sum' === operation) return finiteParserNumber(sum);
|
|
1434
|
+
if ('average' === operation) return count ? finiteParserNumber(sum / count) : 'DIV/0!';
|
|
1435
|
+
if ('max' === operation) return finiteParserNumber(Math.max(...numbers, 0));
|
|
1436
|
+
if ('min' === operation) return finiteParserNumber(Math.min(...numbers, 0));
|
|
1437
|
+
if ('product' === operation) return finiteParserNumber(count ? numbers.reduce((total, value)=>total * value, 1) : 0);
|
|
1438
|
+
if ('stddev' === operation || 'var' === operation) {
|
|
1439
|
+
if (count < 2) return 'DIV/0!';
|
|
1440
|
+
} else if (0 === count) return 'DIV/0!';
|
|
1441
|
+
const mean = sum / count;
|
|
1442
|
+
const divisor = 'stddev' === operation || 'var' === operation ? count - 1 : count;
|
|
1443
|
+
const variance = numbers.reduce((total, value)=>total + (value - mean) ** 2, 0) / divisor;
|
|
1444
|
+
return finiteParserNumber('stddev' === operation || 'stddevp' === operation ? Math.sqrt(variance) : variance);
|
|
1445
|
+
}
|
|
1446
|
+
function flattenParserValues(value) {
|
|
1447
|
+
if (!Array.isArray(value)) return [
|
|
1448
|
+
value
|
|
1449
|
+
];
|
|
1450
|
+
return value.flatMap((entry)=>flattenParserValues(entry));
|
|
1451
|
+
}
|
|
1452
|
+
function parserNumericValue(value) {
|
|
1453
|
+
if ('number' == typeof value) return Number.isFinite(value) ? value : void 0;
|
|
1454
|
+
if ('boolean' == typeof value) return value ? 1 : 0;
|
|
1455
|
+
if ('string' != typeof value || !value.trim()) return;
|
|
1456
|
+
const parsed = Number(value);
|
|
1457
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
1458
|
+
}
|
|
1459
|
+
function parserErrorValue(value) {
|
|
1460
|
+
if (value instanceof Error) return value.message.startsWith('#') ? value.message.slice(1) : 'VALUE!';
|
|
1461
|
+
return 'string' == typeof value && value.startsWith('#') ? value.slice(1) : void 0;
|
|
1462
|
+
}
|
|
1463
|
+
function finiteParserNumber(value) {
|
|
1464
|
+
return Number.isFinite(value) ? value : 'NUM!';
|
|
1465
|
+
}
|
|
1375
1466
|
function normalizeFormulaForFortuneParser(formula) {
|
|
1376
1467
|
const source = formula.replace(/^=/, '');
|
|
1377
1468
|
let output = '';
|
|
@@ -2154,10 +2245,11 @@ class JavaScriptSpreadsheetEvaluator {
|
|
|
2154
2245
|
let unsupportedFunction;
|
|
2155
2246
|
let materializedRangeCells = 0;
|
|
2156
2247
|
parser.setFunction('IFERROR', evaluateParserIfError).setFunction('ROW', (parameters)=>parameters.length ? null : coordinate.row + 1).setFunction('COLUMN', (parameters)=>parameters.length ? null : coordinate.column + 1);
|
|
2157
|
-
parser.on('callFunction', (name, parameters)=>{
|
|
2248
|
+
parser.on('callFunction', (name, parameters, done)=>{
|
|
2158
2249
|
const normalized = normalizeSpreadsheetFunctionName(name);
|
|
2159
2250
|
const arity = browserScalarFunctionArities.get(normalized);
|
|
2160
2251
|
if (!arity || parameters.length < arity[0] || parameters.length > arity[1]) unsupportedFunction ??= name.toUpperCase();
|
|
2252
|
+
if ('SUBTOTAL' === normalized) done(evaluateParserSubtotal(parameters));
|
|
2161
2253
|
});
|
|
2162
2254
|
parser.on('callCellValue', (cell, _options, done)=>{
|
|
2163
2255
|
const dependency = this.resolveCoordinate(indexed.sheet, cell);
|