🎉 Release v0.5.3
🎊 [email protected]
🚧 Important Note
This project is still in heavy development, and major API changes are expected. Your feedback is crucial! Please submit issues and suggestions to help us shape the future of Univer.
🚀 Getting Started
If you're eager to explore Univer, check out our getting started documentation.
Dive into the world of collaborative document, spreadsheet, and presentation editing powered by Univer!
📊 Introducing Univer Go Beta!
Important
Univer Go Beta is now available!
We are excited to announce the release of Univer Go, a new desktop application that enables you to build your own spreadsheet and seamlessly integrate with AI agents, databases, and applications.
✨ Fun Built-in Templates
- AI Spreadsheet Translator: Utilize the Univer API in combination with AI to achieve instant multilingual translation of spreadsheet content
- Work Calendar: Generate a work calendar with one click, demonstrating how to use the Univer API to load snapshot data, customize formulas, bind cell events, and utilize the permissions module
- Gantt Chart: Insert any number of Gantt charts into a spreadsheet with a single click, showcasing how to use the Univer API to add formulas, adjust cell styles, merge cells, set conditional formatting, and add data validation
- High-performance Pivot Tables: Quickly create pivot tables and discover how to use the pivot table API in Univer Go to enhance data analysis efficiency
- Tic Tac Toe: Share a link to play Tic-Tac-Toe with friends, learn how to bind Canvas events and implement real-time multiplayer interactions
More templates are waiting for you to explore. Feel free to share your templates with us!
Beta version is now available for both Windows. We welcome community members to test it out and share their feedback to help us improve the platform!
📊 Univer Sheets
🎉 Highlights
In this release, we are excited to introduce a new set of features and improvements to enhance your Univer experience. Here are the highlights:
- Optimized Facade API chaining, enabling more fluent API calls. This update may require adjustments to existing code, please refer to the Breaking Changes section #4329 #4403 #4412
import '@univerjs/sheets/facade'
univerAPI.getActiveWorkbook().insertSheet()
// set basic properties
.setName('Sales Report 2024')
// set freeze pane
.setFrozenRows(2)
.setFrozenColumns(1)
// set column width
.setColumnWidths(0, 1, 180) // product name column
.setColumnWidths(1, 1, 120) // price column
.setColumnWidths(2, 1, 100) // quantity column
.setColumnWidths(3, 1, 120) // total price column
.setColumnWidths(4, 1, 150) // note column
// set row height
.setRowHeight(0, 35) // main header
.setRowHeight(1, 30) // sub header
// set values
.getRange("a1:e1")
.setValues([
["product name", "price", "quantity", "total price", "note"],
])
- Added range theme feature with 31 built-in themes, Documentation #4369
import '@univerjs/sheets/facade'
univerAPI.getActiveWorkbook().getActiveSheet().getRange("a1:c5").useThemeStyle('default')
univerAPI.getActiveWorkbook().getActiveSheet().getRange("a1:c5").useThemeStyle(null)
- Added Facade API
FRange.splitTextToColumns
for splitting text into columns
import '@univerjs/sheets/facade'
univerAPI.getActiveWorkbook().getActiveSheet().getRange("a1").setValue("1;2;3").splitTextToColumns()
- Added Facade API
FFormula.registerFunction
andFFormula.registerAsyncFunction
for creating custom functions #4399
import '@univerjs/sheets/facade'
import '@univerjs/sheets/sheets-formula'
univerAPI.getFormula().registerFunction('HELLO', (name) => `Hello, ${name}!`, 'A simple greeting function');
// Use the function in a cell
univerAPI.getActiveWorkbook().getActiveSheet().getRange('A1').setValue('World');
univerAPI.getActiveWorkbook().getActiveSheet().getRange('A2').setValue({ f: '=HELLO(A1)' });
// A2 will display: "Hello, World!"
🐞 Bug Fixes
- Fixed mouse scrollbar operation issues #4396
- Fixed non-responsive dropdown menu clicks in the More menu #4416
- Fixed known issues
💔 Breaking Changes
Tools.deepMerge
is deprecated, please usemerge
instead
Before:
import { Tools } from '@univerjs/core'
Tools.deepMerge(obj1, obj2)
After:
import { merge } from '@univerjs/core'
merge(obj1, obj2)
- Changed return type of chained Facade API calls from
Promise<boolean>
toFUniver
orFWorkbook
orFWorksheet
orFRange
orFDataValidation
orFFilter
#4329 #4403 #4412
Before:
await univerAPI.getActiveWorkbook().getActiveSheet().getRange('A1:A5').setValue('123');
await univerAPI.getActiveWorkbook().getActiveSheet().getRange('A1:A5').merge()
After:
univerAPI.getActiveWorkbook().getActiveSheet().getRange('A1:A5').setValue('123').merge();
FUniver{
...
-setCrosshairHighlightColor(color: string): void;
+setCrosshairHighlightColor(color: string): FUniver;
-setCrosshairHighlightEnabled(enabled: boolean): void;
+setCrosshairHighlightEnabled(enabled: boolean): FUniver;
-showMessage(options: IMessageProps): void;
+showMessage(options: IMessageProps): FUniver;
-addWatermark(type: IWatermarkTypeEnum.Text, config: ITextWatermarkConfig): void;
+addWatermark(type: IWatermarkTypeEnum.Text, config: ITextWatermarkConfig): FUniver;
-addWatermark(type: IWatermarkTypeEnum.Image, config: IImageWatermarkConfig): void;
+addWatermark(type: IWatermarkTypeEnum.Image, config: IImageWatermarkConfig): FUniver;
-deleteWatermark(): void;
+deleteWatermark(): FUniver;
...
}
FWorkbook{
...
-deleteActiveSheet(): Promise<boolean>;
+deleteActiveSheet(): FWorkbook;
-deleteSheet(sheet: FWorksheet): Promise<boolean>;
+deleteSheet(sheet: FWorksheet): FWorkbook;
-duplicateActiveSheet(): Promise<boolean>;
+duplicateActiveSheet(): FWorkbook;
-duplicateSheet(sheet: FWorksheet): Promise<boolean>;
+duplicateSheet(sheet: FWorksheet): FWorkbook;
-moveActiveSheet(index: number): Promise<boolean>;
+moveActiveSheet(index: number): FWorkbook;
-moveSheet(sheet: FWorksheet, index: number): Promise<boolean>;
+moveSheet(sheet: FWorksheet, index: number): FWorkbook;
-redo(): Promise<boolean>;
+redo(): FWorkbook;
-undo(): Promise<boolean>;
+undo(): FWorkbook;
...
}
FWorksheet {
...
-cancelFreeze(): boolean;
+cancelFreeze(): FWorksheet;
-clear(options?: IFacadeClearOptions): Promise<boolean>;
+clear(options?: IFacadeClearOptions): FWorksheet;
-clearContents(): Promise<boolean>;
+clearContents(): FWorksheet;
-clearFormats(): Promise<boolean>;
+clearFormats(): FWorksheet;
-deleteColumn(columnPosition: number): Promise<FWorksheet>;
+deleteColumn(columnPosition: number): FWorksheet;
-deleteColumns(columnPosition: number, howMany: number): Promise<FWorksheet>;
+deleteColumns(columnPosition: number, howMany: number): FWorksheet;
-deleteRow(rowPosition: number): Promise<FWorksheet>;
+deleteRow(rowPosition: number): FWorksheet;
-deleteRows(rowPosition: number, howMany: number): Promise<FWorksheet>;
+deleteRows(rowPosition: number, howMany: number): FWorksheet;
-hideColumn(column: FRange): Promise<FWorksheet>;
+hideColumn(column: FRange): FWorksheet;
-hideColumns(columnIndex: number, numColumns?: number): Promise<FWorksheet>;
+hideColumns(columnIndex: number, numColumns?: number): FWorksheet;
-hideRow(row: FRange): Promise<FWorksheet>;
+hideRow(row: FRange): FWorksheet;
-hideRows(rowIndex: number, numRows?: number): Promise<FWorksheet>;
+hideRows(rowIndex: number, numRows?: number): FWorksheet;
-hideSheet(): void;
+hideSheet(): FWorksheet;
-insertColumnAfter(afterPosition: number): Promise<FWorksheet>;
+insertColumnAfter(afterPosition: number): FWorksheet;
-insertColumnBefore(beforePosition: number): Promise<FWorksheet>;
+insertColumnBefore(beforePosition: number): FWorksheet;
-insertColumns(columnIndex: number, numColumns?: number): Promise<FWorksheet>;
+insertColumns(columnIndex: number, numColumns?: number): FWorksheet;
-insertColumnsAfter(afterPosition: number, howMany: number): Promise<FWorksheet>;
+insertColumnsAfter(afterPosition: number, howMany: number): FWorksheet;
-insertColumnsBefore(beforePosition: number, howMany: number): Promise<FWorksheet>;
+insertColumnsBefore(beforePosition: number, howMany: number): FWorksheet;
-insertRowAfter(afterPosition: number): Promise<FWorksheet>;
+insertRowAfter(afterPosition: number): FWorksheet;
-insertRowBefore(beforePosition: number): Promise<FWorksheet>;
+insertRowBefore(beforePosition: number): FWorksheet;
-insertRows(rowIndex: number, numRows?: number): Promise<FWorksheet>;
+insertRows(rowIndex: number, numRows?: number): FWorksheet;
-insertRowsAfter(afterPosition: number, howMany: number): Promise<FWorksheet>;
+insertRowsAfter(afterPosition: number, howMany: number): FWorksheet;
-insertRowsBefore(beforePosition: number, howMany: number): Promise<FWorksheet>;
+insertRowsBefore(beforePosition: number, howMany: number): FWorksheet;
-moveColumns(columnSpec: FRange, destinationIndex: number): Promise<FWorksheet>;
+moveColumns(columnSpec: FRange, destinationIndex: number): FWorksheet;
-moveRows(rowSpec: FRange, destinationIndex: number): Promise<FWorksheet>;
+moveRows(rowSpec: FRange, destinationIndex: number): FWorksheet;
-setColumnCustom(custom: IObjectArrayPrimitiveType<CustomData>): Promise<FWorksheet>;
+setColumnCustom(custom: IObjectArrayPrimitiveType<CustomData>): FWorksheet;
-setColumnDefaultStyle(index: number, style: string | Nullable<IStyleData>): Promise<FWorksheet>;
+setColumnDefaultStyle(index: number, style: string | Nullable<IStyleData>): FWorksheet;
-setColumnWidth(columnPosition: number, width: number): Promise<FWorksheet>;
+setColumnWidth(columnPosition: number, width: number): FWorksheet;
-setColumnWidths(startColumn: number, numColumns: number, width: number): Promise<FWorksheet>;
+setColumnWidths(startColumn: number, numColumns: number, width: number): FWorksheet;
-setDefaultStyle(style: string): Promise<FWorksheet>;
+setDefaultStyle(style: string): FWorksheet;
-setFreeze(freeze: IFreeze): boolean;
+setFreeze(freeze: IFreeze): FWorksheet;
-setFrozenColumns(startColumn: number, endColumn: number): void;
+setFrozenColumns(startColumn: number, endColumn: number): FWorksheet;
-setFrozenRows(startColumn: number, endColumn: number): void;
+setFrozenRows(startColumn: number, endColumn: number): FWorksheet;
-setGridLinesColor(color: string | undefined): Promise<boolean>;
+setGridLinesColor(color: string | undefined): FWorksheet;
-setHiddenGridlines(hidden: boolean): Promise<boolean>;
+setHiddenGridlines(hidden: boolean): FWorksheet;
-setName(name: string): Promise<boolean>;
+setName(name: string): FWorksheet;
-setRowCustom(custom: IObjectArrayPrimitiveType<CustomData>): Promise<FWorksheet>;
+setRowCustom(custom: IObjectArrayPrimitiveType<CustomData>): FWorksheet;
-setRowDefaultStyle(index: number, style: string | Nullable<IStyleData>): Promise<FWorksheet>;
+setRowDefaultStyle(index: number, style: string | Nullable<IStyleData>): FWorksheet;
-setRowHeight(rowPosition: number, height: number): Promise<FWorksheet>;
+setRowHeight(rowPosition: number, height: number): FWorksheet;
-setRowHeights(startRow: number, numRows: number, height: number): Promise<FWorksheet>;
+setRowHeights(startRow: number, numRows: number, height: number): FWorksheet;
-setRowHeightsForced(startRow: number, numRows: number, height: number): Promise<FWorksheet>;
+setRowHeightsForced(startRow: number, numRows: number, height: number): FWorksheet;
-setTabColor(color: string): Promise<boolean>;
+setTabColor(color: string): FWorksheet;
-showColumns(columnIndex: number, numColumns?: number): Promise<FWorksheet>;
+showColumns(columnIndex: number, numColumns?: number): FWorksheet;
-showRows(rowIndex: number, numRows?: number): Promise<FWorksheet>;
+showRows(rowIndex: number, numRows?: number): FWorksheet;
-showSheet(): Promise<boolean>;
+showSheet(): FWorksheet;
-unhideColumn(column: FRange): Promise<FWorksheet>;
+unhideColumn(column: FRange): FWorksheet;
-unhideRow(row: FRange): Promise<FWorksheet>;
+unhideRow(row: FRange): FWorksheet;
-addConditionalFormattingRule(rule: IConditionFormattingRule): Promise<boolean>;
+addConditionalFormattingRule(rule: IConditionFormattingRule): FWorksheet;
-deleteConditionalFormattingRule(cfId: string): Promise<boolean>;
+deleteConditionalFormattingRule(cfId: string): FWorksheet;
-moveConditionalFormattingRule(cfId: string, toCfId: string, type?: IAnchor['type']): Promise<boolean>;
+moveConditionalFormattingRule(cfId: string, toCfId: string, type?: IAnchor['type']): FWorksheet;
-setConditionalFormattingRule(cfId: string, rule: IConditionFormattingRule): Promise<boolean>;
+setConditionalFormattingRule(cfId: string, rule: IConditionFormattingRule): FWorksheet;
-zoom(zoomRatio: number): FWorksheet;
+zoom(zoomRatio: number): FWorksheet;
...
}
FRange {
...
-merge(defaultMerge?: boolean): Promise<FRange>;
+merge(defaultMerge?: boolean): FRange;
-mergeAcross(defaultMerge?: boolean): Promise<FRange>;
+mergeAcross(defaultMerge?: boolean): FRange;
-mergeVertically(defaultMerge?: boolean): Promise<FRange>;
+mergeVertically(defaultMerge?: boolean): FRange;
-setHorizontalAlignment(alignment: FHorizontalAlignment): Promise<boolean>;
+setHorizontalAlignment(alignment: FHorizontalAlignment): FRange;
-setValue(value: CellValue | ICellData): Promise<boolean>;
+setValue(value: CellValue | ICellData): FRange;
-setValues(value: CellValue[][] | IObjectMatrixPrimitiveType<CellValue> | ICellData[][] | IObjectMatrixPrimitiveType<ICellData>): Promise<boolean>;
+setValues(value: CellValue[][] | IObjectMatrixPrimitiveType<CellValue> | ICellData[][] | IObjectMatrixPrimitiveType<ICellData>): FRange;
-setVerticalAlignment(alignment: FVerticalAlignment): Promise<boolean>;
+setVerticalAlignment(alignment: FVerticalAlignment): FRange;
-setWrap(isWrapEnabled: boolean): Promise<boolean>;
+setWrap(isWrapEnabled: boolean): FRange;
-setWrapStrategy(strategy: WrapStrategy): Promise<boolean>;
+setWrapStrategy(strategy: WrapStrategy): FRange;
-addConditionalFormattingRule(rule: IConditionFormattingRule): Promise<boolean>;
+addConditionalFormattingRule(rule: IConditionFormattingRule): FRange;
-deleteConditionalFormattingRule(cfId: string): Promise<boolean>;
+deleteConditionalFormattingRule(cfId: string): FRange;
-moveConditionalFormattingRule(cfId: string, toCfId: string, type?: IAnchor['type']): Promise<boolean>;
+moveConditionalFormattingRule(cfId: string, toCfId: string, type?: IAnchor['type']): FRange;
-setConditionalFormattingRule(cfId: string, rule: IConditionFormattingRule): Promise<boolean>;
+setConditionalFormattingRule(cfId: string, rule: IConditionFormattingRule): FRange;
-setDataValidation(rule: Nullable<FDataValidation>): Promise<FRange>;
+setDataValidation(rule: Nullable<FDataValidation>): FRange;
-createFilter(): Promise<FFilter | null>;
+createFilter(): FRange;
-cancelHyperLink(id: string): Promise<boolean>;
+cancelHyperLink(id: string): boolean;
-setNumberFormat(pattern: string): Promise<boolean>;
+setNumberFormat(pattern: string): FRange;
-sort(column: SortColumnSpec | SortColumnSpec[]): Promise<FRange>;
+sort(column: SortColumnSpec | SortColumnSpec[]): FRange;
...
}
FDataValidation{
-setCriteria(type: DataValidationType, values: [DataValidationOperator, string, string]): boolean;
+setCriteria(type: DataValidationType, values: [DataValidationOperator, string, string]): FDataValidation;
-setOptions(options: Partial<IDataValidationRuleOptions>): boolean;
+setOptions(options: Partial<IDataValidationRuleOptions>): FDataValidation;
-setRanges(ranges: FRange[]): boolean;
+setRanges(ranges: FRange[]): FDataValidation;
}
FFilter{
-remove(): Promise<boolean>;
+remove(): FFilter;
-removeColumnFilterCriteria(col: number): Promise<boolean>;
+removeColumnFilterCriteria(col: number): FFilter;
-removeFilterCriteria(): Promise<boolean>;
+removeFilterCriteria(): FFilter;
-setColumnFilterCriteria(col: number, criteria: ISetSheetsFilterCriteriaCommandParams['criteria']): Promise<boolean>;
+setColumnFilterCriteria(col: number, criteria: ISetSheetsFilterCriteriaCommandParams['criteria']): FFilter;
}
📢 0.6.0 Preview
Important
The development of version 0.6.0 is currently underway. Starting with this release, Univer will support integration with projects using React@19 . However, this update may introduce breaking changes for users relying on React@16 or Univer UMD builds.
If you have any questions or concerns, please feel free to share your suggestions and feedback via GitHub Issues.
- Future versions will continue to improve enums and events, optimizing the Facade API experience #4346 #4406
FUniver.Enum
FUniver.Event
FUniver.addEvent(FUniver.Event.xxx, ()=> { })
📝 Univer Docs
- Fixed known issues
🌐 Univer Server
- Fixed known issues
📦 Univer Presets
- Updated to the latest version of Univer
📢 Join the Conversation
We welcome your input and insights as we embark on this exciting journey. Connect with us on:
📝 Changelog
Full changelog (2025-01-04)
Bug Fixes
- canvas crash when draw broken image (#4388) (09fd432)
- design: fix dropdown on nested situation (#4416) (05896c0)
- extend feventname (#4426) (86e4e8e)
- facade: f-event & f-enum extend error (#4424) (be77c47)
- filter: fix event API export (#4422) (5738128)
- fix snapshot after cut & paste (#4405) (52990cc)
- formula: use different isNullCell for formula modules (#4395) (72e8192)
- range-selector: remove dataStream (#4191) (a90779e)
- sheet: fix spell error (#4425) (430f338)
- ui: update animation class condition to improve Ribbon styling (#4392) (0124730)
- vp start sheet view column (#4396) (868e4b2)
- watermark: fix invalid plugin configuration (#4389) (e3930bb)
Features
- add api for ui and f-enum (#4406) (51ed14e)
- facade: facade-namespace & global addEvent (#4346) (612c981)
- facade: make facade api sync and chainable (#4329) (c5fcf3e)
- fetchThroughInterceptors support filter function (#4385) (e909093)
- filter: update filter facade to add events and enums (#4403) (9ad9d48)
- formula: add register async function (#4399) (c8d287b)
- sheet: support range theme template (#4369) (28ff41a)