@a3s-lab/office 0.21.0 → 0.22.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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  This roadmap defines one versioned collaboration protocol for every A3S Office
4
4
  editor and for native CLI/coding-agent clients. It complements `ROADMAP.md`,
5
- which tracks editor capability parity with WPS.
5
+ which tracks editor capability parity with Traditional Office.
6
6
 
7
7
  ## Design invariants
8
8
 
package/README.md CHANGED
@@ -22,11 +22,11 @@
22
22
  <a href="https://a3s-lab.github.io/Office/">Playground</a> ·
23
23
  <a href="https://a3s-lab.github.io/Office/docs/">Documentation</a> ·
24
24
  <a href="#quick-start">Quick start</a> ·
25
- <a href="#five-format-native-surfaces">Editors</a> ·
25
+ <a href="#editor-capability-comparison">Editors</a> ·
26
26
  <a href="#real-time-collaboration">Collaboration</a> ·
27
27
  <a href="#native-automation">Automation</a> ·
28
28
  <a href="#architecture">Architecture</a> ·
29
- <a href="ROADMAP.md">WPS gap roadmap</a> ·
29
+ <a href="ROADMAP.md">Capability roadmap</a> ·
30
30
  <a href="COLLABORATION_ROADMAP.md">Collaboration roadmap</a> ·
31
31
  <a href="CONTRIBUTING.md">Contributing</a>
32
32
  </p>
@@ -96,6 +96,86 @@ The images below are committed visual-regression baselines from the real
96
96
  </tr>
97
97
  </table>
98
98
 
99
+ ## Editor capability comparison
100
+
101
+ The tables below compare capability families, not button counts or visual
102
+ similarity. **Supported** means the editable path has deterministic tests or
103
+ native round-trip evidence. **Partial** means a useful path exists with a
104
+ documented fidelity boundary. **Gap** means no product-grade editable path
105
+ exists yet. Traditional Office availability varies by application, platform,
106
+ edition, and subscription; its column describes the conventional suite
107
+ baseline rather than one specific release.
108
+
109
+ ### Document
110
+
111
+ | Capability | A3S Office today | Traditional Office baseline |
112
+ | --- | --- | --- |
113
+ | Text, paragraphs, lists, and styles | **Supported** — structured editing, formatting, clipboard, format painter, and undo/redo | Mature authoring with a broader long-tail style catalog |
114
+ | Page layout and rendering | **Partial** — sections, margins, page size, columns, headers/footers, fields, and live pagination | Desktop-grade pagination, print layout, and vector output |
115
+ | Tables, pictures, and equations | **Partial** — rich table geometry, floating pictures, crop/wrap, and structured OMML | Broader drawings, text boxes, charts, WordArt, and SmartArt |
116
+ | Comments, revisions, and collaboration | **Partial** — comments, suggestions, text/format revisions, decisions, Yjs presence, and host relay contracts | Full revision families plus integrated sharing and review services |
117
+ | References and document generation | **Partial** — bookmarks, links, captions, cross-references, citations, notes, and common fields | TOC/index authoring, mail merge, compare/combine, and broader fields |
118
+ | Ribbon and shortcuts | **Supported** — responsive Office-style ribbon and editor-scoped daily-writing shortcuts | Complete desktop shortcut and contextual-tool surface |
119
+ | Very large documents | **Supported with boundaries** — bounded 100,000-block plain-document windows and measured edit/navigation budgets | Native-engine virtualization with device-dependent limits |
120
+ | DOCX and PDF fidelity | **Partial** — source-aware DOCX preservation and live-layout raster PDF export | Broader legacy/OOXML compatibility and searchable vector PDF output |
121
+
122
+ ### Spreadsheet
123
+
124
+ | Capability | A3S Office today | Traditional Office baseline |
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 |
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
+ | Ribbon and shortcuts | **Partial** — common Office-style Home/Data/View commands and grid-scoped shortcuts | Larger command catalog and platform-specific accelerators |
129
+ | Formulas and recalculation | **Partial** — dependency-aware calculation and common formula paths | Wider functions, arrays, volatile semantics, and calculation parity |
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
+ | Large worksheets | **Supported with boundaries** — maximum-dimension sparse import/editing and viewport-bounded Canvas painting | Highly optimized native grid with hardware-dependent limits |
132
+ | Files and printing | **Partial** — XLS/XLSX/ODS/CSV import, XLSX export, and PDF output | Broader round trips, external data, print fidelity, and legacy conversion |
133
+ | 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 |
134
+
135
+ ### Presentation
136
+
137
+ | Capability | A3S Office today | Traditional Office baseline |
138
+ | --- | --- | --- |
139
+ | Slide and object editing | **Supported** — slide lifecycle, scene editing, multi-selection, grouping, transforms, and guides | Mature slide and drawing workflows |
140
+ | Text, shapes, tables, charts, and images | **Partial** — typed editable objects with native import/export paths | Broader shapes, connectors, effects, SmartArt, and embedded chart editing |
141
+ | Masters and layouts | **Partial** — import/export inheritance with editable common paths | Full visual master, layout, and placeholder authoring |
142
+ | Transitions and timings | **Partial** — fade, push, wipe, split, cut, and click/automatic advance | Broader transition catalog and timing controls |
143
+ | Animations and media | **Gap** — no production animation timeline, trigger model, audio, video, or recording path | Object animation, motion paths, media editing, and recording |
144
+ | Slideshow and presenter workflows | **Supported** — current/beginning start, keyboard playback, notes, timer, and responsive presenter view | Rehearsal, recording, ink/laser, and richer multi-display controls |
145
+ | Review and collaboration | **Partial** — comments, shared presence, remote object locations, and host transport | Threads, assignments, mentions, and integrated cloud review |
146
+ | PPTX, print, PDF, and video | **Partial** — PPTX round trip plus slide/notes/handout PDF models; no video export | Broader print controls, vector fidelity, media preservation, and video export |
147
+
148
+ ### PDF
149
+
150
+ | Capability | A3S Office today | Traditional Office baseline |
151
+ | --- | --- | --- |
152
+ | Rendering and navigation | **Supported** — PDFium pages, thumbnails, zoom, keyboard navigation, and bounded long-file windows | Mature desktop/web viewing and navigation |
153
+ | Search and text evidence | **Supported with boundaries** — browser search and bounded native text-layer evidence | Broader tagged-PDF reading order and accessibility extraction |
154
+ | Annotations, forms, and save | **Supported** — common annotations, appearance controls, form filling, history, and save | Broader stamps, measurements, form authoring, scripts, and signatures |
155
+ | Existing text, image, and object editing | **Gap** — no safe production content-stream editing path | Direct text/object editing with font and layout recovery |
156
+ | Page organization | **Gap** — insert, delete, rotate, reorder, extract, merge, and split are not yet editable | Complete page organization workflows |
157
+ | Compression, conversion, and OCR | **Gap / host boundary** — provider contracts are required for authoritative conversion and OCR | Integrated optimization, conversion, and scanned-document recognition |
158
+ | Signatures, protection, and redaction | **Gap / host boundary** — trusted identity and destructive-content guarantees are required | E-signing, certificate validation, encryption, sanitization, and true redaction |
159
+ | AI and real-time collaboration | **Host-owned** — typed page/text evidence, Yjs review records, presence, and provider-neutral ports | Typically bundled with account, storage, and model services |
160
+
161
+ ### Markdown
162
+
163
+ Markdown is an A3S Office differentiator rather than a parity target.
164
+
165
+ | Capability | A3S Office today | Traditional Office baseline |
166
+ | --- | --- | --- |
167
+ | Source and visual editing | **Supported** — GFM source, visual mode, synchronized split preview, and source-native history | No standard first-class Markdown editor |
168
+ | Tables, tasks, links, images, and code | **Supported** — format-native Markdown structures in both editing modes | Usually represented through rich-document conversion or plain text |
169
+ | Responsive UI and shortcuts | **Supported** — desktop split view, phone single-surface modes, and editor-scoped formatting | Depends on a text editor, add-in, or conversion workflow |
170
+ | Collaboration | **Supported** — Yjs content, Awareness presence, remote selections, and host-owned transport | Usually available only after conversion into a cloud document format |
171
+ | Import, export, and automation | **Supported** — direct Markdown round trip plus typed browser, CLI, MCP, and agent mutations | No shared native Markdown automation contract |
172
+
173
+ Document and Markdown accept public TipTap Extensions. Spreadsheet,
174
+ Presentation, and PDF expose stable host ports rather than private command
175
+ contexts. Editor engines and large runtime assets load only when their surface
176
+ is requested. The complete gap inventory and exit evidence live in the
177
+ [capability roadmap](ROADMAP.md).
178
+
99
179
  ## Why A3S Office
100
180
 
101
181
  - **Product-native UI** — Complete Office-style surfaces with no required
@@ -397,274 +477,6 @@ into the PDF; searchable text and vector output remain future fidelity work.
397
477
  Copyable React, Vue, and Web Component examples live in the
398
478
  [component documentation](https://a3s-lab.github.io/Office/docs/components/).
399
479
 
400
- ## Five format-native surfaces
401
-
402
- Each surface keeps a canonical model that matches its file format and user
403
- interaction model.
404
-
405
- - **Document** — Pagination, sections, focused page-setup tabs, clean page
406
- margins with on-demand header/footer editing, outline navigation with
407
- contextual full-text results, keyboard-operated live physical-page raster
408
- thumbnails with viewport-bounded capture, and shared virtualized
409
- long-document windows for page buttons, heading rows, full-text results, and
410
- tracked-revision and anchored-comment review that preserve native scroll
411
- distance, sparse current/selection/draft pins, and Home/End reachability;
412
- a WPS-familiar command catalog, quick-access undo and redo, a priority-aware
413
- adaptive and persistently collapsible ribbon whose tabs can temporarily
414
- expose commands; WPS-oriented Insert groups and direct Page Layout presets
415
- for margins, orientation, paper size, and columns, with matching advanced
416
- Page Setup destinations; WPS-oriented References, Review, and View groups,
417
- direct tracked-change navigation and decisions, contextual object tabs, and
418
- viewport-calculated 100%, one-page, and page-width zoom; an actionable status
419
- bar with live word-count details, WPS `Ctrl+Shift+G`, keyboard-traversable
420
- view and zoom controls, and compact Web prioritization; editor-scoped WPS
421
- formatting, paragraph, style, and review shortcuts, plus a permission-free
422
- formatting clipboard and one-shot format painter shared with compatible
423
- header and footer formatting, paragraph styles and phone-sized
424
- paragraph-spacing and pagination controls
425
- with touch targets and exact invoker-focus restoration; stable compact-ribbon
426
- edge paging and viewport-bounded list galleries with touch-sized numbering
427
- actions, selection-preserving bullet and numbering commands, and explicit
428
- Escape-to-invoker focus restoration;
429
- grouped bundled, common system, monospace, imported, and host-provided font
430
- choices with live typeface previews, independent table layout algorithms,
431
- auto, percentage, or pixel preferred widths, left/center/right placement,
432
- indentation, table-level cell margins, cell-level margin overrides, and
433
- rendered column measurements for autofit tables. One Table Properties dialog
434
- presents table, row, column, and cell tabs. It combines preferred width,
435
- placement, and indent with selected-row height and pagination, current-column
436
- width, and selected-cell vertical alignment and margins. The complete draft
437
- commits in one TipTap transaction and one undo record while untouched imported
438
- measurements and partial margin inheritance retain their exact source values.
439
- Cancel and Escape discard the draft and restore the exact ribbon invoker;
440
- compact layouts keep tabs, numeric steppers, and footer actions touch-sized. A
441
- contextual Picture Properties workflow combines centimeter width and height,
442
- a per-image aspect-ratio lock, inline/square/top-and-bottom wrapping,
443
- alignment, text distance, and alternative text. It commits only changed
444
- fields in one TipTap history entry, preserves untouched imported dimensions
445
- exactly, and retains the image selection and invoker focus after apply,
446
- cancel, or Escape on desktop and phone layouts. A
447
- reusable table-border pen with all, outside, inside, and individual-edge
448
- targets, per-edge DOCX border preservation, and bounded `basedOn` table-style
449
- inheritance with whole-table, banded row or column, first/last row or column,
450
- and corner-cell formatting. Conditional fills, borders, bold, italic,
451
- underline, strikethrough, fonts, and text colors are materialized before
452
- direct table, cell, paragraph, and run formatting. Conditional paragraph
453
- alignment, direction, indents, spacing and line rules, pagination rules, and
454
- tab stops use the same precedence chain. Paragraph shading follows document
455
- defaults, based-on paragraph styles, conditional table styles, and direct
456
- formatting in that order. The complete Word `w:shd` pattern set, independent
457
- foreground/background colors, `auto`, `nil` resets, and independently tinted
458
- or shaded theme references remain structured through body and page-chrome
459
- HTML; browser previews use bounded CSS masks while DOCX export restores the
460
- native pattern and both theme channels. Preview follows Word's tint-over-shade
461
- precedence when both transforms occur on one theme channel while retaining
462
- both attributes for export. Malformed, duplicated,
463
- namespace-spoofed, relationship-bound, or unresolved theme values fail closed
464
- instead of inheriting stale shading. Theme tint and shade values resolve for
465
- table borders and cell fills across edit, preview, and RGB-stable export.
466
- Paragraph borders use the same precedence chain and retain the complete
467
- `w:pBdr` model: schema-ordered `top`, `left`, `bottom`, `right`, `between`,
468
- and facing-page `bar` edges; all 197 line and art styles; direct, automatic,
469
- and theme colors; eighth-point or point widths; spacing; shadow; and frame.
470
- Physical edges remain editable CSS, while art, between-paragraph, and
471
- facing-page behavior uses a bounded browser approximation; DOCX export
472
- restores the exact native edge set and attributes. Direct CSS edits replace
473
- only the edited edge's theme binding, strict and transitional namespaces are
474
- accepted, and malformed order, duplicates, spoofed namespaces, unsafe
475
- attributes, invalid measures, and unresolved themes fail closed.
476
- Splittable table rows that exceed a full physical page
477
- continue at paragraph boundaries with repeated heading rows on every page,
478
- viewport-safe comment drafting and focus-preserving citation drafts, tracked
479
- changes, notes,
480
- pointer- and Shift+F10-accessible host-defined selection menus, and shared
481
- edit/preview/PDF typography and page-chrome placement. Editing, read-only
482
- preview, and browser PDF export share one live pagination result. Tail edits
483
- reuse the stable physical-page prefix, including resolved first/odd/even
484
- headers, footers, page numbers, and navigation descriptors. Browser DOM
485
- measurement runs in bounded 32 ms slices and yields only between top-level
486
- blocks; document edits abort stale passes before a snapshot is committed, so
487
- long repagination work does not monopolize the browser event loop.
488
- Real DOCX fixtures provide deterministic A3S Test evidence for inherited
489
- table styling across edit and preview, a centered 62.5% table with table and
490
- cell margin overrides, all four Table Properties tabs at 390 px, exact
491
- preservation of untouched cell-margin edges, a complete 390 px Picture
492
- Properties flow, and a 120-paragraph row across three physical pages through
493
- the final table content and following paragraph.
494
- A direct-formatting A4 fixture also runs through a real WPS Writer PDF export
495
- and a page-only browser comparison. Its automatic line spacing, paragraph
496
- gaps, centered fixed table, row heights, borders, fills, and cell margins
497
- stay within the checked one-pixel layout-landmark budget while preserving
498
- the original OOXML line multiples for DOCX export.
499
- Separate 30-row common-font, 36-row CJK-font, 18-row document-grid, and
500
- 30-row multilingual-script matrices now gate text-band positions against
501
- WPS. DOCX import selects the Word `ascii`, `hAnsi`, `eastAsia`, or `cs` font
502
- slot from the run script, including complex-script bold, italic, size, and
503
- RTL overrides. The browser keeps the measured per-font automatic-line
504
- advance, while DOCX round trips retain the section `docGrid` type and line
505
- pitch and each run's `snapToGrid` override.
506
- _DOCX import/export; PDF export._
507
- - **Markdown** — GFM source, visual editing, synchronized and resizable split
508
- preview, source-native undo/redo with typing coalescing and selection restore,
509
- source-aware ribbon formatting and shortcuts, empty-source guidance, task
510
- lists, tables, links, images, code, a flat reading surface with a comfortable
511
- line length, and keyboard-accessible host-defined selection menus across both
512
- editing surfaces. At phone widths, Source and Preview each use the complete
513
- workspace instead of being compressed into two stacked panes. _Markdown
514
- import/export._
515
- - **Spreadsheet** — Multiple sheets, formulas, dependency-aware recalculation,
516
- live selection statistics, an A3S-owned worksheet bar with lifecycle and
517
- color controls, safe deletion confirmation, in-place rename validation, a
518
- grid-aligned single-row responsive workbook footer that keeps the active
519
- worksheet and its actions visible across window and phone-width changes,
520
- selection-preserving undo/redo, deterministic Arrow, Enter, Tab, Home,
521
- PageUp/PageDown, row, column, and all-cells selection shortcuts, Cmd/Ctrl
522
- formatting through root-scoped capture before vendor grid listeners, an
523
- WPS-style Home and Editing Find and Select menu whose editor-owned
524
- `Cmd/Ctrl+F` search finds displayed values, raw values, formulas, and sparse
525
- cells without opening browser Find, plus view-only `Ctrl+G` and `F5` Go To
526
- for direct, quoted cross-sheet, and named ranges without content updates,
527
- Undo records, or sparse materialization, with a viewport-safe phone Find
528
- layout, touch-sized controls, bounded validation, and exact focus restoration,
529
- desktop workbook task panes that become focus-contained phone dialogs with
530
- an inert workbook background and exact ribbon-invoker restoration,
531
- a WPS-familiar command catalog and tab order, quick-access Undo and Redo,
532
- a priority-aware adaptive and collapsible ribbon with temporary tab
533
- expansion, an executable Home clipboard group whose Paste, Cut, and Copy
534
- commands share the permission-resilient local fallback with their WPS
535
- shortcuts, a WPS-style Paste split command with quick All, Values, Formulas,
536
- and Formatting actions plus `Cmd/Ctrl+Alt+V` Paste Special for ten content
537
- modes, arithmetic operations, Skip blanks, Transpose, translated formula
538
- references, rich same-editor styles/comments/validation/merges/column widths,
539
- bounded TSV fallback, one-step Undo, and fail-closed protected or unsafe
540
- targets, an Insert and Links Hyperlink command with grid-scoped `Cmd/Ctrl+K`,
541
- accessible Web page, cell-range, and worksheet targets, explicit Edit and
542
- Remove, immutable dense/sparse updates, content/style/comment preservation,
543
- exact focus restoration, one-step Undo, and fail-closed unsafe, hidden,
544
- protected, pivot, or out-of-bounds targets, a Data and Data Tools Validation
545
- command for lists, whole numbers, decimals, dates, and text length across
546
- multiple ranges, compact rule writes and removal, input messages,
547
- invalid-input blocking, 1900/1904-aware XLSX date round trips, exact focus
548
- restoration, one-step Undo, and fail-closed protected, merged, pivot,
549
- read-only, invalid, out-of-bounds, or over-10,000-cell targets, native
550
- Spreadsheet Tables/ListObjects through Insert and grid-scoped `Cmd/Ctrl+T`,
551
- bounded current-region or explicit-range creation, canonical unique headers,
552
- a contextual Table Design ribbon with editable names, 60 OOXML
553
- Light/Medium/Dark styles, first/last-column emphasis and row/column stripes,
554
- visible-range Canvas styling, sparse-safe Convert to Range, row/column
555
- reconciliation, native XLSX table parts and supported filters, one-step Undo,
556
- browser/Yjs record convergence, and fail-closed overlap, merge, AutoFilter,
557
- protection, pivot, invalid, or over-100,000-cell targets, a WPS-style
558
- Format Painter with
559
- single-use and double-click locked
560
- sessions, cross-sheet range-pattern tiling, Escape cancellation, and native
561
- style-only writes, Home and Font Grow/Shrink Font commands with
562
- `Cmd/Ctrl+Shift+.` / `Cmd/Ctrl+]` and `Cmd/Ctrl+Shift+,` / `Cmd/Ctrl+[` aliases,
563
- per-cell mixed-size stepping, native rectangle compaction, a 10,000-cell
564
- bound, and one-step Undo, a WPS-style Underline split control with single,
565
- double, single-accounting, and double-accounting styles, exact Format Cells
566
- and XLSX round trips, active-style-aware `Cmd/Ctrl+U` toggling, and WPS
567
- `Ctrl+2`, `Ctrl+3`, and `Ctrl+4` aliases for Bold, Italic, and Underline;
568
- Automatic Color and No Fill remove direct text and background colors instead
569
- of hard-coding replacements, a
570
- keyboard-accessible WPS Text Orientation menu with horizontal, both 45-degree
571
- angles, stacked vertical, rotate-up, and rotate-down choices, exact Fortune
572
- `rt` / `tr='3'` and OOXML 0–180 / 255 round trips, a 10,000-cell guard, and
573
- one-batch Undo, plus a cell-border split control with side, all,
574
- outside, inside, horizontal, vertical, clear, independent diagonal-down and
575
- diagonal-up targets, crossed-border composition, ten native line styles,
576
- exact color selection, compact overlapping range writes, exact OOXML
577
- direction preservation through Paste Special, Yjs, XLSX export, and reopen,
578
- `Cmd/Ctrl+Shift+&` Outside Borders and `Cmd/Ctrl+Shift+_` Clear Borders,
579
- single-update undo, and grid-focus restoration, Conditional Formatting under
580
- Home and Styles, executable
581
- sorting plus WPS-style AutoFilter under Data, finite current-region discovery,
582
- `Cmd/Ctrl+Shift+L` toggling, an `Alt+ArrowDown` keyboard filter menu,
583
- a Home and Cells Rows and Columns menu for inserting above, below, left, or
584
- right, deleting selected rows or columns, and hiding or unhiding rows and
585
- columns through the shared structure command port, including grid-scoped
586
- `Cmd/Ctrl+9`, `Cmd/Ctrl+0`, `Cmd/Ctrl+Shift+9`, and `Cmd/Ctrl+Shift+0`
587
- shortcuts with 10,000-row and 1,000-column allocation guards, a Home and
588
- Alignment Merge and Center split control with
589
- Merge Cells, Merge Across, Unmerge Cells, Unmerge and Fill, and the WPS
590
- `Ctrl+M` shortcut through one controlled native workbook batch,
591
- a Home and Editing Clear menu for independently removing content, formats,
592
- comments, hyperlinks, or all cell state while preserving merge geometry,
593
- with Delete and Backspace mapped to Clear Contents,
594
- a Home and Editing Fill menu for Down, Right, Up, and Left with native
595
- relative-formula and style propagation, WPS `Cmd/Ctrl+D` and `Cmd/Ctrl+R`
596
- shortcuts, one-step history, protected-range preflight, a 50,000-target-cell
597
- guard, and sparse-row-safe execution,
598
- a WPS AutoSum split command before Fill with Sum, Average, Count, Maximum,
599
- and Minimum, the editor-scoped `Alt+=` Sum shortcut, contiguous source
600
- inference above or left of a blank target, multi-formula totals rows and
601
- columns, target-style preservation, merged/protected/read-only/pivot and
602
- overwrite preflight, a 1,000-formula bound, sparse-safe native batches, and
603
- one-step history,
604
- Home and Number presets for General, Number, CNY Currency, Accounting,
605
- Percentage, Short Date, Time, Scientific, Fraction, and Text, including the
606
- seven standard `Cmd/Ctrl+Shift` format shortcuts, exact XLSX format-code
607
- round trips, value/formula preservation, and one-step history, plus
608
- 10,000-cell-bounded Increase/Decrease Decimal commands that retain every
609
- cell's format family across mixed selections and commit one native batch,
610
- a WPS-style Format Cells dialog under Home and Number with the editor-scoped
611
- `Cmd/Ctrl+1` shortcut, functional Number, Alignment, Font, Border, Fill, and
612
- Protection tabs, untouched mixed-value preservation, custom native number
613
- codes, compact protection ranges, dense/sparse representation retention,
614
- bounded blank-cell materialization, one controlled update and one Undo
615
- record per Apply, and exact launcher or remounted-grid focus restoration,
616
- a Home and Styles gallery with 17 WPS built-in cell styles grouped as Common,
617
- Data and Model, and Titles and Totals, true native previews, two-dimensional
618
- keyboard navigation, a 10,000-cell bound, blank-cell styling, per-cell border
619
- semantics, current-style recognition without private markers, one-step
620
- history, and direct XLSX font, fill, alignment, wrap, rotation, border, and
621
- number-format XF round trips; imported theme, indexed, automatic, and tint
622
- identities for direct font, solid-fill, and border colors survive unrelated
623
- edits and Yjs transport when the rendered RGB and palette slot still agree,
624
- while changed or conflicting colors safely export as explicit RGB,
625
- a View and Window Freeze Panes menu for current-cell, top-row, first-column,
626
- and unfreeze patterns with XLSX round trips, and visible F9 workbook
627
- recalculation,
628
- Shift+F11 creation, Ctrl/Cmd+PageUp/PageDown switching in edit and read-only
629
- preview,
630
- one shared cell/worksheet context-menu surface with executable shortcut
631
- hints that becomes a touch-sized, scrollable bottom action sheet on phones,
632
- keyboard-operated cells and sheet tabs, direct type-to-edit,
633
- permission-resilient multi-cell cut/copy/paste, clear, F2 editing, and
634
- focus-safe Escape behavior, direct
635
- font-family, vertical-alignment, text-wrap, number-format, and decimal
636
- controls, charts, validation, protection, comments, and print settings.
637
- _XLSX, XLS, ODS, and CSV import; XLSX and PDF export._
638
- - **Presentation** — Typed slide scene graph, multi-selection, groups, object
639
- transforms, keyboard-accessible table-size insertion, Shift+F10-accessible
640
- native slide and object context actions, guides, comments, transitions,
641
- editor-scoped formatting and clipboard shortcuts that restore the selected
642
- object, a docked desktop chart inspector that becomes a focus-contained modal
643
- surface whenever it overlays the canvas, docked desktop comment review that
644
- becomes a readable, touch-sized, focus-contained full-editor modal on phones
645
- with dirty-draft cancellation and exact invoker restoration, a dismissible
646
- phone slide navigator, a top-aligned phone canvas with a priority-aware status
647
- bar, one-step slideshow from the beginning or current slide,
648
- keyboard-complete playback, and a responsive presenter view with one
649
- navigation strip, current/next context, speaker notes, and a session timer.
650
- _PPTX import/export; PDF export._
651
- - **PDF** — PDFium rendering, navigation, search, form filling, annotations,
652
- annotation color, opacity, compatible stroke-width controls, history,
653
- a scrollable page-thumbnail rail with current-page synchronization and
654
- focus-synchronized Arrow/Home/End navigation, a 32-thumbnail hard window,
655
- cancellation of stale PDFium bitmap tasks, bounded main-page rendering for
656
- long files, and a dismissible page drawer whose phone trigger stays in the
657
- page controls instead of covering PDF content,
658
- focus-safe page and search drafts, responsive search-result, navigation, and
659
- zoom controls, editor-scoped shortcuts, and a keyboard-operated overflow menu
660
- that retains secondary annotation tools and appearance settings on phones.
661
- _PDF open/save._
662
-
663
- Document and Markdown accept public TipTap Extensions. Spreadsheet,
664
- Presentation, and PDF expose stable host ports rather than their internal
665
- command contexts. Editor engines and large runtime assets load only when that
666
- surface is requested.
667
-
668
480
  ## Controlled by design
669
481
 
670
482
  A3S Office is headless at the product boundary, not at the UI boundary. The
@@ -1495,10 +1307,10 @@ minor release may still include breaking model changes. Required migrations
1495
1307
  will be called out in the [changelog](CHANGELOG.md).
1496
1308
 
1497
1309
  The project targets predictable browser editing and file preservation, not
1498
- pixel parity with every Microsoft Office or WPS feature. Unsupported OOXML
1499
- semantics and fidelity gaps remain explicit compatibility boundaries instead
1500
- of being silently approximated. Track product depth and release evidence in
1501
- the [editor quality roadmap](docs/latest/en/editor-quality-roadmap.md).
1310
+ pixel parity with every Traditional Office feature. Unsupported OOXML semantics
1311
+ and fidelity gaps remain explicit compatibility boundaries instead of being
1312
+ silently approximated. Track product depth and release evidence in the
1313
+ [editor quality roadmap](docs/latest/en/editor-quality-roadmap.md).
1502
1314
 
1503
1315
  ## Development
1504
1316
 
@@ -1535,6 +1347,7 @@ without hard-coded return URLs.
1535
1347
 
1536
1348
  - [Live Playground](https://a3s-lab.github.io/Office/)
1537
1349
  - [Documentation center](https://a3s-lab.github.io/Office/docs/)
1350
+ - [A3S Office 0.22.0 documentation](https://a3s-lab.github.io/Office/docs/0.22.0/)
1538
1351
  - [A3S Office 0.21.0 documentation](https://a3s-lab.github.io/Office/docs/0.21.0/)
1539
1352
  - [A3S Office 0.20.0 documentation](https://a3s-lab.github.io/Office/docs/0.20.0/)
1540
1353
  - [A3S Office 0.19.0 documentation](https://a3s-lab.github.io/Office/docs/0.19.0/)
package/dist/0~6090.js CHANGED
@@ -257,6 +257,7 @@ function shortcutCodeKey(code) {
257
257
  if ('Space' === code) return 'space';
258
258
  if ('Equal' === code) return 'equal';
259
259
  if ('Minus' === code) return 'minus';
260
+ if ('Semicolon' === code) return ';';
260
261
  if ('Comma' === code) return ',';
261
262
  if ('Period' === code) return '.';
262
263
  return null;
@@ -1,7 +1,7 @@
1
1
  import { __webpack_require__ } from "./0~rslib-runtime.js";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { Workbook } from "@fortune-sheet/react";
4
- import { AArrowDown, AArrowUp, AlignCenter, AlignLeft, AlignRight, AlignVerticalJustifyCenter, AlignVerticalJustifyEnd, AlignVerticalJustifyStart, ArrowDown, ArrowDownToLine, ArrowLeft, ArrowLeftToLine, ArrowRight, ArrowRightToLine, ArrowUp, ArrowUpToLine, BadgeJapaneseYen, BarChart3, BetweenHorizontalEnd, BetweenHorizontalStart, BetweenVerticalEnd, BetweenVerticalStart, Bold, Bookmark, Calculator, Check, ChevronDown, ChevronLeft, ChevronRight, ClipboardPaste, Cloud, Columns3, Copy, CopyPlus, DecimalsArrowLeft, DecimalsArrowRight, Eraser, Eye, EyeOff, FileX2, Globe2, Grid2X2, Grid3X3, Hash, Italic, KeyRound, Layers2, Link2, Link2Off, ListChecks, ListFilter, LocateFixed, Merge, MessageSquareX, MoveHorizontal, MoveVertical, Paintbrush, Palette, PanelLeft, PanelTop, PanelsTopLeft, Pencil, Percent, Plus, Printer, Redo2, RefreshCw, Rows3, Save, Scissors, Search, Settings2, ShieldCheck, Sigma, SortAsc, SortDesc, Strikethrough, SwatchBook, Table2, TableProperties, Trash2, Underline, Undo2, WrapText, X } from "lucide-react";
4
+ import { AArrowDown, AArrowUp, AlignCenter, AlignLeft, AlignRight, AlignVerticalJustifyCenter, AlignVerticalJustifyEnd, AlignVerticalJustifyStart, ArrowDown, ArrowDownToLine, ArrowLeft, ArrowLeftToLine, ArrowRight, ArrowRightToLine, ArrowUp, ArrowUpToLine, BadgeJapaneseYen, BarChart3, BetweenHorizontalEnd, BetweenHorizontalStart, BetweenVerticalEnd, BetweenVerticalStart, Bold, Bookmark, Calculator, CalendarClock, CalendarDays, Check, ChevronDown, ChevronLeft, ChevronRight, ClipboardPaste, Clock, Cloud, Columns3, Copy, CopyPlus, DecimalsArrowLeft, DecimalsArrowRight, Eraser, Eye, EyeOff, FileX2, Globe2, Grid2X2, Grid3X3, Hash, Italic, KeyRound, Layers2, Link2, Link2Off, ListChecks, ListFilter, LocateFixed, Merge, MessageSquareX, MoveHorizontal, MoveVertical, Paintbrush, Palette, PanelLeft, PanelTop, PanelsTopLeft, Pencil, Percent, Plus, Printer, Redo2, RefreshCw, Rows3, Save, Scissors, Search, Settings2, ShieldCheck, Sigma, SortAsc, SortDesc, Strikethrough, SwatchBook, Table2, TableProperties, Trash2, Underline, Undo2, WrapText, X } from "lucide-react";
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";
@@ -3236,6 +3236,38 @@ const spreadsheetCommandCatalog = {
3236
3236
  group: 'number'
3237
3237
  }
3238
3238
  },
3239
+ insertCurrentDate: {
3240
+ id: 'number.insertCurrentDate',
3241
+ label: '插入当前日期',
3242
+ location: {
3243
+ area: 'ribbon',
3244
+ tab: 'home',
3245
+ group: 'number'
3246
+ },
3247
+ shortcut: {
3248
+ label: 'Ctrl+;',
3249
+ aria: 'Control+;',
3250
+ editor: [
3251
+ 'Control-;'
3252
+ ]
3253
+ }
3254
+ },
3255
+ insertCurrentTime: {
3256
+ id: 'number.insertCurrentTime',
3257
+ label: '插入当前时间',
3258
+ location: {
3259
+ area: 'ribbon',
3260
+ tab: 'home',
3261
+ group: 'number'
3262
+ },
3263
+ shortcut: {
3264
+ label: 'Ctrl+Shift+;',
3265
+ aria: 'Control+Shift+;',
3266
+ editor: [
3267
+ 'Control-Shift-;'
3268
+ ]
3269
+ }
3270
+ },
3239
3271
  formatCells: {
3240
3272
  id: 'number.formatCells',
3241
3273
  label: '设置单元格格式',
@@ -6036,6 +6068,207 @@ function clampSpreadsheetDataValidationFocus(value, range) {
6036
6068
  const focus = 'number' == typeof value && Number.isFinite(value) ? Math.trunc(value) : minimum;
6037
6069
  return Math.min(maximum, Math.max(minimum, focus));
6038
6070
  }
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
+ const MILLISECONDS_PER_DAY = 86400000;
6147
+ const MINUTES_PER_DAY = 1440;
6148
+ const EXCEL_1900_EPOCH_UTC = Date.UTC(1899, 11, 30);
6149
+ function spreadsheetDateTimeEntry(kind, now) {
6150
+ if (!Number.isFinite(now.getTime())) return null;
6151
+ if ('date' === kind) {
6152
+ const year = now.getFullYear();
6153
+ const month = now.getMonth();
6154
+ const day = now.getDate();
6155
+ const value = (Date.UTC(year, month, day) - EXCEL_1900_EPOCH_UTC) / MILLISECONDS_PER_DAY;
6156
+ if (!Number.isFinite(value)) return null;
6157
+ return {
6158
+ format: {
6159
+ fa: 'yyyy-MM-dd',
6160
+ t: 'd'
6161
+ },
6162
+ formulaBarValue: `${padDatePart(year, 4)}-${padDatePart(month + 1)}-${padDatePart(day)}`,
6163
+ value
6164
+ };
6165
+ }
6166
+ if ('time' !== kind) return null;
6167
+ const hours = now.getHours();
6168
+ const minutes = now.getMinutes();
6169
+ return {
6170
+ format: {
6171
+ fa: 'hh:mm',
6172
+ t: 'd'
6173
+ },
6174
+ formulaBarValue: `${padDatePart(hours)}:${padDatePart(minutes)}`,
6175
+ value: (60 * hours + minutes) / MINUTES_PER_DAY
6176
+ };
6177
+ }
6178
+ function createSpreadsheetDateTimeExtension() {
6179
+ return createOfficeEditorExtension({
6180
+ name: 'spreadsheetDateTime',
6181
+ addCommands: ()=>({
6182
+ insertCurrentDateTime: {
6183
+ canExecute: (context, kind)=>isSpreadsheetDateTimeKind(kind) && null !== spreadsheetDateTimeTarget(context),
6184
+ execute: insertCurrentSpreadsheetDateTime
6185
+ }
6186
+ }),
6187
+ addKeyboardShortcuts: ()=>({
6188
+ [spreadsheetCommandCatalog.insertCurrentDate.shortcut.editor["0"]]: ({ can, commands }, event)=>runSpreadsheetDateTimeShortcut(event, 'date', can.insertCurrentDateTime, commands.insertCurrentDateTime),
6189
+ [spreadsheetCommandCatalog.insertCurrentTime.shortcut.editor["0"]]: ({ can, commands }, event)=>runSpreadsheetDateTimeShortcut(event, 'time', can.insertCurrentDateTime, commands.insertCurrentDateTime)
6190
+ })
6191
+ });
6192
+ }
6193
+ function insertCurrentSpreadsheetDateTime(context, kind) {
6194
+ if (!isSpreadsheetDateTimeKind(kind)) return false;
6195
+ const target = spreadsheetDateTimeTarget(context);
6196
+ const entry = spreadsheetDateTimeEntry(kind, new Date());
6197
+ if (!target || !entry || !context.workbook) return false;
6198
+ try {
6199
+ context.workbook.batchCallApis([
6200
+ {
6201
+ name: 'setCellValuesByRange',
6202
+ args: [
6203
+ [
6204
+ [
6205
+ entry.value
6206
+ ]
6207
+ ],
6208
+ target.range,
6209
+ {
6210
+ id: target.sheetId
6211
+ }
6212
+ ]
6213
+ },
6214
+ {
6215
+ name: 'setCellFormatByRange',
6216
+ args: [
6217
+ 'ct',
6218
+ entry.format,
6219
+ target.range,
6220
+ {
6221
+ id: target.sheetId
6222
+ }
6223
+ ]
6224
+ }
6225
+ ]);
6226
+ } catch {
6227
+ return false;
6228
+ }
6229
+ try {
6230
+ context.formulaBar?.setValue(entry.formulaBarValue);
6231
+ } catch {}
6232
+ return true;
6233
+ }
6234
+ function spreadsheetDateTimeTarget(context) {
6235
+ const workbook = context.workbook;
6236
+ const sheetId = context.targetSheetId;
6237
+ if (!context.editable || !workbook || !sheetId || sheetId !== context.activeSheetId) return null;
6238
+ try {
6239
+ const selection = finiteSpreadsheetSelection(workbook.getSelection()?.at(-1) ?? context.fallbackRange);
6240
+ const row = selection.row_focus ?? selection.row[0] ?? 0;
6241
+ const column = selection.column_focus ?? selection.column[0] ?? 0;
6242
+ if (!Number.isSafeInteger(row) || row < 0 || row >= MAX_SPREADSHEET_ROWS || !Number.isSafeInteger(column) || column < 0 || column >= 16384) return null;
6243
+ const range = {
6244
+ row: [
6245
+ row,
6246
+ row
6247
+ ],
6248
+ column: [
6249
+ column,
6250
+ column
6251
+ ]
6252
+ };
6253
+ const sheet = context.content.sheets.find((candidate)=>candidate.id === sheetId);
6254
+ return canMutateSpreadsheetCellRange(sheet, range) ? {
6255
+ range,
6256
+ sheetId
6257
+ } : null;
6258
+ } catch {
6259
+ return null;
6260
+ }
6261
+ }
6262
+ function runSpreadsheetDateTimeShortcut(event, kind, canExecute, execute) {
6263
+ if (event.repeat || event.isComposing || isOfficeShortcutBlocked(event.target) || isSpreadsheetNativeTextUndoTarget(event.target) || !isSpreadsheetGridKeyboardTarget(event.target) || !canExecute(kind)) return false;
6264
+ return execute(kind);
6265
+ }
6266
+ function isSpreadsheetDateTimeKind(value) {
6267
+ return 'date' === value || 'time' === value;
6268
+ }
6269
+ function padDatePart(value, length = 2) {
6270
+ return String(value).padStart(length, '0');
6271
+ }
6039
6272
  function canApplySpreadsheetCellMerge(sheet, range, command) {
6040
6273
  if (!sheet) return false;
6041
6274
  const normalized = normalizeSpreadsheetCellMergeRange(range);
@@ -8368,6 +8601,7 @@ function createSpreadsheetEditorExtensions() {
8368
8601
  createSpreadsheetCellBorderExtension(),
8369
8602
  createSpreadsheetCellStyleExtension(),
8370
8603
  createSpreadsheetNumberFormatExtension(),
8604
+ createSpreadsheetDateTimeExtension(),
8371
8605
  createSpreadsheetNavigationExtension(),
8372
8606
  createSpreadsheetDataValidationExtension(),
8373
8607
  createSpreadsheetHyperlinkExtension(),
@@ -10721,6 +10955,73 @@ function SpreadsheetUnderlineGlyph({ style }) {
10721
10955
  })
10722
10956
  });
10723
10957
  }
10958
+ function SpreadsheetDateTimeMenu({ can, commands }) {
10959
+ const items = [
10960
+ {
10961
+ definition: spreadsheetCommandCatalog.insertCurrentDate,
10962
+ icon: /*#__PURE__*/ jsx(CalendarDays, {
10963
+ size: 16
10964
+ }),
10965
+ kind: 'date'
10966
+ },
10967
+ {
10968
+ definition: spreadsheetCommandCatalog.insertCurrentTime,
10969
+ icon: /*#__PURE__*/ jsx(Clock, {
10970
+ size: 16
10971
+ }),
10972
+ kind: 'time'
10973
+ }
10974
+ ];
10975
+ const disabled = items.every(({ kind })=>!can.insertCurrentDateTime(kind));
10976
+ return /*#__PURE__*/ jsx(Popover, {
10977
+ label: "日期和时间",
10978
+ panelLabel: "插入日期和时间",
10979
+ panelRole: "menu",
10980
+ portal: true,
10981
+ className: "work-spreadsheet-ribbon-menu-root",
10982
+ panelClassName: "work-office-context-menu work-spreadsheet-ribbon-menu",
10983
+ disabled: disabled,
10984
+ focusFirstOnOpen: true,
10985
+ onPanelKeyDown: moveOfficeMenuFocus,
10986
+ trigger: (triggerProps, { open })=>/*#__PURE__*/ jsxs("button", {
10987
+ ...triggerProps,
10988
+ className: `with-label work-spreadsheet-ribbon-menu-trigger work-spreadsheet-date-time-trigger${open ? ' active' : ''}`,
10989
+ title: "插入当前日期或时间(Ctrl+; / Ctrl+Shift+;)",
10990
+ children: [
10991
+ /*#__PURE__*/ jsx(CalendarClock, {
10992
+ size: 19
10993
+ }),
10994
+ /*#__PURE__*/ jsx("span", {
10995
+ children: "日期和时间"
10996
+ })
10997
+ ]
10998
+ }),
10999
+ children: (close)=>items.map(({ definition, icon, kind })=>/*#__PURE__*/ jsxs("button", {
11000
+ type: "button",
11001
+ role: "menuitem",
11002
+ tabIndex: -1,
11003
+ "aria-label": definition.label,
11004
+ "aria-keyshortcuts": definition.shortcut.aria,
11005
+ disabled: !can.insertCurrentDateTime(kind),
11006
+ onClick: ()=>{
11007
+ close();
11008
+ commands.insertCurrentDateTime(kind);
11009
+ },
11010
+ children: [
11011
+ /*#__PURE__*/ jsx("span", {
11012
+ className: "work-spreadsheet-ribbon-menu-item-icon",
11013
+ children: icon
11014
+ }),
11015
+ /*#__PURE__*/ jsx("span", {
11016
+ children: definition.label
11017
+ }),
11018
+ /*#__PURE__*/ jsx("kbd", {
11019
+ children: definition.shortcut.label
11020
+ })
11021
+ ]
11022
+ }, definition.id))
11023
+ });
11024
+ }
10724
11025
  const spreadsheetNumberFormatOptions = [
10725
11026
  {
10726
11027
  value: 'general',
@@ -10918,16 +11219,25 @@ function SpreadsheetNumberRibbonGroup({ can, commands, toolbarCell }) {
10918
11219
  label: "数字",
10919
11220
  priority: "high",
10920
11221
  children: [
10921
- /*#__PURE__*/ jsx(OfficeSelect, {
10922
- className: "work-spreadsheet-number-format",
10923
- ariaLabel: "数字格式",
10924
- value: numberFormatPreset,
10925
- disabled: !can.setCellFormat('ct', currentNumberFormatValue),
10926
- options: spreadsheetNumberFormatOptions,
10927
- onValueChange: (preset)=>{
10928
- if ('custom' === preset) return;
10929
- commands.setCellFormat('ct', spreadsheetNumberFormatValue(spreadsheetNumberFormatCode(preset), toolbarCell));
10930
- }
11222
+ /*#__PURE__*/ jsxs("div", {
11223
+ className: "work-spreadsheet-number-format-stack",
11224
+ children: [
11225
+ /*#__PURE__*/ jsx(OfficeSelect, {
11226
+ className: "work-spreadsheet-number-format",
11227
+ ariaLabel: "数字格式",
11228
+ value: numberFormatPreset,
11229
+ disabled: !can.setCellFormat('ct', currentNumberFormatValue),
11230
+ options: spreadsheetNumberFormatOptions,
11231
+ onValueChange: (preset)=>{
11232
+ if ('custom' === preset) return;
11233
+ commands.setCellFormat('ct', spreadsheetNumberFormatValue(spreadsheetNumberFormatCode(preset), toolbarCell));
11234
+ }
11235
+ }),
11236
+ /*#__PURE__*/ jsx(SpreadsheetDateTimeMenu, {
11237
+ can: can,
11238
+ commands: commands
11239
+ })
11240
+ ]
10931
11241
  }),
10932
11242
  /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
10933
11243
  label: `${currencyDefinition.label}格式`,
@@ -13784,81 +14094,6 @@ function formatCellsSelectionDescription(source) {
13784
14094
  const columns = source.range.column[1] - source.range.column[0] + 1;
13785
14095
  return `设置当前选区的数字、对齐、字体、边框、填充和保护属性(${rows} 行 × ${columns} 列)。`;
13786
14096
  }
13787
- const MAX_SPREADSHEET_ROWS = 1048576;
13788
- const spreadsheetPasteContentOptions = [
13789
- {
13790
- value: 'all',
13791
- label: '全部',
13792
- richOnly: false
13793
- },
13794
- {
13795
- value: 'formulas',
13796
- label: '公式',
13797
- richOnly: false
13798
- },
13799
- {
13800
- value: 'values',
13801
- label: '值',
13802
- richOnly: false
13803
- },
13804
- {
13805
- value: 'formats',
13806
- label: '格式',
13807
- richOnly: true
13808
- },
13809
- {
13810
- value: 'comments',
13811
- label: '批注',
13812
- richOnly: true
13813
- },
13814
- {
13815
- value: 'validation',
13816
- label: '数据验证',
13817
- richOnly: true
13818
- },
13819
- {
13820
- value: 'all-except-borders',
13821
- label: '边框除外的全部',
13822
- richOnly: true
13823
- },
13824
- {
13825
- value: 'formulas-and-number-formats',
13826
- label: '公式和数字格式',
13827
- richOnly: true
13828
- },
13829
- {
13830
- value: 'values-and-number-formats',
13831
- label: '值和数字格式',
13832
- richOnly: true
13833
- },
13834
- {
13835
- value: 'column-widths',
13836
- label: '列宽',
13837
- richOnly: true
13838
- }
13839
- ];
13840
- const spreadsheetPasteOperationOptions = [
13841
- {
13842
- value: 'none',
13843
- label: '无'
13844
- },
13845
- {
13846
- value: 'add',
13847
- label: '加'
13848
- },
13849
- {
13850
- value: 'subtract',
13851
- label: '减'
13852
- },
13853
- {
13854
- value: 'multiply',
13855
- label: '乘'
13856
- },
13857
- {
13858
- value: 'divide',
13859
- label: '除'
13860
- }
13861
- ];
13862
14097
  function captureSpreadsheetClipboardSnapshot(content, sheetId, selection, plainText) {
13863
14098
  const range = spreadsheet_cell_range_normalizeSpreadsheetCellRange(selection);
13864
14099
  const sheet = content.sheets.find((candidate)=>candidate.id === sheetId);
@@ -23988,6 +24223,7 @@ function spreadsheetCommandsWithGridFocus(commands, restoreFocus) {
23988
24223
  deleteSelectedStructure: afterSuccessfulCommand(commands.deleteSelectedStructure),
23989
24224
  fillSelectedCells: afterSuccessfulCommand(commands.fillSelectedCells),
23990
24225
  insertSelectedStructure: afterSuccessfulCommand(commands.insertSelectedStructure),
24226
+ insertCurrentDateTime: afterSuccessfulCommand(commands.insertCurrentDateTime),
23991
24227
  mergeSelectedCells: afterSuccessfulCommand(commands.mergeSelectedCells),
23992
24228
  openPasteSpecial: afterSuccessfulCommand(commands.openPasteSpecial),
23993
24229
  pasteSelection: afterSuccessfulCommand(commands.pasteSelection),
@@ -364,6 +364,34 @@ export declare const spreadsheetCommandCatalog: {
364
364
  readonly group: "number";
365
365
  };
366
366
  };
367
+ readonly insertCurrentDate: {
368
+ readonly id: "number.insertCurrentDate";
369
+ readonly label: "插入当前日期";
370
+ readonly location: {
371
+ readonly area: "ribbon";
372
+ readonly tab: "home";
373
+ readonly group: "number";
374
+ };
375
+ readonly shortcut: {
376
+ readonly label: "Ctrl+;";
377
+ readonly aria: "Control+;";
378
+ readonly editor: readonly ["Control-;"];
379
+ };
380
+ };
381
+ readonly insertCurrentTime: {
382
+ readonly id: "number.insertCurrentTime";
383
+ readonly label: "插入当前时间";
384
+ readonly location: {
385
+ readonly area: "ribbon";
386
+ readonly tab: "home";
387
+ readonly group: "number";
388
+ };
389
+ readonly shortcut: {
390
+ readonly label: "Ctrl+Shift+;";
391
+ readonly aria: "Control+Shift+;";
392
+ readonly editor: readonly ["Control-Shift-;"];
393
+ };
394
+ };
367
395
  readonly formatCells: {
368
396
  readonly id: "number.formatCells";
369
397
  readonly label: "设置单元格格式";
@@ -11,6 +11,7 @@ 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
13
  import { type SpreadsheetFontSizeDirection } from './spreadsheet-font-size-command';
14
+ import { type SpreadsheetDateTimeKind } from './spreadsheet-date-time-command';
14
15
  import type { SpreadsheetDataValidationRequest, SpreadsheetDataValidationTarget } from './spreadsheet-data-validation';
15
16
  import { type SpreadsheetCellMergeCommand } from './spreadsheet-cell-merge';
16
17
  import type { SpreadsheetFormatPainterMode } from './spreadsheet-format-painter';
@@ -169,6 +170,7 @@ export interface SpreadsheetEditorCommands {
169
170
  fillSelectedCells: (direction: SpreadsheetCellFillDirection) => boolean;
170
171
  hideSheet: (sheetId: string) => boolean;
171
172
  insertSelectedStructure: (axis: SpreadsheetStructureAxis, position: SpreadsheetStructureInsertPosition) => boolean;
173
+ insertCurrentDateTime: (kind: SpreadsheetDateTimeKind) => boolean;
172
174
  mergeSelectedCells: (command: SpreadsheetCellMergeCommand) => boolean;
173
175
  moveSheet: (sheetId: string, direction: SpreadsheetSheetMoveDirection) => boolean;
174
176
  moveSelection: (move: SpreadsheetSelectionMove, extend: boolean) => boolean;
@@ -0,0 +1,14 @@
1
+ import type { Cell } from '@fortune-sheet/core';
2
+ import type { SpreadsheetCommandContext, SpreadsheetEditorCommands } from './spreadsheet-command-controller';
3
+ import { type OfficeEditorExtension } from './office-editor-extension';
4
+ export type SpreadsheetDateTimeKind = 'date' | 'time';
5
+ export interface SpreadsheetDateTimeEntry {
6
+ format: NonNullable<Cell['ct']> & {
7
+ fa: string;
8
+ t: string;
9
+ };
10
+ formulaBarValue: string;
11
+ value: number;
12
+ }
13
+ export declare function spreadsheetDateTimeEntry(kind: SpreadsheetDateTimeKind, now: Date): SpreadsheetDateTimeEntry | null;
14
+ export declare function createSpreadsheetDateTimeExtension(): OfficeEditorExtension<SpreadsheetCommandContext, SpreadsheetEditorCommands>;
@@ -0,0 +1,8 @@
1
+ import type { SpreadsheetEditorCanCommands, SpreadsheetEditorCommands } from './spreadsheet-command-controller';
2
+ type SpreadsheetDateTimeCanCommands = Pick<SpreadsheetEditorCanCommands, 'insertCurrentDateTime'>;
3
+ type SpreadsheetDateTimeCommands = Pick<SpreadsheetEditorCommands, 'insertCurrentDateTime'>;
4
+ export declare function SpreadsheetDateTimeMenu({ can, commands, }: {
5
+ can: SpreadsheetDateTimeCanCommands;
6
+ commands: SpreadsheetDateTimeCommands;
7
+ }): import("react").JSX.Element;
8
+ export {};
Binary file
package/dist/styles.css CHANGED
@@ -13885,6 +13885,41 @@ button.work-office-collaboration-participant:hover .work-office-collaboration-lo
13885
13885
  min-width: 94px;
13886
13886
  }
13887
13887
 
13888
+ .work-spreadsheet-number-format-stack {
13889
+ flex-direction: column;
13890
+ flex: 0 0 94px;
13891
+ gap: 2px;
13892
+ width: 94px;
13893
+ height: 51px;
13894
+ display: flex;
13895
+ }
13896
+
13897
+ .work-spreadsheet-number-format-stack > .work-spreadsheet-ribbon-menu-root {
13898
+ width: 94px;
13899
+ min-width: 0;
13900
+ }
13901
+
13902
+ .work-office-ribbon .work-office-toolbar .work-spreadsheet-number-format-stack .work-spreadsheet-date-time-trigger.with-label {
13903
+ flex-direction: row;
13904
+ justify-content: flex-start;
13905
+ gap: 4px;
13906
+ width: 94px;
13907
+ min-width: 94px;
13908
+ height: 21px;
13909
+ padding: 0 6px;
13910
+ }
13911
+
13912
+ .work-office-ribbon .work-office-toolbar .work-spreadsheet-number-format-stack .work-spreadsheet-date-time-trigger.with-label > svg {
13913
+ width: 14px;
13914
+ height: 14px;
13915
+ }
13916
+
13917
+ .work-office-ribbon .work-office-toolbar .work-spreadsheet-number-format-stack .work-spreadsheet-date-time-trigger.with-label > span {
13918
+ max-width: 66px;
13919
+ font-size: 9px;
13920
+ line-height: 11px;
13921
+ }
13922
+
13888
13923
  .work-spreadsheet-workbook-panel {
13889
13924
  z-index: 8;
13890
13925
  border-left: 1px solid var(--a3s-line);
@@ -47,17 +47,17 @@ model:
47
47
  and compacts low-priority, then normal-priority groups before exposing group
48
48
  paging. It can remain collapsed; activating a tab temporarily overlays that
49
49
  tab's commands without moving the document, and an outside pointer action
50
- returns to the compact row. Writer routes its catalogued WPS font-size,
50
+ returns to the compact row. Writer routes its catalogued Traditional Office font-size,
51
51
  alignment, line-spacing, heading, spelling, field-refresh, comment, and
52
52
  track-changes shortcuts only while the document surface owns the event. The
53
- status route uses the same catalog for WPS word count, opening live page,
53
+ status route uses the same catalog for Traditional Office word count, opening live page,
54
54
  word, character, and paragraph details from either `Ctrl+Shift+G` or the
55
- visible count. Its local formatting clipboard powers WPS copy-format and
55
+ visible count. Its local formatting clipboard powers Traditional Office copy-format and
56
56
  paste-format shortcuts
57
57
  plus a one-shot format painter without requiring browser clipboard access;
58
58
  paste replaces only direct character and paragraph formatting, preserving
59
59
  links, comments, and revision semantics in one document transaction.
60
- Header and footer TipTap surfaces register the same WPS alignment and
60
+ Header and footer TipTap surfaces register the same Traditional Office alignment and
61
61
  copy-format shortcuts. Cross-surface paste retains compatible marks and
62
62
  paragraph attributes while falling back from unsupported heading nodes.
63
63
  Writer orders Insert commands as Pages, Table, Illustrations, Links, Header
@@ -105,11 +105,11 @@ model:
105
105
  page metrics and scroll viewport. Picture, Table, and Header and Footer tabs
106
106
  carry explicit contextual semantics and disappear with their selection. The
107
107
  Spreadsheet shell now uses the same responsive ribbon contract with its own
108
- command catalog and workbook semantics. It keeps the WPS tab order, places
108
+ command catalog and workbook semantics. It keeps the Traditional Office tab order, places
109
109
  Conditional Formatting under Home and Styles, exposes real sorting under
110
110
  Data, and owns F9 workbook recalculation in the root-scoped keyboard
111
111
  controller. Paste, Cut, and Copy live in the first Home group; both button
112
- clicks and WPS shortcuts cross one clipboard command port before using the
112
+ clicks and Traditional Office shortcuts cross one clipboard command port before using the
113
113
  permission-resilient browser/local clipboard implementation. Paste Special
114
114
  extends that port with a versioned rich snapshot and a pure bounded planner
115
115
  instead of delegating mutation to rendered vendor controls. Quick All,
@@ -136,7 +136,7 @@ model:
136
136
  `Alt+ArrowDown`. The Fortune adapter only exposes the header trigger and
137
137
  value menu, adding dialog, checkbox, focus-restoration, and keyboard
138
138
  semantics without making vendor DOM text the command contract. Freeze Panes
139
- also stays controlled: a pure model translates the current WPS cell into
139
+ also stays controlled: a pure model translates the current Traditional Office cell into
140
140
  rows above and columns left or applies top-row and first-column presets, a
141
141
  typed View command performs one immutable workbook update, and the native
142
142
  Fortune/XLSX frozen-pane model remains the render and serialization
@@ -300,7 +300,7 @@ focus restoration.
300
300
  | --- | --- | --- | --- |
301
301
  | Document | One TipTap/ProseMirror body tree retained across editing and read-only preview, controlled TipTap header/footer surfaces with direct paper-margin editing and a contextual ribbon, one typography and page-chrome baseline across editing, preview, and PDF surfaces, a persistent typed heading-navigation pane with active-selection tracking, filtering and collapsible keyboard traversal, host-owned selected-text menus with full document context and range-mapped async commands, responsive and keyboard-operated paragraph-style and list galleries, typed bullet and numbering commands with restart/continue/start controls, typed physical-page and section-page descriptors, repeated first/default/even page chrome, a versioned structured model with an HTML compatibility representation, prefix-reused visual-line measurement and pages, page decorations, page-aware horizontal and vertical rulers for page margins, paragraph indents and typed tab stops, structured list-item pagination, explicit paragraph and list-item direction, compact spacing and pagination controls, typed inline/square/tight/through/top-and-bottom/no-wrap image layout and floating-image drawing layers, imported style-inherited paragraph properties, structured inline tabs, and theme-aware run font/size/color/background import | Worker plus resumable Rust/WASM flow pagination and Rustybuzz shaping across CSS-matched registered text runs; the same live result remains mounted in read-only preview and is consumed by bounded browser PDF capture, including eligible list paragraphs, Unicode bidi level segmentation, ordered per-grapheme font fallback, packaged Latin/CJK/Arabic/Hebrew faces, and structured left-to-right tabs, with explicit DOM and JavaScript fallbacks for text affected by supported floats | Language-complete font substitution, complete Word style and numbering coverage, locale-complete and bidirectional tabs, arbitrary floating-object geometry and non-image drawing layers, complex table flow, searchable/vector PDF output, and loss-preserving OOXML package state |
302
302
  | Markdown | TipTap visual editing with a resizable source-and-preview split view by default, source-aware ribbon formatting and shortcuts, bounded source-native history with coalesced typing and selection restoration, host-defined selection menus across both editing surfaces, GFM tables, strikethrough, autolinks and nested task lists, controlled source state, coalesced preview rebuilds, proportional pane scrolling, keyboard-adjustable pane sizing, a flat measure-bounded reading surface, optional visual or source-only views, and a full-workspace Source/Preview switch on phones | No kernel required for normal editing | CommonMark differential fixtures, multi-megabyte profiling, and an off-main-thread parser boundary when measurements justify it |
303
- | Spreadsheet | Fortune Sheet grid integrated with the shared Office shell, a WPS-oriented command catalog and tab order, quick-access Undo and Redo, a priority-aware adaptive and collapsible ribbon with temporary tab expansion, Home and Styles Conditional Formatting, Home and Cells row/column insertion and deletion through the shared typed structure commands, Home and Alignment Merge and Center plus Merge Cells, Merge Across, Unmerge Cells, and Unmerge and Fill through one native-model-backed controlled batch per intent and the WPS `Ctrl+M` shortcut, Home and Font native strikethrough through the same typed formatting command and WPS `Cmd/Ctrl+5`, Home and Editing Clear All, Formats, Contents, Comments, and Hyperlinks with Delete/Backspace mapped to content-only clearing and merge geometry retained, Data sorting and AutoFilter with bounded current-region discovery, controlled filter state, WPS toggle and header-menu shortcuts, and accessible vendor menu semantics, View and Window Freeze Panes with WPS current-cell, top-row, first-column, and unfreeze patterns backed by controlled state and native XLSX frozen panes, Formulas and F9 workbook recalculation, an executable Home clipboard group with permission-resilient Paste, Cut, and Copy plus a WPS-style one-shot and locked Format Painter for bounded cross-sheet native-style patterns, shared grid/formula/footer visual tokens and one spreadsheet accent across selection, sheet tabs, menus, and zoom, an A3S-owned accessible single-row workbook footer for creation, activation, rename, duplicate, color, hide, reorder, delete, selection status, and zoom, a resize-observed worksheet viewport that keeps the active tab and its touch action visible across desktop, compact, and phone-width changes, one cell/worksheet context-menu surface whose displayed accelerators remain executable while the menu owns focus, Arrow/Home/End tab navigation plus Shift+F10 and native context-menu access, typed editing and calculation command ports, A3S-owned deterministic Arrow, Enter, Tab, Home, PageUp/PageDown, extended-selection, row, column, and all-cells keyboard commands, selection-preserving focus restoration across controlled workbook remounts and F2/Escape editing transitions, Cmd/Ctrl formatting, undo/redo, clear, a permission-resilient editor-local clipboard fallback, Shift+F11 sheet creation, and Ctrl/Cmd+PageUp/PageDown sheet-navigation shortcuts, direct font-family, horizontal/vertical-alignment, text-wrap, general/number/percent, and decimal-place controls backed by native cell-style keys, live count/sum/average selection summaries, operation-driven sparse-workbook projection, guarded controlled-value remounts that reject stale engine callbacks, and no-history result patches with cell-scoped Fortune fallback | Versioned, cancellable Worker/Rust-WASM calculation sessions using the shared bounded Rust formula parser, retained formula ASTs, incremental forward/reverse dependency graphs, dirty-subgraph recalculation, cross-sheet references, and a dynamically loaded JavaScript fallback | A3S-owned virtual grid, moving replacement projection off the main thread, broader Excel formula semantics, A3S-owned custom number-format evaluation, and print layout |
303
+ | Spreadsheet | Fortune Sheet grid integrated with the shared Office shell, an Office-oriented command catalog and tab order, quick-access Undo and Redo, a priority-aware adaptive and collapsible ribbon with temporary tab expansion, Home and Styles Conditional Formatting, Home and Cells row/column insertion and deletion through the shared typed structure commands, Home and Alignment Merge and Center plus Merge Cells, Merge Across, Unmerge Cells, and Unmerge and Fill through one native-model-backed controlled batch per intent and the Traditional Office `Ctrl+M` shortcut, Home and Font native strikethrough through the same typed formatting command and Traditional Office `Cmd/Ctrl+5`, Home and Editing Clear All, Formats, Contents, Comments, and Hyperlinks with Delete/Backspace mapped to content-only clearing and merge geometry retained, Data sorting and AutoFilter with bounded current-region discovery, controlled filter state, Traditional Office toggle and header-menu shortcuts, and accessible vendor menu semantics, View and Window Freeze Panes with Traditional Office current-cell, top-row, first-column, and unfreeze patterns backed by controlled state and native XLSX frozen panes, Formulas and F9 workbook recalculation, an executable Home clipboard group with permission-resilient Paste, Cut, and Copy plus an Office-style one-shot and locked Format Painter for bounded cross-sheet native-style patterns, shared grid/formula/footer visual tokens and one spreadsheet accent across selection, sheet tabs, menus, and zoom, an A3S-owned accessible single-row workbook footer for creation, activation, rename, duplicate, color, hide, reorder, delete, selection status, and zoom, a resize-observed worksheet viewport that keeps the active tab and its touch action visible across desktop, compact, and phone-width changes, one cell/worksheet context-menu surface whose displayed accelerators remain executable while the menu owns focus, Arrow/Home/End tab navigation plus Shift+F10 and native context-menu access, typed editing and calculation command ports, A3S-owned deterministic Arrow, Enter, Tab, Home, PageUp/PageDown, extended-selection, row, column, and all-cells keyboard commands, selection-preserving focus restoration across controlled workbook remounts and F2/Escape editing transitions, Cmd/Ctrl formatting, undo/redo, clear, a permission-resilient editor-local clipboard fallback, Shift+F11 sheet creation, and Ctrl/Cmd+PageUp/PageDown sheet-navigation shortcuts, direct font-family, horizontal/vertical-alignment, text-wrap, general/number/percent, and decimal-place controls backed by native cell-style keys, live count/sum/average selection summaries, operation-driven sparse-workbook projection, guarded controlled-value remounts that reject stale engine callbacks, and no-history result patches with cell-scoped Fortune fallback | Versioned, cancellable Worker/Rust-WASM calculation sessions using the shared bounded Rust formula parser, retained formula ASTs, incremental forward/reverse dependency graphs, dirty-subgraph recalculation, cross-sheet references, and a dynamically loaded JavaScript fallback | A3S-owned virtual grid, moving replacement projection off the main thread, broader Excel formula semantics, A3S-owned custom number-format evaluation, and print layout |
304
304
  | Presentation | Scene canvas with ordered typed multi-selection, persistent nested browser groups, native PPTX group-node export, exact keyboard-accessible table-dimension insertion, native slide/object context actions with optional AI actions, a separate object/content editing state, one on-demand TipTap instance, collective move/scale/nudge/clipboard/delete/layer commands, selection-bound alignment and distribution, typed group/ungroup commands, one typed dispatcher for ribbon commands, editor-scoped shortcuts with post-command selection focus, direct beginning/current-slide playback with fullscreen fallback, frame-coalesced transactional move/resize previews that commit once on pointer release, two-level thumbnail node and scene windowing, and a phone stage that top-aligns the primary canvas while retaining one readable slide indicator beside view and zoom controls | Revisioned, cancellable Worker/Rust-WASM slide-relative alignment and object-set snapping with typed visual guides and a JavaScript fallback | Arbitrary rotated or reflected PPTX group transforms, connectors, theme resolution, text fitting, kernel-owned thumbnail layout, and slide serialization |
305
305
  | PDF | PDFium-backed page rendering with an A3S-owned responsive toolbar, a scrollable page-thumbnail rail with active-page synchronization and bounded bitmap/DOM windowing, a focus-contained phone page drawer, and typed capability controllers for navigation, zoom, search, basic annotations, annotation color, opacity, compatible stroke-width defaults and selection updates, history, and save; page and search drafts cancel without accidental commands, shortcuts remain scoped to the PDF root, and compact widths retain page status while exposing search-result traversal, navigation, zoom, and history through the keyboard-operated overflow menu | PDFium WebAssembly | Forms, redaction review, page organization, and reopen fixtures |
306
306
 
@@ -635,7 +635,7 @@ The current browser-kernel slice collects contiguous geometry-affecting text
635
635
  runs from eligible paragraphs. Each run carries an ordered registered font
636
636
  stack, size, line height, letter spacing, ligature, and kerning behavior. Font
637
637
  families and normal/italic styles remain exact; numeric weights follow the CSS
638
- Fonts matching order so WPS-style values such as 680 or 730 select a registered
638
+ Fonts matching order so Office-style values such as 680 or 730 select a registered
639
639
  700 face. When a family has only one normal-style weight, the same face
640
640
  provides deterministic metrics for browser-synthesized bold text. The kernel
641
641
  selects a face for each grapheme, joins adjacent selections that use the same
@@ -816,13 +816,13 @@ numbering settings. Reversed lists, per-item `value` overrides, native Word
816
816
  list-identity continuation, arbitrary multilevel templates, and loss-preserving
817
817
  custom numbering formats remain later fidelity gates.
818
818
 
819
- The declared direct-formatting layout slice now has a real WPS Writer reference
819
+ The declared direct-formatting layout slice now has a real Traditional Office Writer reference
820
820
  gate. Its deterministic A4 fixture uses installed Arial runs, explicit OOXML
821
821
  paragraph spacing, a fixed centered table, direct cell fills and borders, and
822
822
  physical cell margins. Automatic `w:line` values retain their original OOXML
823
- multiples for export while the browser applies the measured WPS single-line
823
+ multiples for export while the browser applies the measured Traditional Office single-line
824
824
  font metric; imported tables no longer receive editor-only block margins. The
825
- Windows parity workflow exports the same fixture through WPS, captures both
825
+ Windows parity workflow exports the same fixture through Traditional Office, captures both
826
826
  794 by 1123 CSS-pixel pages, and rejects page-size, landmark, or bounded pixel
827
827
  differences. Language-complete font substitution, variable font axes, the
828
828
  remaining character and table style properties, non-image floating-object
@@ -1181,7 +1181,7 @@ Migration to browser-native OOXML is staged:
1181
1181
  editing surfaces.
1182
1182
 
1183
1183
  Each stage needs compatibility fixtures, deterministic layout goldens, large
1184
- document performance budgets, and real Microsoft Office and WPS
1184
+ document performance budgets, and real Microsoft Office and Traditional Office
1185
1185
  interoperability evidence before it can be described as fidelity-complete.
1186
1186
 
1187
1187
  ## Delivery roadmap
@@ -1225,7 +1225,7 @@ bundle regression.
1225
1225
 
1226
1226
  Exit criteria: deterministic layout goldens for the supported feature set;
1227
1227
  incremental reflow does not rebuild unaffected pages; DOCX fixtures round-trip
1228
- through Microsoft Word and WPS without losing unsupported package parts.
1228
+ through Microsoft Word and Traditional Office without losing unsupported package parts.
1229
1229
 
1230
1230
  ### Stage 3: spreadsheet calculation and virtualization
1231
1231
 
@@ -1355,7 +1355,7 @@ window.
1355
1355
  Exit criteria: object drag and resize stay interactive on complex slides;
1356
1356
  partial rich-text formatting survives PPTX round trips; masters, layouts,
1357
1357
  themes, tables, charts, links, and notes have compatibility fixtures for
1358
- PowerPoint and WPS.
1358
+ PowerPoint and Traditional Office.
1359
1359
 
1360
1360
  ### Stage 5: PDF product surface
1361
1361
 
@@ -1415,7 +1415,7 @@ page window rather than the complete file.
1415
1415
  CLI, MCP server, and Skill.
1416
1416
 
1417
1417
  Exit criteria: import-edit-export fixtures show semantic and package-level
1418
- round-trip evidence in Microsoft Office and WPS; unsupported content is
1418
+ round-trip evidence in Microsoft Office and Traditional Office; unsupported content is
1419
1419
  retained or rejected explicitly, never silently discarded.
1420
1420
 
1421
1421
  ## Performance gates
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a3s-lab/office",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Open-source collaborative browser editors for documents, Markdown, spreadsheets, presentations, and PDFs.",
5
5
  "keywords": [
6
6
  "office",
@@ -88,6 +88,7 @@
88
88
  "playground:typecheck": "tsc --noEmit -p playground/tsconfig.json",
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
+ "playground:visual:spreadsheet-date-time": "playwright test visual-tests/spreadsheet-date-time.functional.spec.ts --config playwright.config.ts",
91
92
  "playground:visual:spreadsheet-diagonal-borders": "playwright test visual-tests/spreadsheet-diagonal-borders.functional.spec.ts --config playwright.config.ts",
92
93
  "playground:visual:spreadsheet-font-colors-shortcuts": "playwright test visual-tests/spreadsheet-font-colors-shortcuts.functional.spec.ts --config playwright.config.ts",
93
94
  "playground:visual:spreadsheet-hyperlink": "playwright test visual-tests/spreadsheet-hyperlink.functional.spec.ts --config playwright.config.ts",
@@ -160,6 +161,8 @@
160
161
  "test:e2e:spreadsheet-data-validation:check": "a3s-test check tests/e2e/spreadsheet-data-validation.acl --json",
161
162
  "test:e2e:spreadsheet-diagonal-borders": "a3s-test run tests/e2e/spreadsheet-diagonal-borders.acl --json",
162
163
  "test:e2e:spreadsheet-diagonal-borders:check": "a3s-test check tests/e2e/spreadsheet-diagonal-borders.acl --json",
164
+ "test:e2e:spreadsheet-date-time": "a3s-test run tests/e2e/spreadsheet-date-time.acl --json",
165
+ "test:e2e:spreadsheet-date-time:check": "a3s-test check tests/e2e/spreadsheet-date-time.acl --json",
163
166
  "test:e2e:spreadsheet-hyperlink": "a3s-test run tests/e2e/spreadsheet-hyperlink.acl --json",
164
167
  "test:e2e:spreadsheet-hyperlink:check": "a3s-test check tests/e2e/spreadsheet-hyperlink.acl --json",
165
168
  "test:e2e:spreadsheet-maximum-sparse": "a3s-test run tests/e2e/spreadsheet-maximum-sparse.acl --json",
@@ -179,6 +182,7 @@
179
182
  "test:e2e:writer-status": "a3s-test run tests/e2e/word-status-bar.acl --json",
180
183
  "test:e2e:writer-status:check": "a3s-test check tests/e2e/word-status-bar.acl --json",
181
184
  "test:wps-layout": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/test-wps-layout-parity.ps1",
185
+ "test:office-layout": "bun run test:wps-layout",
182
186
  "test:watch": "rstest --watch",
183
187
  "typecheck": "tsc --noEmit"
184
188
  },