@a3s-lab/office 0.23.0 → 0.24.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 +3 -2
- package/dist/0~4595.js +3 -1
- package/dist/0~spreadsheet-editor.js +138 -46
- package/dist/internal/features/work/editors/office-select.d.ts +3 -1
- package/dist/internal/features/work/editors/spreadsheet-command-catalog.d.ts +28 -0
- package/dist/internal/features/work/editors/spreadsheet-command-controller.d.ts +3 -1
- package/dist/internal/features/work/editors/spreadsheet-format-cells-dialog-model.d.ts +1 -20
- package/dist/internal/features/work/editors/spreadsheet-format-cells-dialog-panels.d.ts +2 -0
- package/dist/internal/features/work/editors/spreadsheet-format-cells-dialog.d.ts +3 -1
- package/dist/internal/features/work/editors/spreadsheet-format-cells-intent.d.ts +32 -0
- package/dist/office-kernel.wasm +0 -0
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -124,8 +124,8 @@ baseline rather than one specific release.
|
|
|
124
124
|
| Capability | A3S Office today | Traditional Office baseline |
|
|
125
125
|
| --- | --- | --- |
|
|
126
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
|
-
| Formatting and style rendering | **Partial** — native fonts, colors, borders, alignment, number formats, cell styles,
|
|
128
|
-
| Ribbon and shortcuts | **Partial** — common Office-style Home/Data/View commands
|
|
127
|
+
| Formatting and style rendering | **Partial** — native fonts, colors, borders, alignment, number formats, cell styles, static date/time entry, and contrast-safe font preview | Broader themes, locale formats, rich text, and advanced style effects |
|
|
128
|
+
| 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 |
|
|
129
129
|
| Formulas and recalculation | **Partial** — dependency-aware calculation and common formula paths | Wider functions, arrays, volatile semantics, and calculation parity |
|
|
130
130
|
| Tables, pivots, charts, and rules | **Partial** — native tables, pivots, charts, conditional formatting, and validation | Calculated columns, slicers, pivot charts, advanced rules, and analysis |
|
|
131
131
|
| Large worksheets | **Supported with boundaries** — maximum-dimension sparse import/editing and viewport-bounded Canvas painting | Highly optimized native grid with hardware-dependent limits |
|
|
@@ -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.24.0 documentation](https://a3s-lab.github.io/Office/docs/0.24.0/)
|
|
1350
1351
|
- [A3S Office 0.23.0 documentation](https://a3s-lab.github.io/Office/docs/0.23.0/)
|
|
1351
1352
|
- [A3S Office 0.22.0 documentation](https://a3s-lab.github.io/Office/docs/0.22.0/)
|
|
1352
1353
|
- [A3S Office 0.21.0 documentation](https://a3s-lab.github.io/Office/docs/0.21.0/)
|
package/dist/0~4595.js
CHANGED
|
@@ -343,7 +343,7 @@ function Dialog({ title, description, children, footer, onClose, closeDisabled =
|
|
|
343
343
|
});
|
|
344
344
|
return "u" > typeof document && portalRootRef.current ? /*#__PURE__*/ createPortal(dialog, portalRootRef.current) : dialog;
|
|
345
345
|
}
|
|
346
|
-
function OfficeSelect({ ariaLabel, value, options, onValueChange, disabled = false, placeholder = '请选择', className = '' }) {
|
|
346
|
+
function OfficeSelect({ ariaLabel, value, options, onValueChange, disabled = false, placeholder = '请选择', className = '', ariaKeyShortcuts, initialFocus = false }) {
|
|
347
347
|
const reactId = useId().replaceAll(':', '');
|
|
348
348
|
const [open, setOpen] = useState(false);
|
|
349
349
|
const selectedIndex = useMemo(()=>options.findIndex((option)=>option.value === value), [
|
|
@@ -384,6 +384,8 @@ function OfficeSelect({ ariaLabel, value, options, onValueChange, disabled = fal
|
|
|
384
384
|
...triggerProps,
|
|
385
385
|
role: "combobox",
|
|
386
386
|
"aria-expanded": popoverOpen,
|
|
387
|
+
"aria-keyshortcuts": ariaKeyShortcuts,
|
|
388
|
+
"data-autofocus": initialFocus ? 'true' : void 0,
|
|
387
389
|
onClick: (event)=>{
|
|
388
390
|
if (!popoverOpen) {
|
|
389
391
|
const next = nearestEnabledOption(options, selectedIndex >= 0 ? selectedIndex : 0, 1);
|
|
@@ -3284,6 +3284,38 @@ const spreadsheetCommandCatalog = {
|
|
|
3284
3284
|
]
|
|
3285
3285
|
}
|
|
3286
3286
|
},
|
|
3287
|
+
formatCellsFont: {
|
|
3288
|
+
id: 'font.formatCellsFont',
|
|
3289
|
+
label: '设置字体格式',
|
|
3290
|
+
location: {
|
|
3291
|
+
area: 'ribbon',
|
|
3292
|
+
tab: 'home',
|
|
3293
|
+
group: 'font'
|
|
3294
|
+
},
|
|
3295
|
+
shortcut: {
|
|
3296
|
+
label: 'Cmd/Ctrl+Shift+F',
|
|
3297
|
+
aria: 'Control+Shift+F Meta+Shift+F',
|
|
3298
|
+
editor: [
|
|
3299
|
+
'Mod-Shift-f'
|
|
3300
|
+
]
|
|
3301
|
+
}
|
|
3302
|
+
},
|
|
3303
|
+
formatCellsFontSize: {
|
|
3304
|
+
id: 'font.formatCellsFontSize',
|
|
3305
|
+
label: '设置字号格式',
|
|
3306
|
+
location: {
|
|
3307
|
+
area: 'ribbon',
|
|
3308
|
+
tab: 'home',
|
|
3309
|
+
group: 'font'
|
|
3310
|
+
},
|
|
3311
|
+
shortcut: {
|
|
3312
|
+
label: 'Cmd/Ctrl+Shift+P',
|
|
3313
|
+
aria: 'Control+Shift+P Meta+Shift+P',
|
|
3314
|
+
editor: [
|
|
3315
|
+
'Mod-Shift-p'
|
|
3316
|
+
]
|
|
3317
|
+
}
|
|
3318
|
+
},
|
|
3287
3319
|
borderTop: {
|
|
3288
3320
|
id: 'font.borderTop',
|
|
3289
3321
|
label: '上框线',
|
|
@@ -4752,6 +4784,56 @@ function normalizeColor(value) {
|
|
|
4752
4784
|
function spreadsheet_cell_format_cellKey(row, column) {
|
|
4753
4785
|
return `${row}:${column}`;
|
|
4754
4786
|
}
|
|
4787
|
+
const spreadsheetFormatCellsTabs = [
|
|
4788
|
+
{
|
|
4789
|
+
id: 'number',
|
|
4790
|
+
label: '数字'
|
|
4791
|
+
},
|
|
4792
|
+
{
|
|
4793
|
+
id: 'alignment',
|
|
4794
|
+
label: '对齐'
|
|
4795
|
+
},
|
|
4796
|
+
{
|
|
4797
|
+
id: 'font',
|
|
4798
|
+
label: '字体'
|
|
4799
|
+
},
|
|
4800
|
+
{
|
|
4801
|
+
id: 'border',
|
|
4802
|
+
label: '边框'
|
|
4803
|
+
},
|
|
4804
|
+
{
|
|
4805
|
+
id: 'fill',
|
|
4806
|
+
label: '填充'
|
|
4807
|
+
},
|
|
4808
|
+
{
|
|
4809
|
+
id: 'protection',
|
|
4810
|
+
label: '保护'
|
|
4811
|
+
}
|
|
4812
|
+
];
|
|
4813
|
+
const defaultSpreadsheetFormatCellsOpenIntent = {
|
|
4814
|
+
tab: 'number'
|
|
4815
|
+
};
|
|
4816
|
+
const spreadsheetFormatCellsTabIds = new Set(spreadsheetFormatCellsTabs.map(({ id })=>id));
|
|
4817
|
+
function normalizeSpreadsheetFormatCellsOpenIntent(value) {
|
|
4818
|
+
if (void 0 === value) return defaultSpreadsheetFormatCellsOpenIntent;
|
|
4819
|
+
if (!spreadsheet_format_cells_intent_isRecord(value)) return null;
|
|
4820
|
+
const keys = Object.keys(value);
|
|
4821
|
+
if (keys.some((key)=>'tab' !== key && 'focus' !== key)) return null;
|
|
4822
|
+
if ('string' != typeof value.tab || !spreadsheetFormatCellsTabIds.has(value.tab)) return null;
|
|
4823
|
+
if ('font' !== value.tab) return void 0 === value.focus ? {
|
|
4824
|
+
tab: value.tab
|
|
4825
|
+
} : null;
|
|
4826
|
+
if (void 0 === value.focus) return {
|
|
4827
|
+
tab: 'font'
|
|
4828
|
+
};
|
|
4829
|
+
return 'fontFamily' === value.focus || 'fontSize' === value.focus ? {
|
|
4830
|
+
tab: 'font',
|
|
4831
|
+
focus: value.focus
|
|
4832
|
+
} : null;
|
|
4833
|
+
}
|
|
4834
|
+
function spreadsheet_format_cells_intent_isRecord(value) {
|
|
4835
|
+
return Boolean(value && 'object' == typeof value && !Array.isArray(value));
|
|
4836
|
+
}
|
|
4755
4837
|
function createSpreadsheetCellFormatExtension() {
|
|
4756
4838
|
return createOfficeEditorExtension({
|
|
4757
4839
|
name: 'spreadsheetCellFormat',
|
|
@@ -4766,17 +4848,27 @@ function createSpreadsheetCellFormatExtension() {
|
|
|
4766
4848
|
}
|
|
4767
4849
|
}),
|
|
4768
4850
|
addKeyboardShortcuts: ()=>({
|
|
4769
|
-
|
|
4851
|
+
[spreadsheetCommandCatalog.formatCells.shortcut.editor["0"]]: ({ can, commands }, event)=>runSpreadsheetFormatCellsShortcut(event, void 0, can.openFormatCells, commands.openFormatCells),
|
|
4852
|
+
[spreadsheetCommandCatalog.formatCellsFont.shortcut.editor["0"]]: ({ can, commands }, event)=>runSpreadsheetFormatCellsShortcut(event, {
|
|
4853
|
+
tab: 'font',
|
|
4854
|
+
focus: 'fontFamily'
|
|
4855
|
+
}, can.openFormatCells, commands.openFormatCells),
|
|
4856
|
+
[spreadsheetCommandCatalog.formatCellsFontSize.shortcut.editor["0"]]: ({ can, commands }, event)=>runSpreadsheetFormatCellsShortcut(event, {
|
|
4857
|
+
tab: 'font',
|
|
4858
|
+
focus: 'fontSize'
|
|
4859
|
+
}, can.openFormatCells, commands.openFormatCells)
|
|
4770
4860
|
})
|
|
4771
4861
|
});
|
|
4772
4862
|
}
|
|
4773
|
-
function canOpenSpreadsheetFormatCells(context) {
|
|
4863
|
+
function canOpenSpreadsheetFormatCells(context, intent) {
|
|
4864
|
+
if (!normalizeSpreadsheetFormatCellsOpenIntent(intent)) return false;
|
|
4774
4865
|
if (!context.editable || !context.formatCells.canOpen || !context.workbook || !context.targetSheetId || context.targetSheetId !== context.activeSheetId) return false;
|
|
4775
4866
|
const range = liveSpreadsheetFormatCellsRange(context);
|
|
4776
4867
|
return Boolean(range && spreadsheet_cell_range_spreadsheetCellRangeArea(range) <= 10000);
|
|
4777
4868
|
}
|
|
4778
|
-
function spreadsheet_cell_format_command_openSpreadsheetFormatCells(context) {
|
|
4779
|
-
|
|
4869
|
+
function spreadsheet_cell_format_command_openSpreadsheetFormatCells(context, intent) {
|
|
4870
|
+
const normalizedIntent = normalizeSpreadsheetFormatCellsOpenIntent(intent);
|
|
4871
|
+
if (!normalizedIntent || !canOpenSpreadsheetFormatCells(context, normalizedIntent) || !context.workbook) return false;
|
|
4780
4872
|
const selection = context.workbook.getSelection()?.at(-1) ?? context.fallbackRange;
|
|
4781
4873
|
const range = spreadsheet_cell_range_normalizeSpreadsheetCellRange(spreadsheetSingleRange(selection));
|
|
4782
4874
|
if (!range) return false;
|
|
@@ -4787,7 +4879,8 @@ function spreadsheet_cell_format_command_openSpreadsheetFormatCells(context) {
|
|
|
4787
4879
|
row: clampFocus(selection.row_focus, range.row),
|
|
4788
4880
|
column: clampFocus(selection.column_focus, range.column)
|
|
4789
4881
|
},
|
|
4790
|
-
cells: []
|
|
4882
|
+
cells: [],
|
|
4883
|
+
intent: normalizedIntent
|
|
4791
4884
|
};
|
|
4792
4885
|
try {
|
|
4793
4886
|
request.cells = context.workbook.getCellsByRange(range, {
|
|
@@ -4808,9 +4901,9 @@ function applySpreadsheetFormatCells(context, request) {
|
|
|
4808
4901
|
function liveSpreadsheetFormatCellsRange(context) {
|
|
4809
4902
|
return spreadsheet_cell_range_normalizeSpreadsheetCellRange(spreadsheetSingleRange(context.workbook?.getSelection()?.at(-1) ?? context.fallbackRange));
|
|
4810
4903
|
}
|
|
4811
|
-
function runSpreadsheetFormatCellsShortcut(event, canExecute, execute) {
|
|
4812
|
-
if (event.repeat || isOfficeShortcutBlocked(event.target) || isSpreadsheetNativeTextUndoTarget(event.target) || !canExecute()) return false;
|
|
4813
|
-
return execute();
|
|
4904
|
+
function runSpreadsheetFormatCellsShortcut(event, intent, canExecute, execute) {
|
|
4905
|
+
if (event.repeat || event.isComposing || isOfficeShortcutBlocked(event.target) || isSpreadsheetNativeTextUndoTarget(event.target) || !canExecute(intent)) return false;
|
|
4906
|
+
return execute(intent);
|
|
4814
4907
|
}
|
|
4815
4908
|
function clampFocus(value, range) {
|
|
4816
4909
|
const minimum = range[0] ?? 0;
|
|
@@ -13603,7 +13696,7 @@ function AlignmentPanel({ source, draft, errors, touched, setDraft, touch }) {
|
|
|
13603
13696
|
]
|
|
13604
13697
|
});
|
|
13605
13698
|
}
|
|
13606
|
-
function FontPanel({ source, draft, errors, touched, setDraft, touch }) {
|
|
13699
|
+
function FontPanel({ source, draft, errors, touched, initialFocus, setDraft, touch }) {
|
|
13607
13700
|
const familyMixed = source.fields.fontFamily.mixed && !touched.fontFamily;
|
|
13608
13701
|
const sizeMixed = source.fields.fontSize.mixed && !touched.fontSize;
|
|
13609
13702
|
const underlineMixed = source.fields.underline.mixed && !touched.underline;
|
|
@@ -13621,6 +13714,8 @@ function FontPanel({ source, draft, errors, touched, setDraft, touch }) {
|
|
|
13621
13714
|
label: "字体",
|
|
13622
13715
|
children: /*#__PURE__*/ jsx(OfficeSelect, {
|
|
13623
13716
|
ariaLabel: "单元格字体",
|
|
13717
|
+
ariaKeyShortcuts: spreadsheetCommandCatalog.formatCellsFont.shortcut.aria,
|
|
13718
|
+
initialFocus: 'fontFamily' === initialFocus,
|
|
13624
13719
|
value: familyMixed ? MIXED_VALUE : draft.fontFamily,
|
|
13625
13720
|
options: withMixedOption(spreadsheetFontFamilyOptions(draft.fontFamily), familyMixed),
|
|
13626
13721
|
onValueChange: (value)=>{
|
|
@@ -13637,6 +13732,8 @@ function FontPanel({ source, draft, errors, touched, setDraft, touch }) {
|
|
|
13637
13732
|
label: "字号",
|
|
13638
13733
|
children: /*#__PURE__*/ jsx(OfficeSelect, {
|
|
13639
13734
|
ariaLabel: "单元格字号",
|
|
13735
|
+
ariaKeyShortcuts: spreadsheetCommandCatalog.formatCellsFontSize.shortcut.aria,
|
|
13736
|
+
initialFocus: 'fontSize' === initialFocus,
|
|
13640
13737
|
value: sizeMixed ? MIXED_VALUE : String(draft.fontSize),
|
|
13641
13738
|
options: withMixedOption(spreadsheetFontSizeOptions(draft.fontSize), sizeMixed),
|
|
13642
13739
|
onValueChange: (value)=>{
|
|
@@ -13714,6 +13811,7 @@ function FontPanel({ source, draft, errors, touched, setDraft, touch }) {
|
|
|
13714
13811
|
/*#__PURE__*/ jsx("div", {
|
|
13715
13812
|
className: "work-spreadsheet-format-cells-font-preview",
|
|
13716
13813
|
style: {
|
|
13814
|
+
backgroundColor: spreadsheetFontPreviewBackground(draft.fontColor),
|
|
13717
13815
|
color: draft.fontColor,
|
|
13718
13816
|
fontFamily: draft.fontFamily,
|
|
13719
13817
|
fontSize: `${Math.max(10, draft.fontSize)}px`,
|
|
@@ -13731,6 +13829,21 @@ function FontPanel({ source, draft, errors, touched, setDraft, touch }) {
|
|
|
13731
13829
|
]
|
|
13732
13830
|
});
|
|
13733
13831
|
}
|
|
13832
|
+
function spreadsheetFontPreviewBackground(color) {
|
|
13833
|
+
const match = /^#([0-9a-f]{6})$/i.exec(color.trim());
|
|
13834
|
+
if (!match?.[1]) return '#f4f6f8';
|
|
13835
|
+
const channels = [
|
|
13836
|
+
0,
|
|
13837
|
+
2,
|
|
13838
|
+
4
|
|
13839
|
+
].map((offset)=>Number.parseInt(match[1].slice(offset, offset + 2), 16));
|
|
13840
|
+
const [red = 0, green = 0, blue = 0] = channels.map((channel)=>{
|
|
13841
|
+
const component = channel / 255;
|
|
13842
|
+
return component <= 0.04045 ? component / 12.92 : ((component + 0.055) / 1.055) ** 2.4;
|
|
13843
|
+
});
|
|
13844
|
+
const luminance = 0.2126 * red + 0.7152 * green + 0.0722 * blue;
|
|
13845
|
+
return luminance >= 0.55 ? '#172033' : '#f4f6f8';
|
|
13846
|
+
}
|
|
13734
13847
|
function BorderPanel({ source, draft, touched, setDraft, touch }) {
|
|
13735
13848
|
const hasTarget = (target)=>draft.borders.some((format)=>format.target === target);
|
|
13736
13849
|
const updateBorders = (borders)=>{
|
|
@@ -13983,32 +14096,6 @@ function borderCss(format) {
|
|
|
13983
14096
|
const style = 'dotted' === format.style ? 'dotted' : format.style.includes('dash') ? 'dashed' : 'solid';
|
|
13984
14097
|
return `${width}px ${style} ${format.color}`;
|
|
13985
14098
|
}
|
|
13986
|
-
const spreadsheetFormatCellsTabs = [
|
|
13987
|
-
{
|
|
13988
|
-
id: 'number',
|
|
13989
|
-
label: '数字'
|
|
13990
|
-
},
|
|
13991
|
-
{
|
|
13992
|
-
id: 'alignment',
|
|
13993
|
-
label: '对齐'
|
|
13994
|
-
},
|
|
13995
|
-
{
|
|
13996
|
-
id: 'font',
|
|
13997
|
-
label: '字体'
|
|
13998
|
-
},
|
|
13999
|
-
{
|
|
14000
|
-
id: 'border',
|
|
14001
|
-
label: '边框'
|
|
14002
|
-
},
|
|
14003
|
-
{
|
|
14004
|
-
id: 'fill',
|
|
14005
|
-
label: '填充'
|
|
14006
|
-
},
|
|
14007
|
-
{
|
|
14008
|
-
id: 'protection',
|
|
14009
|
-
label: '保护'
|
|
14010
|
-
}
|
|
14011
|
-
];
|
|
14012
14099
|
function createSpreadsheetFormatCellsDialogSource(content, sheetId, rangeInput, cells, requestedActiveCell) {
|
|
14013
14100
|
const range = spreadsheet_cell_range_normalizeSpreadsheetCellRange(rangeInput);
|
|
14014
14101
|
const sheet = content.sheets.find((candidate)=>candidate.id === sheetId);
|
|
@@ -14180,10 +14267,10 @@ function sameDialogValue(left, right) {
|
|
|
14180
14267
|
function clampIndex(value, minimum, maximum) {
|
|
14181
14268
|
return Math.min(maximum, Math.max(minimum, Math.trunc(value)));
|
|
14182
14269
|
}
|
|
14183
|
-
function SpreadsheetFormatCellsDialog({ source, restoreFocusTarget, onApply, onClose }) {
|
|
14270
|
+
function SpreadsheetFormatCellsDialog({ source, restoreFocusTarget, openIntent = defaultSpreadsheetFormatCellsOpenIntent, onApply, onClose }) {
|
|
14184
14271
|
const [draft, setDraft] = useState(()=>createSpreadsheetFormatCellsDraft(source));
|
|
14185
14272
|
const [touched, setTouched] = useState({});
|
|
14186
|
-
const [activeTab, setActiveTab] = useState(
|
|
14273
|
+
const [activeTab, setActiveTab] = useState(openIntent.tab);
|
|
14187
14274
|
const formId = useId();
|
|
14188
14275
|
const idBase = `spreadsheet-format-cells-${useId().replaceAll(':', '')}`;
|
|
14189
14276
|
const errors = spreadsheetFormatCellsDraftErrors(draft);
|
|
@@ -14244,6 +14331,7 @@ function SpreadsheetFormatCellsDialog({ source, restoreFocusTarget, onApply, onC
|
|
|
14244
14331
|
draft: draft,
|
|
14245
14332
|
errors: errors,
|
|
14246
14333
|
touched: touched,
|
|
14334
|
+
initialFocus: 'font' === openIntent.tab ? openIntent.focus : void 0,
|
|
14247
14335
|
setDraft: setDraft,
|
|
14248
14336
|
touch: (field)=>setTouched((current)=>({
|
|
14249
14337
|
...current,
|
|
@@ -23226,7 +23314,7 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
23226
23314
|
const [selectionState, setSelectionState] = useState(null);
|
|
23227
23315
|
const formatPainterSelectionHandlerRef = useRef((_sheetId, _selection)=>void 0);
|
|
23228
23316
|
const [contextMenu, setContextMenu] = useState(null);
|
|
23229
|
-
const [
|
|
23317
|
+
const [formatCellsDialog, setFormatCellsDialog] = useState(null);
|
|
23230
23318
|
const formatCellsInvokerRef = useRef(null);
|
|
23231
23319
|
const formatCellsSelectionRef = useRef(null);
|
|
23232
23320
|
const formatCellsApplyingRef = useRef(false);
|
|
@@ -23376,7 +23464,7 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
23376
23464
|
panelTriggerRef.current = null;
|
|
23377
23465
|
setPanel(null);
|
|
23378
23466
|
setContextMenu(null);
|
|
23379
|
-
|
|
23467
|
+
setFormatCellsDialog(null);
|
|
23380
23468
|
formatCellsInvokerRef.current = null;
|
|
23381
23469
|
formatCellsSelectionRef.current = null;
|
|
23382
23470
|
formatCellsApplyingRef.current = false;
|
|
@@ -23656,14 +23744,17 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
23656
23744
|
column_focus: request.activeCell.column
|
|
23657
23745
|
}
|
|
23658
23746
|
};
|
|
23659
|
-
|
|
23747
|
+
setFormatCellsDialog({
|
|
23748
|
+
source,
|
|
23749
|
+
intent: request.intent
|
|
23750
|
+
});
|
|
23660
23751
|
return true;
|
|
23661
23752
|
}, []);
|
|
23662
23753
|
const closeSpreadsheetFormatCells = useCallback(()=>{
|
|
23663
23754
|
const invoker = formatCellsInvokerRef.current;
|
|
23664
23755
|
const canvas = spreadsheetCanvasRef.current;
|
|
23665
23756
|
const openedFromGrid = Boolean(invoker && canvas?.contains(invoker));
|
|
23666
|
-
|
|
23757
|
+
setFormatCellsDialog(null);
|
|
23667
23758
|
requestAnimationFrame(()=>{
|
|
23668
23759
|
if (openedFromGrid || !invoker?.isConnected) focusSpreadsheetGrid(canvas, {
|
|
23669
23760
|
focusOrigin: invoker
|
|
@@ -23804,7 +23895,7 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
23804
23895
|
},
|
|
23805
23896
|
formatPainter,
|
|
23806
23897
|
formatCells: {
|
|
23807
|
-
canOpen: !preview && null ===
|
|
23898
|
+
canOpen: !preview && null === formatCellsDialog,
|
|
23808
23899
|
open: openSpreadsheetFormatCells
|
|
23809
23900
|
},
|
|
23810
23901
|
hyperlink: spreadsheetHyperlink.commandPort,
|
|
@@ -24247,16 +24338,17 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
24247
24338
|
onClose: ()=>setContextMenu(null),
|
|
24248
24339
|
onRestoreFocus: ()=>focusSpreadsheetGrid(spreadsheetCanvasRef.current)
|
|
24249
24340
|
}),
|
|
24250
|
-
|
|
24251
|
-
source:
|
|
24341
|
+
formatCellsDialog && /*#__PURE__*/ jsx(SpreadsheetFormatCellsDialog, {
|
|
24342
|
+
source: formatCellsDialog.source,
|
|
24343
|
+
openIntent: formatCellsDialog.intent,
|
|
24252
24344
|
restoreFocusTarget: ()=>formatCellsInvokerRef.current?.isConnected ? formatCellsInvokerRef.current : spreadsheetGridFocusTarget(spreadsheetCanvasRef.current),
|
|
24253
24345
|
onApply: (patch)=>{
|
|
24254
24346
|
formatCellsApplyingRef.current = true;
|
|
24255
24347
|
let handled = false;
|
|
24256
24348
|
try {
|
|
24257
24349
|
handled = spreadsheetCommands.applyCellFormat({
|
|
24258
|
-
sheetId:
|
|
24259
|
-
range:
|
|
24350
|
+
sheetId: formatCellsDialog.source.sheetId,
|
|
24351
|
+
range: formatCellsDialog.source.range,
|
|
24260
24352
|
patch
|
|
24261
24353
|
});
|
|
24262
24354
|
} finally{
|
|
@@ -8,7 +8,7 @@ export interface OfficeSelectOption<T extends string = string> {
|
|
|
8
8
|
previewStyle?: CSSProperties;
|
|
9
9
|
searchText?: string;
|
|
10
10
|
}
|
|
11
|
-
export declare function OfficeSelect<T extends string>({ ariaLabel, value, options, onValueChange, disabled, placeholder, className, }: {
|
|
11
|
+
export declare function OfficeSelect<T extends string>({ ariaLabel, value, options, onValueChange, disabled, placeholder, className, ariaKeyShortcuts, initialFocus, }: {
|
|
12
12
|
ariaLabel: string;
|
|
13
13
|
value: T;
|
|
14
14
|
options: readonly OfficeSelectOption<T>[];
|
|
@@ -16,4 +16,6 @@ export declare function OfficeSelect<T extends string>({ ariaLabel, value, optio
|
|
|
16
16
|
disabled?: boolean;
|
|
17
17
|
placeholder?: string;
|
|
18
18
|
className?: string;
|
|
19
|
+
ariaKeyShortcuts?: string;
|
|
20
|
+
initialFocus?: boolean;
|
|
19
21
|
}): import("react").JSX.Element;
|
|
@@ -406,6 +406,34 @@ export declare const spreadsheetCommandCatalog: {
|
|
|
406
406
|
readonly editor: readonly ["Mod-1"];
|
|
407
407
|
};
|
|
408
408
|
};
|
|
409
|
+
readonly formatCellsFont: {
|
|
410
|
+
readonly id: "font.formatCellsFont";
|
|
411
|
+
readonly label: "设置字体格式";
|
|
412
|
+
readonly location: {
|
|
413
|
+
readonly area: "ribbon";
|
|
414
|
+
readonly tab: "home";
|
|
415
|
+
readonly group: "font";
|
|
416
|
+
};
|
|
417
|
+
readonly shortcut: {
|
|
418
|
+
readonly label: "Cmd/Ctrl+Shift+F";
|
|
419
|
+
readonly aria: "Control+Shift+F Meta+Shift+F";
|
|
420
|
+
readonly editor: readonly ["Mod-Shift-f"];
|
|
421
|
+
};
|
|
422
|
+
};
|
|
423
|
+
readonly formatCellsFontSize: {
|
|
424
|
+
readonly id: "font.formatCellsFontSize";
|
|
425
|
+
readonly label: "设置字号格式";
|
|
426
|
+
readonly location: {
|
|
427
|
+
readonly area: "ribbon";
|
|
428
|
+
readonly tab: "home";
|
|
429
|
+
readonly group: "font";
|
|
430
|
+
};
|
|
431
|
+
readonly shortcut: {
|
|
432
|
+
readonly label: "Cmd/Ctrl+Shift+P";
|
|
433
|
+
readonly aria: "Control+Shift+P Meta+Shift+P";
|
|
434
|
+
readonly editor: readonly ["Mod-Shift-p"];
|
|
435
|
+
};
|
|
436
|
+
};
|
|
409
437
|
readonly borderTop: {
|
|
410
438
|
readonly id: "font.borderTop";
|
|
411
439
|
readonly label: "上框线";
|
|
@@ -7,6 +7,7 @@ import type { SpreadsheetAutoSumFunction } from './spreadsheet-auto-sum';
|
|
|
7
7
|
import { type SpreadsheetCellClearMode } from './spreadsheet-cell-clear';
|
|
8
8
|
import type { SpreadsheetCellBorderFormat } from './spreadsheet-cell-border';
|
|
9
9
|
import type { SpreadsheetCellFormatRequest } from './spreadsheet-cell-format';
|
|
10
|
+
import type { SpreadsheetFormatCellsOpenIntent } from './spreadsheet-format-cells-intent';
|
|
10
11
|
import type { SpreadsheetCellRange } from './spreadsheet-cell-range';
|
|
11
12
|
import type { SpreadsheetCellStyleChoice } from './spreadsheet-cell-style';
|
|
12
13
|
import type { SpreadsheetCellFillDirection } from './spreadsheet-cell-fill';
|
|
@@ -119,6 +120,7 @@ export interface SpreadsheetFormatCellsOpenRequest {
|
|
|
119
120
|
column: number;
|
|
120
121
|
};
|
|
121
122
|
cells: (Cell | null)[][];
|
|
123
|
+
intent: SpreadsheetFormatCellsOpenIntent;
|
|
122
124
|
}
|
|
123
125
|
export interface SpreadsheetFormatCellsCommandPort {
|
|
124
126
|
canOpen: boolean;
|
|
@@ -179,7 +181,7 @@ export interface SpreadsheetEditorCommands {
|
|
|
179
181
|
openAutoFilterMenu: () => boolean;
|
|
180
182
|
openDataValidation: () => boolean;
|
|
181
183
|
openFind: () => boolean;
|
|
182
|
-
openFormatCells: () => boolean;
|
|
184
|
+
openFormatCells: (intent?: SpreadsheetFormatCellsOpenIntent) => boolean;
|
|
183
185
|
openGoTo: () => boolean;
|
|
184
186
|
openHyperlink: () => boolean;
|
|
185
187
|
openPasteSpecial: () => boolean;
|
|
@@ -4,26 +4,7 @@ import { type SpreadsheetUnderlineStyle } from '../work-spreadsheet-underline';
|
|
|
4
4
|
import { type SpreadsheetCellBorderFormat, type SpreadsheetCellBorderStyle } from './spreadsheet-cell-border';
|
|
5
5
|
import { type SpreadsheetCellFormatPatch, type SpreadsheetHorizontalAlignment, type SpreadsheetVerticalAlignment } from './spreadsheet-cell-format';
|
|
6
6
|
import { type SpreadsheetCellRange } from './spreadsheet-cell-range';
|
|
7
|
-
export
|
|
8
|
-
readonly id: "number";
|
|
9
|
-
readonly label: "数字";
|
|
10
|
-
}, {
|
|
11
|
-
readonly id: "alignment";
|
|
12
|
-
readonly label: "对齐";
|
|
13
|
-
}, {
|
|
14
|
-
readonly id: "font";
|
|
15
|
-
readonly label: "字体";
|
|
16
|
-
}, {
|
|
17
|
-
readonly id: "border";
|
|
18
|
-
readonly label: "边框";
|
|
19
|
-
}, {
|
|
20
|
-
readonly id: "fill";
|
|
21
|
-
readonly label: "填充";
|
|
22
|
-
}, {
|
|
23
|
-
readonly id: "protection";
|
|
24
|
-
readonly label: "保护";
|
|
25
|
-
}];
|
|
26
|
-
export type SpreadsheetFormatCellsTabId = (typeof spreadsheetFormatCellsTabs)[number]['id'];
|
|
7
|
+
export { spreadsheetFormatCellsTabs, type SpreadsheetFormatCellsTabId, } from './spreadsheet-format-cells-intent';
|
|
27
8
|
export interface SpreadsheetFormatCellsField<T> {
|
|
28
9
|
value: T;
|
|
29
10
|
mixed: boolean;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Dispatch, SetStateAction } from 'react';
|
|
2
2
|
import type { SpreadsheetCellFormatPatch } from './spreadsheet-cell-format';
|
|
3
3
|
import type { SpreadsheetFormatCellsDialogSource, SpreadsheetFormatCellsDraft, SpreadsheetFormatCellsDraftErrors, SpreadsheetFormatCellsTabId, SpreadsheetFormatCellsTouched } from './spreadsheet-format-cells-dialog-model';
|
|
4
|
+
import type { SpreadsheetFormatCellsInitialFocus } from './spreadsheet-format-cells-intent';
|
|
4
5
|
interface PanelProps {
|
|
5
6
|
activeTab: SpreadsheetFormatCellsTabId;
|
|
6
7
|
idBase: string;
|
|
@@ -8,6 +9,7 @@ interface PanelProps {
|
|
|
8
9
|
draft: SpreadsheetFormatCellsDraft;
|
|
9
10
|
errors: SpreadsheetFormatCellsDraftErrors;
|
|
10
11
|
touched: SpreadsheetFormatCellsTouched;
|
|
12
|
+
initialFocus?: SpreadsheetFormatCellsInitialFocus;
|
|
11
13
|
setDraft: Dispatch<SetStateAction<SpreadsheetFormatCellsDraft>>;
|
|
12
14
|
touch: (field: keyof SpreadsheetCellFormatPatch) => void;
|
|
13
15
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { SpreadsheetCellFormatPatch } from './spreadsheet-cell-format';
|
|
2
2
|
import { type SpreadsheetFormatCellsDialogSource } from './spreadsheet-format-cells-dialog-model';
|
|
3
|
-
|
|
3
|
+
import { type SpreadsheetFormatCellsOpenIntent } from './spreadsheet-format-cells-intent';
|
|
4
|
+
export declare function SpreadsheetFormatCellsDialog({ source, restoreFocusTarget, openIntent, onApply, onClose, }: {
|
|
4
5
|
source: SpreadsheetFormatCellsDialogSource;
|
|
5
6
|
restoreFocusTarget: () => HTMLElement | null;
|
|
7
|
+
openIntent?: SpreadsheetFormatCellsOpenIntent;
|
|
6
8
|
onApply: (patch: SpreadsheetCellFormatPatch) => boolean;
|
|
7
9
|
onClose: () => void;
|
|
8
10
|
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare const spreadsheetFormatCellsTabs: readonly [{
|
|
2
|
+
readonly id: "number";
|
|
3
|
+
readonly label: "数字";
|
|
4
|
+
}, {
|
|
5
|
+
readonly id: "alignment";
|
|
6
|
+
readonly label: "对齐";
|
|
7
|
+
}, {
|
|
8
|
+
readonly id: "font";
|
|
9
|
+
readonly label: "字体";
|
|
10
|
+
}, {
|
|
11
|
+
readonly id: "border";
|
|
12
|
+
readonly label: "边框";
|
|
13
|
+
}, {
|
|
14
|
+
readonly id: "fill";
|
|
15
|
+
readonly label: "填充";
|
|
16
|
+
}, {
|
|
17
|
+
readonly id: "protection";
|
|
18
|
+
readonly label: "保护";
|
|
19
|
+
}];
|
|
20
|
+
export type SpreadsheetFormatCellsTabId = (typeof spreadsheetFormatCellsTabs)[number]['id'];
|
|
21
|
+
export type SpreadsheetFormatCellsInitialFocus = 'fontFamily' | 'fontSize';
|
|
22
|
+
export type SpreadsheetFormatCellsOpenIntent = {
|
|
23
|
+
tab: 'font';
|
|
24
|
+
focus?: SpreadsheetFormatCellsInitialFocus;
|
|
25
|
+
} | {
|
|
26
|
+
tab: Exclude<SpreadsheetFormatCellsTabId, 'font'>;
|
|
27
|
+
focus?: never;
|
|
28
|
+
};
|
|
29
|
+
export declare const defaultSpreadsheetFormatCellsOpenIntent: {
|
|
30
|
+
readonly tab: "number";
|
|
31
|
+
};
|
|
32
|
+
export declare function normalizeSpreadsheetFormatCellsOpenIntent(value: unknown): SpreadsheetFormatCellsOpenIntent | null;
|
package/dist/office-kernel.wasm
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@a3s-lab/office",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Open-source collaborative browser editors for documents, Markdown, spreadsheets, presentations, and PDFs.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"office",
|
|
@@ -90,6 +90,7 @@
|
|
|
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
92
|
"playground:visual:spreadsheet-copy-from-above": "playwright test visual-tests/spreadsheet-copy-from-above.functional.spec.ts --config playwright.config.ts",
|
|
93
|
+
"playground:visual:spreadsheet-font-dialog-shortcuts": "playwright test visual-tests/spreadsheet-font-dialog-shortcuts.functional.spec.ts --config playwright.config.ts",
|
|
93
94
|
"playground:visual:spreadsheet-diagonal-borders": "playwright test visual-tests/spreadsheet-diagonal-borders.functional.spec.ts --config playwright.config.ts",
|
|
94
95
|
"playground:visual:spreadsheet-font-colors-shortcuts": "playwright test visual-tests/spreadsheet-font-colors-shortcuts.functional.spec.ts --config playwright.config.ts",
|
|
95
96
|
"playground:visual:spreadsheet-hyperlink": "playwright test visual-tests/spreadsheet-hyperlink.functional.spec.ts --config playwright.config.ts",
|
|
@@ -166,6 +167,8 @@
|
|
|
166
167
|
"test:e2e:spreadsheet-date-time:check": "a3s-test check tests/e2e/spreadsheet-date-time.acl --json",
|
|
167
168
|
"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
169
|
"test:e2e:spreadsheet-copy-from-above:check": "a3s-test check tests/e2e/spreadsheet-copy-from-above.acl --json",
|
|
170
|
+
"test:e2e:spreadsheet-font-dialog-shortcuts": "A3S_TEST_SUITE=tests/e2e/spreadsheet-font-dialog-shortcuts.acl bash scripts/run-a3s-test-web-gate.sh",
|
|
171
|
+
"test:e2e:spreadsheet-font-dialog-shortcuts:check": "a3s-test check tests/e2e/spreadsheet-font-dialog-shortcuts.acl --json",
|
|
169
172
|
"test:e2e:spreadsheet-hyperlink": "a3s-test run tests/e2e/spreadsheet-hyperlink.acl --json",
|
|
170
173
|
"test:e2e:spreadsheet-hyperlink:check": "a3s-test check tests/e2e/spreadsheet-hyperlink.acl --json",
|
|
171
174
|
"test:e2e:spreadsheet-maximum-sparse": "a3s-test run tests/e2e/spreadsheet-maximum-sparse.acl --json",
|