@a3s-lab/office 0.22.0 → 0.23.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 CHANGED
@@ -123,7 +123,7 @@ baseline rather than one specific release.
123
123
 
124
124
  | Capability | A3S Office today | Traditional Office baseline |
125
125
  | --- | --- | --- |
126
- | Cells, sheets, navigation, and history | **Supported** — multiple sheets, sparse editing, search, clipboard, fill, and undo/redo | Mature grid workflows across desktop and web |
126
+ | Cells, sheets, navigation, and history | **Supported** — multiple sheets, sparse editing, search, clipboard, four-direction fill, exact formula/value copy from above, and undo/redo | Mature grid workflows across desktop and web |
127
127
  | Formatting and style rendering | **Partial** — native fonts, colors, borders, alignment, number formats, cell styles, and static date/time entry | Broader themes, locale formats, rich text, and advanced style effects |
128
128
  | Ribbon and shortcuts | **Partial** — common Office-style Home/Data/View commands and grid-scoped shortcuts | Larger command catalog and platform-specific accelerators |
129
129
  | Formulas and recalculation | **Partial** — dependency-aware calculation and common formula paths | Wider functions, arrays, volatile semantics, and calculation parity |
@@ -1347,6 +1347,7 @@ without hard-coded return URLs.
1347
1347
 
1348
1348
  - [Live Playground](https://a3s-lab.github.io/Office/)
1349
1349
  - [Documentation center](https://a3s-lab.github.io/Office/docs/)
1350
+ - [A3S Office 0.23.0 documentation](https://a3s-lab.github.io/Office/docs/0.23.0/)
1350
1351
  - [A3S Office 0.22.0 documentation](https://a3s-lab.github.io/Office/docs/0.22.0/)
1351
1352
  - [A3S Office 0.21.0 documentation](https://a3s-lab.github.io/Office/docs/0.21.0/)
1352
1353
  - [A3S Office 0.20.0 documentation](https://a3s-lab.github.io/Office/docs/0.20.0/)
package/dist/0~6090.js CHANGED
@@ -258,6 +258,7 @@ function shortcutCodeKey(code) {
258
258
  if ('Equal' === code) return 'equal';
259
259
  if ('Minus' === code) return 'minus';
260
260
  if ('Semicolon' === code) return ';';
261
+ if ('Quote' === code) return "'";
261
262
  if ('Comma' === code) return ',';
262
263
  if ('Period' === code) return '.';
263
264
  return null;
@@ -5,7 +5,7 @@ import { AArrowDown, AArrowUp, AlignCenter, AlignLeft, AlignRight, AlignVertical
5
5
  import { Fragment as external_react_Fragment, cloneElement, memo, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
6
6
  import { genarate, indexToColumnChar, update as core_update } from "@fortune-sheet/core";
7
7
  import { freezeImportedSpreadsheetCell, spreadsheetTextOrientationFromChoice, spreadsheetMatrixProfile, withoutEditableRange, spreadsheetTextOrientationFromAngle, isSpreadsheetTextOrientationId, normalizeSpreadsheetConditionalVisualOptions, spreadsheetCellValueWithDiagonalBorder, spreadsheetUnderlineCellValue, effectiveSpreadsheetPageSetup, attachSpreadsheetShownCommentCells, withEditableRange, sameSpreadsheetHistoryValue, createOfficeSpreadsheetCollaborationBinding as createWorkOfficeSpreadsheetCollaborationBinding, isSpreadsheetConditionalComparisonOperator, spreadsheetConditionalIconForValue, defaultSpreadsheetConditionalIconThresholds, spreadsheetUnderlineStyle, normalizeSpreadsheetDateValidationBoundary, sheetProtectionAuthority, editableRangeCellCount, unlockedCellCount, registerDerivedSpreadsheetMatrix, editableRangeRequiresCredentials, spreadsheetTextOrientationCellStyle, normalizeSpreadsheetConditionalIconSetFormat, defaultSpreadsheetDataBarOptions, spreadsheetConditionalThresholdValue, spreadsheetTextOrientationChoiceFromCell, normalizeSheetProtectionAuthority, withSheetProtection, defaultSpreadsheetColorScaleThresholds, spreadsheetProtectionKey, spreadsheetDiagonalBorderFromCellValue, SPREADSHEET_CONDITIONAL_ICON_SETS, protectedSheetCount, withSheetSelectionPermissions, SPREADSHEET_CONDITIONAL_COMPARISON_OPERATORS, spreadsheetConditionalComparisonNeedsUpperValue, drawSpreadsheetConditionalIcon, spreadsheetTextOrientationFromCell, replaceOfficeSpreadsheetCollaboration as replaceWorkOfficeSpreadsheetCollaboration, readOfficeSpreadsheetCollaboration as readWorkOfficeSpreadsheetCollaboration, spreadsheetConditionalThresholdsEqual, isSpreadsheetUnderlineStyle, spreadsheetVisibleTextRotationFromCell } from "./5045.js";
8
- import { workSpreadsheetChartSupportsGrouping, createSpreadsheetChartFromSelection, normalizeWorkSpreadsheetDataLabelPosition, normalizeSpreadsheetPrintTitleColumns, normalizeSpreadsheetPrintTitleRows, formulaHasStructuredReference, normalizeWorkSpreadsheetErrorBars, defaultPivotValueCaption, workSpreadsheetChartSupportsBarSpacing, normalizeWorkSpreadsheetChartGrouping, spreadsheetGridSize, normalizeWorkSpreadsheetChartAxisGroup, normalizeWorkSpreadsheetScatterStyle, cloneSparseMatrix, spreadsheetPivotAggregationLabel, workSpreadsheetChartAxisIsCategoryAxis, reconcileSpreadsheetChartPreviews, normalizeWorkSpreadsheetChartAxes, normalizeWorkSpreadsheetDoughnutHoleSize, normalizeWorkSpreadsheetChartLegendPosition, spreadsheetChartCount, workSpreadsheetChartTypeLabel, sparseArrayEntries, normalizeWorkSpreadsheetTrendline, effectiveSpreadsheetCalculationSettings, spreadsheetPivotIntersects, normalizeWorkSpreadsheetDataLabels, spreadsheetPivotOutputContains, normalizeSpreadsheetPrintArea, spreadsheetCellAddress, formatSpreadsheetCellRanges, normalizeWorkSpreadsheetChartLayout, spreadsheetFormulaRangeForCell, workSpreadsheetChartAxisIsValueAxis, normalizeWorkSpreadsheetChartSmoothLines, spreadsheetPivotFilterValueKey, normalizeWorkSpreadsheetBubbleScale, normalizeWorkSpreadsheetChartSeriesStyle, volatileSpreadsheetFormulaFunctions, sparseArrayIndexes, normalizeWorkSpreadsheetBubbleSizeRepresents, workSpreadsheetChartSupportsTrendlines, normalizeWorkSpreadsheetChartLegendOverlay, parseSpreadsheetChartReference, workSpreadsheetChartGroupingIsStacked, normalizeWorkSpreadsheetChartGapWidth, workSpreadsheetChartSupportsSmoothLines, refreshSpreadsheetPivotTables, createSpreadsheetPivotFromSelection, reconcileSpreadsheetPivots, spreadsheetPivotCount, sparseMatrixColumnCount, workSpreadsheetChartSupportsErrorBars, formulaHasExternalReference, isValidSpreadsheetDefinedName, spreadsheetPivotValidation, deleteSpreadsheetPivotTable, workSpreadsheetChartAxisDefaultLabelPosition, workSpreadsheetChartSupportsSeriesAnalysis, parseSpreadsheetCellRanges, spreadsheetPivotFilterItems, spreadsheetPivotFields, normalizeWorkSpreadsheetChartOverlap, spreadsheetFormulaRangeConflict, spreadsheetSheetsWithChartPreviews, workSpreadsheetChartUsesNumericXAxis, workSpreadsheetChartAxisShowsMajorGridlinesByDefault, workSpreadsheetChartSupportsAxes, normalizeWorkSpreadsheetCombinationSeriesType, normalizeWorkSpreadsheetRadarStyle } from "./8715.js";
8
+ import { workSpreadsheetChartSupportsGrouping, spreadsheetFormulaRangesForSelection, createSpreadsheetChartFromSelection, normalizeWorkSpreadsheetDataLabelPosition, normalizeSpreadsheetPrintTitleColumns, normalizeSpreadsheetPrintTitleRows, formulaHasStructuredReference, normalizeWorkSpreadsheetErrorBars, defaultPivotValueCaption, workSpreadsheetChartSupportsBarSpacing, normalizeWorkSpreadsheetChartGrouping, spreadsheetGridSize, normalizeWorkSpreadsheetChartAxisGroup, normalizeWorkSpreadsheetScatterStyle, cloneSparseMatrix, spreadsheetPivotAggregationLabel, workSpreadsheetChartAxisIsCategoryAxis, reconcileSpreadsheetChartPreviews, normalizeWorkSpreadsheetChartAxes, normalizeWorkSpreadsheetDoughnutHoleSize, normalizeWorkSpreadsheetChartLegendPosition, spreadsheetChartCount, workSpreadsheetChartTypeLabel, sparseArrayEntries, normalizeWorkSpreadsheetTrendline, effectiveSpreadsheetCalculationSettings, spreadsheetPivotIntersects, normalizeWorkSpreadsheetDataLabels, spreadsheetPivotOutputContains, normalizeSpreadsheetPrintArea, spreadsheetCellAddress, formatSpreadsheetCellRanges, normalizeWorkSpreadsheetChartLayout, spreadsheetFormulaRangeForCell, workSpreadsheetChartAxisIsValueAxis, normalizeWorkSpreadsheetChartSmoothLines, spreadsheetPivotFilterValueKey, normalizeWorkSpreadsheetBubbleScale, normalizeWorkSpreadsheetChartSeriesStyle, volatileSpreadsheetFormulaFunctions, sparseArrayIndexes, normalizeWorkSpreadsheetBubbleSizeRepresents, workSpreadsheetChartSupportsTrendlines, normalizeWorkSpreadsheetChartLegendOverlay, parseSpreadsheetChartReference, workSpreadsheetChartGroupingIsStacked, normalizeWorkSpreadsheetChartGapWidth, workSpreadsheetChartSupportsSmoothLines, refreshSpreadsheetPivotTables, createSpreadsheetPivotFromSelection, reconcileSpreadsheetPivots, spreadsheetPivotCount, sparseMatrixColumnCount, workSpreadsheetChartSupportsErrorBars, formulaHasExternalReference, isValidSpreadsheetDefinedName, spreadsheetPivotValidation, deleteSpreadsheetPivotTable, workSpreadsheetChartAxisDefaultLabelPosition, workSpreadsheetChartSupportsSeriesAnalysis, parseSpreadsheetCellRanges, spreadsheetPivotFilterItems, spreadsheetPivotFields, normalizeWorkSpreadsheetChartOverlap, spreadsheetFormulaRangeConflict, spreadsheetSheetsWithChartPreviews, workSpreadsheetChartUsesNumericXAxis, workSpreadsheetChartAxisShowsMajorGridlinesByDefault, workSpreadsheetChartSupportsAxes, normalizeWorkSpreadsheetCombinationSeriesType, normalizeWorkSpreadsheetRadarStyle } from "./8715.js";
9
9
  import { moveOfficeMenuFocus, stepOfficeZoom, useOfficeRemoteParticipants, Popover, officePresenceColor, useOfficePublishPresenceLocation, button_Button, icon_button_IconButton, moveOfficeGridMenuFocus, office_text_field_OfficeTextField, useDialogFocusScope, useOfficeEditorWheelZoom } from "./0~6090.js";
10
10
  import { useOfficeTaskPaneEscape, OfficeCheckbox, CommittedOfficeNumberField, useOfficeDialog, useOfficeTaskPaneModal, createOfficeKernelClient, officeFontFamilies, CollectionState, OfficeNumberField, handleOfficeTaskPaneKeyDown } from "./0~7048.js";
11
11
  import { isOfficeShortcutBlocked, OfficeColorPicker } from "./0~3635.js";
@@ -3752,6 +3752,38 @@ const spreadsheetCommandCatalog = {
3752
3752
  group: 'editing'
3753
3753
  }
3754
3754
  },
3755
+ copyFormulaFromAbove: {
3756
+ id: 'editing.copyFormulaFromAbove',
3757
+ label: '复制上方公式',
3758
+ location: {
3759
+ area: 'ribbon',
3760
+ tab: 'home',
3761
+ group: 'editing'
3762
+ },
3763
+ shortcut: {
3764
+ label: "Ctrl+'",
3765
+ aria: "Control+'",
3766
+ editor: [
3767
+ "Control-'"
3768
+ ]
3769
+ }
3770
+ },
3771
+ copyValueFromAbove: {
3772
+ id: 'editing.copyValueFromAbove',
3773
+ label: '复制上方值',
3774
+ location: {
3775
+ area: 'ribbon',
3776
+ tab: 'home',
3777
+ group: 'editing'
3778
+ },
3779
+ shortcut: {
3780
+ label: "Ctrl+Shift+'",
3781
+ aria: "Control+Shift+'",
3782
+ editor: [
3783
+ "Control-Shift-'"
3784
+ ]
3785
+ }
3786
+ },
3755
3787
  clearAll: {
3756
3788
  id: 'editing.clearAll',
3757
3789
  label: '清除全部',
@@ -5223,6 +5255,213 @@ function spreadsheetSelectedCellFillPlan(context, direction) {
5223
5255
  const sheet = context.content.sheets.find((candidate)=>candidate.id === context.targetSheetId);
5224
5256
  return canApplySpreadsheetCellFill(sheet, plan) ? plan : null;
5225
5257
  }
5258
+ const MAX_SPREADSHEET_ROWS = 1048576;
5259
+ const spreadsheetPasteContentOptions = [
5260
+ {
5261
+ value: 'all',
5262
+ label: '全部',
5263
+ richOnly: false
5264
+ },
5265
+ {
5266
+ value: 'formulas',
5267
+ label: '公式',
5268
+ richOnly: false
5269
+ },
5270
+ {
5271
+ value: 'values',
5272
+ label: '值',
5273
+ richOnly: false
5274
+ },
5275
+ {
5276
+ value: 'formats',
5277
+ label: '格式',
5278
+ richOnly: true
5279
+ },
5280
+ {
5281
+ value: 'comments',
5282
+ label: '批注',
5283
+ richOnly: true
5284
+ },
5285
+ {
5286
+ value: 'validation',
5287
+ label: '数据验证',
5288
+ richOnly: true
5289
+ },
5290
+ {
5291
+ value: 'all-except-borders',
5292
+ label: '边框除外的全部',
5293
+ richOnly: true
5294
+ },
5295
+ {
5296
+ value: 'formulas-and-number-formats',
5297
+ label: '公式和数字格式',
5298
+ richOnly: true
5299
+ },
5300
+ {
5301
+ value: 'values-and-number-formats',
5302
+ label: '值和数字格式',
5303
+ richOnly: true
5304
+ },
5305
+ {
5306
+ value: 'column-widths',
5307
+ label: '列宽',
5308
+ richOnly: true
5309
+ }
5310
+ ];
5311
+ const spreadsheetPasteOperationOptions = [
5312
+ {
5313
+ value: 'none',
5314
+ label: '无'
5315
+ },
5316
+ {
5317
+ value: 'add',
5318
+ label: '加'
5319
+ },
5320
+ {
5321
+ value: 'subtract',
5322
+ label: '减'
5323
+ },
5324
+ {
5325
+ value: 'multiply',
5326
+ label: '乘'
5327
+ },
5328
+ {
5329
+ value: 'divide',
5330
+ label: '除'
5331
+ }
5332
+ ];
5333
+ function planSpreadsheetCopyFromAbove(sheet, target, kind) {
5334
+ if (!sheet || !isSpreadsheetCopyFromAboveKind(kind) || !spreadsheetCellCoordinateIsSupported(target.row, target.column) || 0 === target.row) return null;
5335
+ const targetRange = {
5336
+ row: [
5337
+ target.row,
5338
+ target.row
5339
+ ],
5340
+ column: [
5341
+ target.column,
5342
+ target.column
5343
+ ]
5344
+ };
5345
+ if (!canMutateSpreadsheetCellRange(sheet, targetRange)) return null;
5346
+ const source = {
5347
+ row: target.row - 1,
5348
+ column: target.column
5349
+ };
5350
+ const sourceCell = spreadsheetCopyFromAboveCellAt(sheet, source.row, source.column);
5351
+ const targetCell = spreadsheetCopyFromAboveCellAt(sheet, target.row, target.column);
5352
+ const formula = spreadsheetCopyableFormula(sheet, sourceCell, source.row, source.column);
5353
+ if ('formula' === kind && sourceCell?.f && null === formula) return null;
5354
+ const copiesFormula = 'formula' === kind && null !== formula;
5355
+ const value = copiesFormula ? formula : spreadsheetCopyFromAboveCellValue(sourceCell);
5356
+ if (copiesFormula ? targetCell?.f === value : !targetCell?.f && Object.is(spreadsheetCopyFromAboveCellValue(targetCell), value)) return null;
5357
+ return {
5358
+ formulaBarValue: value ?? '',
5359
+ kind,
5360
+ source,
5361
+ targetRange,
5362
+ value
5363
+ };
5364
+ }
5365
+ function spreadsheetCopyableFormula(sheet, cell, row, column) {
5366
+ if ('string' != typeof cell?.f || !cell.f.trim()) return null;
5367
+ const formula = cell.f.trim();
5368
+ if (!formula.startsWith('=') || formulaHasExternalReference(formula) || void 0 !== cell.spl || spreadsheetFormulaRangesForSelection(sheet, {
5369
+ startRow: row,
5370
+ endRow: row,
5371
+ startColumn: column,
5372
+ endColumn: column
5373
+ }).length > 0) return null;
5374
+ return formula;
5375
+ }
5376
+ function spreadsheetCopyFromAboveCellValue(cell) {
5377
+ if (cell?.v !== void 0 && null !== cell.v) return cell.v;
5378
+ const inlineText = spreadsheet_copy_from_above_spreadsheetInlineCellText(cell);
5379
+ if (null !== inlineText) return inlineText;
5380
+ if (cell?.m !== void 0 && null !== cell.m) return cell.m;
5381
+ return null;
5382
+ }
5383
+ function spreadsheet_copy_from_above_spreadsheetInlineCellText(cell) {
5384
+ const format = cell?.ct;
5385
+ if (format?.t !== 'inlineStr' || !Array.isArray(format.s)) return null;
5386
+ return format.s.map((run)=>spreadsheet_copy_from_above_isRecord(run) && ('string' == typeof run.v || 'number' == typeof run.v) ? String(run.v) : '').join('');
5387
+ }
5388
+ function spreadsheetCopyFromAboveCellAt(sheet, row, column) {
5389
+ if (void 0 !== sheet.data) return sheet.data[row]?.[column];
5390
+ return sheet.celldata?.find((entry)=>entry.r === row && entry.c === column)?.v;
5391
+ }
5392
+ function spreadsheetCellCoordinateIsSupported(row, column) {
5393
+ return Number.isSafeInteger(row) && row >= 0 && row < MAX_SPREADSHEET_ROWS && Number.isSafeInteger(column) && column >= 0 && column < 16384;
5394
+ }
5395
+ function isSpreadsheetCopyFromAboveKind(value) {
5396
+ return 'formula' === value || 'value' === value;
5397
+ }
5398
+ function spreadsheet_copy_from_above_isRecord(value) {
5399
+ return Boolean(value && 'object' == typeof value && !Array.isArray(value));
5400
+ }
5401
+ function createSpreadsheetCopyFromAboveExtension() {
5402
+ return createOfficeEditorExtension({
5403
+ name: 'spreadsheetCopyFromAbove',
5404
+ addCommands: ()=>({
5405
+ copyCellFromAbove: {
5406
+ canExecute: (context, kind)=>null !== spreadsheetSelectedCopyFromAbovePlan(context, kind),
5407
+ execute: copySpreadsheetCellFromAbove
5408
+ }
5409
+ }),
5410
+ addKeyboardShortcuts: ()=>({
5411
+ [spreadsheetCommandCatalog.copyFormulaFromAbove.shortcut.editor["0"]]: ({ can, commands }, event)=>runSpreadsheetCopyFromAboveShortcut(event, 'formula', can.copyCellFromAbove, commands.copyCellFromAbove),
5412
+ [spreadsheetCommandCatalog.copyValueFromAbove.shortcut.editor["0"]]: ({ can, commands }, event)=>runSpreadsheetCopyFromAboveShortcut(event, 'value', can.copyCellFromAbove, commands.copyCellFromAbove)
5413
+ })
5414
+ });
5415
+ }
5416
+ function copySpreadsheetCellFromAbove(context, kind) {
5417
+ const plan = spreadsheetSelectedCopyFromAbovePlan(context, kind);
5418
+ if (!plan || !context.workbook || !context.targetSheetId) return false;
5419
+ try {
5420
+ context.workbook.batchCallApis([
5421
+ {
5422
+ name: 'setCellValuesByRange',
5423
+ args: [
5424
+ [
5425
+ [
5426
+ plan.value
5427
+ ]
5428
+ ],
5429
+ plan.targetRange,
5430
+ {
5431
+ id: context.targetSheetId
5432
+ }
5433
+ ]
5434
+ }
5435
+ ]);
5436
+ } catch {
5437
+ return false;
5438
+ }
5439
+ try {
5440
+ context.formulaBar?.setValue(plan.formulaBarValue);
5441
+ } catch {}
5442
+ return true;
5443
+ }
5444
+ function spreadsheetSelectedCopyFromAbovePlan(context, kind) {
5445
+ const workbook = context.workbook;
5446
+ const sheetId = context.targetSheetId;
5447
+ if (!context.editable || !workbook || !sheetId || sheetId !== context.activeSheetId) return null;
5448
+ try {
5449
+ const selection = finiteSpreadsheetSelection(workbook.getSelection()?.at(-1) ?? context.fallbackRange);
5450
+ const row = selection.row_focus ?? selection.row[0] ?? 0;
5451
+ const column = selection.column_focus ?? selection.column[0] ?? 0;
5452
+ const sheet = context.content.sheets.find((candidate)=>candidate.id === sheetId);
5453
+ return planSpreadsheetCopyFromAbove(sheet, {
5454
+ row,
5455
+ column
5456
+ }, kind);
5457
+ } catch {
5458
+ return null;
5459
+ }
5460
+ }
5461
+ function runSpreadsheetCopyFromAboveShortcut(event, kind, canExecute, execute) {
5462
+ if (event.repeat || event.isComposing || isOfficeShortcutBlocked(event.target) || isSpreadsheetNativeTextUndoTarget(event.target) || !isSpreadsheetGridKeyboardTarget(event.target) || !canExecute(kind)) return false;
5463
+ return execute(kind);
5464
+ }
5226
5465
  function canEditSpreadsheetSelection(context) {
5227
5466
  return Boolean(context.editable && context.workbook && context.targetSheetId);
5228
5467
  }
@@ -6068,81 +6307,6 @@ function clampSpreadsheetDataValidationFocus(value, range) {
6068
6307
  const focus = 'number' == typeof value && Number.isFinite(value) ? Math.trunc(value) : minimum;
6069
6308
  return Math.min(maximum, Math.max(minimum, focus));
6070
6309
  }
6071
- const MAX_SPREADSHEET_ROWS = 1048576;
6072
- const spreadsheetPasteContentOptions = [
6073
- {
6074
- value: 'all',
6075
- label: '全部',
6076
- richOnly: false
6077
- },
6078
- {
6079
- value: 'formulas',
6080
- label: '公式',
6081
- richOnly: false
6082
- },
6083
- {
6084
- value: 'values',
6085
- label: '值',
6086
- richOnly: false
6087
- },
6088
- {
6089
- value: 'formats',
6090
- label: '格式',
6091
- richOnly: true
6092
- },
6093
- {
6094
- value: 'comments',
6095
- label: '批注',
6096
- richOnly: true
6097
- },
6098
- {
6099
- value: 'validation',
6100
- label: '数据验证',
6101
- richOnly: true
6102
- },
6103
- {
6104
- value: 'all-except-borders',
6105
- label: '边框除外的全部',
6106
- richOnly: true
6107
- },
6108
- {
6109
- value: 'formulas-and-number-formats',
6110
- label: '公式和数字格式',
6111
- richOnly: true
6112
- },
6113
- {
6114
- value: 'values-and-number-formats',
6115
- label: '值和数字格式',
6116
- richOnly: true
6117
- },
6118
- {
6119
- value: 'column-widths',
6120
- label: '列宽',
6121
- richOnly: true
6122
- }
6123
- ];
6124
- const spreadsheetPasteOperationOptions = [
6125
- {
6126
- value: 'none',
6127
- label: '无'
6128
- },
6129
- {
6130
- value: 'add',
6131
- label: '加'
6132
- },
6133
- {
6134
- value: 'subtract',
6135
- label: '减'
6136
- },
6137
- {
6138
- value: 'multiply',
6139
- label: '乘'
6140
- },
6141
- {
6142
- value: 'divide',
6143
- label: '除'
6144
- }
6145
- ];
6146
6310
  const MILLISECONDS_PER_DAY = 86400000;
6147
6311
  const MINUTES_PER_DAY = 1440;
6148
6312
  const EXCEL_1900_EPOCH_UTC = Date.UTC(1899, 11, 30);
@@ -8608,6 +8772,7 @@ function createSpreadsheetEditorExtensions() {
8608
8772
  createSpreadsheetTableExtension(),
8609
8773
  createSpreadsheetAutoSumExtension(),
8610
8774
  createSpreadsheetCellFillExtension(),
8775
+ createSpreadsheetCopyFromAboveExtension(),
8611
8776
  createSpreadsheetVisibilityShortcutExtension(),
8612
8777
  createOfficeEditorExtension({
8613
8778
  name: 'spreadsheetFormatPainter',
@@ -24217,6 +24382,7 @@ function spreadsheetCommandsWithGridFocus(commands, restoreFocus) {
24217
24382
  activateFormatPainter: afterSuccessfulCommand(commands.activateFormatPainter),
24218
24383
  cancelFormatPainter: afterSuccessfulCommand(commands.cancelFormatPainter),
24219
24384
  clearSelectedCells: afterSuccessfulCommand(commands.clearSelectedCells),
24385
+ copyCellFromAbove: afterSuccessfulCommand(commands.copyCellFromAbove),
24220
24386
  copySelection: afterSuccessfulCommand(commands.copySelection),
24221
24387
  convertTableToRange: afterSuccessfulCommand(commands.convertTableToRange),
24222
24388
  cutSelection: afterSuccessfulCommand(commands.cutSelection),
@@ -852,6 +852,34 @@ export declare const spreadsheetCommandCatalog: {
852
852
  readonly group: "editing";
853
853
  };
854
854
  };
855
+ readonly copyFormulaFromAbove: {
856
+ readonly id: "editing.copyFormulaFromAbove";
857
+ readonly label: "复制上方公式";
858
+ readonly location: {
859
+ readonly area: "ribbon";
860
+ readonly tab: "home";
861
+ readonly group: "editing";
862
+ };
863
+ readonly shortcut: {
864
+ readonly label: "Ctrl+'";
865
+ readonly aria: "Control+'";
866
+ readonly editor: readonly ["Control-'"];
867
+ };
868
+ };
869
+ readonly copyValueFromAbove: {
870
+ readonly id: "editing.copyValueFromAbove";
871
+ readonly label: "复制上方值";
872
+ readonly location: {
873
+ readonly area: "ribbon";
874
+ readonly tab: "home";
875
+ readonly group: "editing";
876
+ };
877
+ readonly shortcut: {
878
+ readonly label: "Ctrl+Shift+'";
879
+ readonly aria: "Control+Shift+'";
880
+ readonly editor: readonly ["Control-Shift-'"];
881
+ };
882
+ };
855
883
  readonly clearAll: {
856
884
  readonly id: "editing.clearAll";
857
885
  readonly label: "清除全部";
@@ -10,6 +10,7 @@ import type { SpreadsheetCellFormatRequest } from './spreadsheet-cell-format';
10
10
  import type { SpreadsheetCellRange } from './spreadsheet-cell-range';
11
11
  import type { SpreadsheetCellStyleChoice } from './spreadsheet-cell-style';
12
12
  import type { SpreadsheetCellFillDirection } from './spreadsheet-cell-fill';
13
+ import type { SpreadsheetCopyFromAboveKind } from './spreadsheet-copy-from-above';
13
14
  import { type SpreadsheetFontSizeDirection } from './spreadsheet-font-size-command';
14
15
  import { type SpreadsheetDateTimeKind } from './spreadsheet-date-time-command';
15
16
  import type { SpreadsheetDataValidationRequest, SpreadsheetDataValidationTarget } from './spreadsheet-data-validation';
@@ -162,6 +163,7 @@ export interface SpreadsheetEditorCommands {
162
163
  applyTable: (request: SpreadsheetTableRequest) => boolean;
163
164
  cancelFormatPainter: () => boolean;
164
165
  clearSelectedCells: (mode?: SpreadsheetCellClearMode) => boolean;
166
+ copyCellFromAbove: (kind: SpreadsheetCopyFromAboveKind) => boolean;
165
167
  copySelection: () => boolean;
166
168
  cutSelection: () => boolean;
167
169
  deleteSelectedStructure: (axis: SpreadsheetStructureAxis) => boolean;
@@ -0,0 +1,3 @@
1
+ import { type OfficeEditorExtension } from './office-editor-extension';
2
+ import type { SpreadsheetCommandContext, SpreadsheetEditorCommands } from './spreadsheet-command-controller';
3
+ export declare function createSpreadsheetCopyFromAboveExtension(): OfficeEditorExtension<SpreadsheetCommandContext, SpreadsheetEditorCommands>;
@@ -0,0 +1,18 @@
1
+ import type { WorkSpreadsheetSheet } from '../work-types';
2
+ import type { SpreadsheetCellRange } from './spreadsheet-cell-range';
3
+ export type SpreadsheetCopyFromAboveKind = 'formula' | 'value';
4
+ export type SpreadsheetCopyFromAboveValue = boolean | number | string | null;
5
+ export interface SpreadsheetCopyFromAbovePlan {
6
+ formulaBarValue: SpreadsheetCopyFromAboveValue | '';
7
+ kind: SpreadsheetCopyFromAboveKind;
8
+ source: {
9
+ row: number;
10
+ column: number;
11
+ };
12
+ targetRange: SpreadsheetCellRange;
13
+ value: SpreadsheetCopyFromAboveValue;
14
+ }
15
+ export declare function planSpreadsheetCopyFromAbove(sheet: WorkSpreadsheetSheet | undefined, target: {
16
+ row: number;
17
+ column: number;
18
+ }, kind: SpreadsheetCopyFromAboveKind): SpreadsheetCopyFromAbovePlan | null;
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a3s-lab/office",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "description": "Open-source collaborative browser editors for documents, Markdown, spreadsheets, presentations, and PDFs.",
5
5
  "keywords": [
6
6
  "office",
@@ -89,6 +89,7 @@
89
89
  "playground:visual": "playwright test --config playwright.config.ts",
90
90
  "playground:visual:spreadsheet-data-validation": "playwright test visual-tests/spreadsheet-data-validation.functional.spec.ts --config playwright.config.ts",
91
91
  "playground:visual:spreadsheet-date-time": "playwright test visual-tests/spreadsheet-date-time.functional.spec.ts --config playwright.config.ts",
92
+ "playground:visual:spreadsheet-copy-from-above": "playwright test visual-tests/spreadsheet-copy-from-above.functional.spec.ts --config playwright.config.ts",
92
93
  "playground:visual:spreadsheet-diagonal-borders": "playwright test visual-tests/spreadsheet-diagonal-borders.functional.spec.ts --config playwright.config.ts",
93
94
  "playground:visual:spreadsheet-font-colors-shortcuts": "playwright test visual-tests/spreadsheet-font-colors-shortcuts.functional.spec.ts --config playwright.config.ts",
94
95
  "playground:visual:spreadsheet-hyperlink": "playwright test visual-tests/spreadsheet-hyperlink.functional.spec.ts --config playwright.config.ts",
@@ -163,6 +164,8 @@
163
164
  "test:e2e:spreadsheet-diagonal-borders:check": "a3s-test check tests/e2e/spreadsheet-diagonal-borders.acl --json",
164
165
  "test:e2e:spreadsheet-date-time": "a3s-test run tests/e2e/spreadsheet-date-time.acl --json",
165
166
  "test:e2e:spreadsheet-date-time:check": "a3s-test check tests/e2e/spreadsheet-date-time.acl --json",
167
+ "test:e2e:spreadsheet-copy-from-above": "A3S_TEST_SUITE=tests/e2e/spreadsheet-copy-from-above.acl bash scripts/run-a3s-test-web-gate.sh",
168
+ "test:e2e:spreadsheet-copy-from-above:check": "a3s-test check tests/e2e/spreadsheet-copy-from-above.acl --json",
166
169
  "test:e2e:spreadsheet-hyperlink": "a3s-test run tests/e2e/spreadsheet-hyperlink.acl --json",
167
170
  "test:e2e:spreadsheet-hyperlink:check": "a3s-test check tests/e2e/spreadsheet-hyperlink.acl --json",
168
171
  "test:e2e:spreadsheet-maximum-sparse": "a3s-test run tests/e2e/spreadsheet-maximum-sparse.acl --json",