@odoo/o-spreadsheet
Version:
A spreadsheet component
1,335 lines (1,302 loc) • 250 kB
TypeScript
import * as ChartJs from 'chart.js';
import { ChartConfiguration, CoreChartOptions, Scriptable, Color as Color$1, ScriptableContext, FontSpec } from 'chart.js';
/**
* Block of code that produces a value.
*/
interface FunctionCode {
readonly returnExpression: string;
/**
* Return the same function code but with the return expression assigned to a variable.
*/
assignResultToVariable(): FunctionCode;
}
declare class FunctionCodeBuilder {
private scope;
private code;
constructor(scope?: Scope);
append(...lines: (string | FunctionCode)[]): void;
return(expression: string): FunctionCode;
toString(): string;
}
declare class Scope {
private nextId;
private declaredVariables;
nextVariableName(): string;
isAlreadyDeclared(name: string): boolean;
}
type LocaleCode = string & Alias;
interface Locale {
name: string;
code: LocaleCode;
thousandsSeparator?: string;
decimalSeparator: string;
weekStart: number;
dateFormat: string;
timeFormat: string;
formulaArgSeparator: string;
}
declare const DEFAULT_LOCALES: Locale[];
declare const DEFAULT_LOCALE: Locale;
type Format = string & Alias;
type FormattedValue = string & Alias;
interface CellAttributes {
readonly id: UID;
/**
* Raw cell content
*/
readonly content: string;
readonly format?: Format;
}
interface LiteralCell extends CellAttributes {
readonly isFormula: false;
readonly parsedValue: CellValue;
}
interface FormulaCell extends CellAttributes {
readonly isFormula: true;
readonly compiledFormula: RangeCompiledFormula;
}
type Cell = LiteralCell | FormulaCell;
interface EvaluatedCellProperties extends FunctionResultObject {
readonly format?: Format;
/**
* Cell value formatted based on the format
*/
readonly formattedValue: FormattedValue;
readonly defaultAlign: "right" | "center" | "left";
/**
* Can the cell appear in an automatic sum zone.
*/
readonly isAutoSummable: boolean;
readonly link?: Link;
}
type CellValue = string | number | boolean | null;
type EvaluatedCell = NumberCell | TextCell | BooleanCell | EmptyCell | ErrorCell;
interface NumberCell extends EvaluatedCellProperties {
readonly type: CellValueType.number;
readonly value: number;
}
interface TextCell extends EvaluatedCellProperties {
readonly type: CellValueType.text;
readonly value: string;
}
interface BooleanCell extends EvaluatedCellProperties {
readonly type: CellValueType.boolean;
readonly value: boolean;
}
interface EmptyCell extends EvaluatedCellProperties {
readonly type: CellValueType.empty;
readonly value: null;
}
interface ErrorCell extends EvaluatedCellProperties {
readonly type: CellValueType.error;
readonly value: string;
readonly message?: string;
}
declare enum CellValueType {
boolean = "boolean",
number = "number",
text = "text",
empty = "empty",
error = "error"
}
/**
* Tokenizer
*
* A tokenizer is a piece of code whose job is to transform a string into a list
* of "tokens". For example, "(12+" is converted into:
* [{type: "LEFT_PAREN", value: "("},
* {type: "NUMBER", value: "12"},
* {type: "OPERATOR", value: "+"}]
*
* As the example shows, a tokenizer does not care about the meaning behind those
* tokens. It only cares about the structure.
*
* The tokenizer is usually the first step in a compilation pipeline. Also, it
* is useful for the composer, which needs to be able to work with incomplete
* formulas.
*/
declare const POSTFIX_UNARY_OPERATORS: string[];
type TokenType = "OPERATOR" | "NUMBER" | "STRING" | "SYMBOL" | "SPACE" | "DEBUGGER" | "ARG_SEPARATOR" | "ARRAY_ROW_SEPARATOR" | "LEFT_PAREN" | "RIGHT_PAREN" | "LEFT_BRACE" | "RIGHT_BRACE" | "REFERENCE" | "INVALID_REFERENCE" | "UNKNOWN";
interface Token {
readonly type: TokenType;
readonly value: string;
}
declare function tokenize(str: string, locale?: Locale): Token[];
interface BarChartDefinition extends CommonChartDefinition {
readonly type: "bar";
readonly stacked: boolean;
readonly horizontal?: boolean;
readonly zoomable?: boolean;
}
type BarChartRuntime = {
chartJsConfig: ChartConfiguration<"bar" | "line">;
masterChartConfig?: ChartConfiguration<"bar">;
background: Color;
};
interface GenericCriterion {
type: GenericCriterionType;
values: string[];
}
type GenericCriterionType = "containsText" | "notContainsText" | "isEqualText" | "isEmail" | "isLink" | "dateIs" | "dateIsBefore" | "dateIsOnOrBefore" | "dateIsAfter" | "dateIsOnOrAfter" | "dateIsBetween" | "dateIsNotBetween" | "dateIsValid" | "isEqual" | "isNotEqual" | "isGreaterThan" | "isGreaterOrEqualTo" | "isLessThan" | "isLessOrEqualTo" | "isBetween" | "isNotBetween" | "isBoolean" | "isValueInList" | "isValueInRange" | "customFormula" | "beginsWithText" | "endsWithText" | "isNotEmpty" | "isEmpty";
type DateCriterionValue = "today" | "tomorrow" | "yesterday" | "lastWeek" | "lastMonth" | "lastYear" | "exactDate";
type EvaluatedCriterion<T extends GenericCriterion = GenericCriterion> = Omit<T, "values"> & {
values: CellValue[];
};
interface RangePart {
readonly colFixed: boolean;
readonly rowFixed: boolean;
}
interface Range {
readonly zone: Readonly<Zone>;
readonly unboundedZone: Readonly<UnboundedZone>;
readonly parts: readonly RangePart[];
readonly invalidXc?: string;
/** true if the user provided the range with the sheet name */
readonly prefixSheet: boolean;
/** the name of any sheet that is invalid */
readonly invalidSheetName?: string;
/** the sheet on which the range is defined */
readonly sheetId: UID;
}
interface RangeStringOptions {
useBoundedReference?: boolean;
useFixedReference?: boolean;
}
interface RangeData {
_zone: Zone | UnboundedZone;
_sheetId: UID;
}
interface Table {
readonly id: TableId;
readonly range: Range;
readonly filters: Filter[];
readonly config: TableConfig;
}
interface StaticTable extends Table {
readonly type: "static" | "forceStatic";
}
interface DynamicTable extends Omit<Table, "filters"> {
readonly type: "dynamic";
}
type CoreTable = StaticTable | DynamicTable;
type CoreTableType = Extract<CoreTable, {
type: string;
}>["type"];
interface Filter {
readonly id: UID;
readonly rangeWithHeaders: Range;
readonly col: number;
/** The filtered zone doesn't includes the headers of the table */
readonly filteredRange: Range | undefined;
}
interface TableConfig {
hasFilters: boolean;
totalRow: boolean;
firstColumn: boolean;
lastColumn: boolean;
numberOfHeaders: number;
bandedRows: boolean;
bandedColumns: boolean;
automaticAutofill?: boolean;
styleId: string;
}
interface TableElementStyle {
border?: TableBorder;
style?: Style;
size?: number;
}
interface TableBorder extends Border {
horizontal?: BorderDescr;
vertical?: BorderDescr;
}
interface TableStyle {
category: string;
displayName: string;
templateName: TableStyleTemplateName;
primaryColor: string;
wholeTable?: TableElementStyle;
firstColumnStripe?: TableElementStyle;
secondColumnStripe?: TableElementStyle;
firstRowStripe?: TableElementStyle;
secondRowStripe?: TableElementStyle;
firstColumn?: TableElementStyle;
lastColumn?: TableElementStyle;
headerRow?: TableElementStyle;
totalRow?: TableElementStyle;
}
type TableStyleTemplateName = "none" | "lightColoredText" | "lightAllBorders" | "mediumAllBorders" | "lightWithHeader" | "mediumBandedBorders" | "mediumMinimalBorders" | "darkNoBorders" | "mediumWhiteBorders" | "dark";
declare const filterCriterions: GenericCriterionType[];
type FilterCriterionType = (typeof filterCriterions)[number];
interface ValuesFilter {
filterType: "values";
hiddenValues: string[];
}
interface CriterionFilter {
filterType: "criterion";
type: FilterCriterionType | "none";
values: string[];
dateValue?: DateCriterionValue;
}
type DataFilterValue = ValuesFilter | CriterionFilter;
declare class PositionMap<T> {
private map;
constructor(entries?: Iterable<readonly [CellPosition, T]>);
set({ sheetId, col, row }: CellPosition, value: T): void;
setMany(values: Iterable<[CellPosition, T]>): void;
get({ sheetId, col, row }: CellPosition): T | undefined;
getSheet(sheetId: UID): Record<number, Record<number, T>> | undefined;
clearSheet(sheetId: UID): void;
has({ sheetId, col, row }: CellPosition): boolean;
delete({ sheetId, col, row }: CellPosition): void;
keys(): CellPosition[];
keysForSheet(sheetId: UID): CellPosition[];
entries(): IterableIterator<[CellPosition, T]>;
}
/**
* An Operation can be executed to change a data structure from state A
* to state B.
* It should hold the necessary data used to perform this transition.
* It should be possible to revert the changes made by this operation.
*
* In the context of o-spreadsheet, the data from an operation would
* be a revision (the commands are used to execute it, the `changes` are used
* to revert it).
*/
declare class Operation<T> {
readonly id: UID;
readonly data: T;
constructor(id: UID, data: T);
transformed(transformation: Transformation<T>): Operation<T>;
}
/**
* A branch holds a sequence of operations.
* It can be represented as "A - B - C - D" if A, B, C and D are executed one
* after the other.
*
* @param buildTransformation Factory to build transformations
* @param operations initial operations
*/
declare class Branch<T> {
private readonly buildTransformation;
private operations;
constructor(buildTransformation: TransformationFactory<T>, operations?: Operation<T>[]);
getOperations(): readonly Operation<T>[];
getOperation(operationId: UID): Operation<T>;
getLastOperationId(): UID | undefined;
/**
* Get the id of the operation appears first in the list of operations
*/
getFirstOperationAmong(op1: UID, op2: UID): UID;
contains(operationId: UID): boolean;
/**
* Add the given operation as the first operation
*/
prepend(operation: Operation<T>): void;
/**
* add the given operation after the given predecessorOpId
*/
insert(newOperation: Operation<T>, predecessorOpId: UID): void;
/**
* Add the given operation as the last operation
*/
append(operation: Operation<T>): void;
/**
* Append operations in the given branch to this branch.
*/
appendBranch(branch: Branch<T>): void;
/**
* Create and return a copy of this branch, starting after the given operationId
*/
fork(operationId: UID): Branch<T>;
/**
* Transform all the operations in this branch with the given transformation
*/
transform(transformation: Transformation<T>): void;
/**
* Cut the branch before the operation, meaning the operation
* and all following operations are dropped.
*/
cutBefore(operationId: UID): void;
/**
* Cut the branch after the operation, meaning all following operations are dropped.
*/
cutAfter(operationId: UID): void;
/**
* Find an operation in this branch based on its id.
* This returns the operation itself, operations which comes before it
* and operation which comes after it.
*/
private locateOperation;
}
interface CreateRevisionOptions {
revisionId?: UID;
clientId?: UID;
pending?: boolean;
}
interface HistoryChange {
key: string;
target: any;
before: any;
}
interface WorkbookHistory<Plugin> {
update<T extends keyof Plugin>(key: T, val: Plugin[T]): void;
update<T extends keyof Plugin, U extends keyof NonNullable<Plugin[T]>>(key1: T, key2: U, val: NonNullable<Plugin[T]>[U]): void;
update<T extends keyof Plugin, U extends keyof NonNullable<Plugin[T]>, K extends keyof NonNullable<NonNullable<Plugin[T]>[U]>>(key1: T, key2: U, key3: K, val: NonNullable<NonNullable<Plugin[T]>[U]>[K]): void;
update<T extends keyof Plugin, U extends keyof NonNullable<Plugin[T]>, K extends keyof NonNullable<NonNullable<Plugin[T]>[U]>, V extends keyof NonNullable<NonNullable<NonNullable<Plugin[T]>[U]>[K]>>(key1: T, key2: U, key3: K, key4: V, val: NonNullable<NonNullable<NonNullable<Plugin[T]>[U]>[K]>[V]): void;
update<T extends keyof Plugin, U extends keyof NonNullable<Plugin[T]>, K extends keyof NonNullable<NonNullable<Plugin[T]>[U]>, V extends keyof NonNullable<NonNullable<NonNullable<Plugin[T]>[U]>[K]>, W extends keyof NonNullable<NonNullable<NonNullable<NonNullable<Plugin[T]>[U]>[K]>[V]>>(key1: T, key2: U, key3: K, key4: V, key5: W, val: NonNullable<NonNullable<NonNullable<NonNullable<Plugin[T]>[U]>[K]>[V]>[W]): void;
update<T extends keyof Plugin, U extends keyof NonNullable<Plugin[T]>, K extends keyof NonNullable<NonNullable<Plugin[T]>[U]>, V extends keyof NonNullable<NonNullable<NonNullable<Plugin[T]>[U]>[K]>, W extends keyof NonNullable<NonNullable<NonNullable<NonNullable<Plugin[T]>[U]>[K]>[V]>, Y extends keyof NonNullable<NonNullable<NonNullable<NonNullable<NonNullable<Plugin[T]>[U]>[K]>[V]>[W]>>(key1: T, key2: U, key3: K, key4: V, key5: W, key6: Y, val: NonNullable<NonNullable<NonNullable<NonNullable<NonNullable<Plugin[T]>[U]>[K]>[V]>[W]>[Y]): void;
}
type Transformation<T = unknown> = (dataToTransform: T) => T;
interface TransformationFactory<T = unknown> {
/**
* Build a transformation function to transform any operation as if the execution of
* a previous `operation` was omitted.
*/
without: (operation: T) => Transformation<T>;
/**
* Build a transformation function to transform any operation as if a new `operation` was
* executed before.
*/
with: (operation: T) => Transformation<T>;
}
interface OperationSequenceNode<T> {
operation: Operation<T>;
branch: Branch<T>;
isCancelled: boolean;
next?: {
operation: Operation<T>;
branch: Branch<T>;
};
}
type HistoryPath = [any, ...(number | string)[]];
declare class StateObserver {
private changes;
private commands;
/**
* Record the changes which could happen in the given callback, save them in a
* new revision with the given id and userId.
*/
recordChanges(callback: () => void): {
changes: HistoryChange[];
commands: CoreCommand[];
};
addCommand(command: CoreCommand): void;
addChange(...args: [...HistoryPath, any]): void;
}
interface CarouselState {
readonly carousels: Record<UID, Record<UID, Carousel | undefined> | undefined>;
}
declare class CarouselPlugin extends CorePlugin<CarouselState> implements CarouselState {
static getters: readonly ["getCarousel", "doesCarouselExist"];
readonly carousels: Record<UID, Record<UID, Carousel | undefined> | undefined>;
allowDispatch(cmd: CoreCommand): CommandResult.Success | CommandResult.InvalidFigureId | CommandResult.DuplicatedFigureId;
handle(cmd: CoreCommand): void;
doesCarouselExist(figureId: UID): boolean;
getCarousel(figureId: UID): Carousel;
private removeDeletedCharts;
import(data: WorkbookData): void;
export(data: WorkbookData): void;
}
interface CoreState$1 {
cells: Record<UID, Record<UID, Cell | undefined> | undefined>;
nextId: number;
}
/**
* Core Plugin
*
* This is the most fundamental of all plugins. It defines how to interact with
* cell and sheet content.
*/
declare class CellPlugin extends CorePlugin<CoreState$1> implements CoreState$1 {
static getters: readonly ["zoneToXC", "getCells", "getTranslatedCellFormula", "getCellById", "getFormulaString", "getFormulaMovedInSheet"];
readonly nextId = 1;
readonly cells: {
[sheetId: string]: {
[id: string]: Cell;
};
};
adaptRanges({ applyChange }: RangeAdapterFunctions, sheetId: UID, sheetName: AdaptSheetName): void;
allowDispatch(cmd: CoreCommand): CommandResult | CommandResult[];
handle(cmd: CoreCommand): void;
private clearZones;
/**
* Set a format to all the cells in a zone
*/
private setFormatter;
/**
* Clear the styles and format of zones
*/
private clearFormatting;
/**
* Clear the styles, the format and the content of zones
*/
private clearCells;
/**
* Copy the format of the reference column/row to the new columns/rows.
*/
private handleAddColumnsRows;
import(data: WorkbookData): void;
export(data: WorkbookData): void;
importCell(sheetId: UID, content?: string, format?: Format): Cell;
exportForExcel(data: ExcelWorkbookData): void;
getCells(sheetId: UID): Record<UID, Cell>;
/**
* get a cell by ID. Used in evaluation when evaluating an async cell, we need to be able to find it back after
* starting an async evaluation even if it has been moved or re-allocated
*/
getCellById(cellId: UID): Cell | undefined;
getFormulaString(sheetId: UID, tokens: Token[], dependencies: Range[], useBoundedReference?: boolean): string;
getTranslatedCellFormula(sheetId: UID, offsetX: number, offsetY: number, tokens: Token[]): string;
getFormulaMovedInSheet(originSheetId: UID, targetSheetId: UID, tokens: Token[]): string;
/**
* Converts a zone to a XC coordinate system
*
* The conversion also treats merges as one single cell
*
* Examples:
* {top:0,left:0,right:0,bottom:0} ==> A1
* {top:0,left:0,right:1,bottom:1} ==> A1:B2
*
* if A1:B2 is a merge:
* {top:0,left:0,right:1,bottom:1} ==> A1
* {top:1,left:0,right:1,bottom:2} ==> A1:B3
*
* if A1:B2 and A4:B5 are merges:
* {top:1,left:0,right:1,bottom:3} ==> A1:A5
*/
zoneToXC(sheetId: UID, zone: Zone, fixedParts?: RangePart[]): string;
/**
* Copy the format of one column to other columns.
*/
private copyColumnFormat;
/**
* Copy the format of one row to other rows.
*/
private copyRowFormat;
/**
* gets the currently used style and format of a cell based on it's coordinates
*/
private getFormat;
private getNextUid;
private updateCell;
private createCell;
private createLiteralCell;
private createFormulaCell;
/**
* Create a new formula cell with the content
* being a computed property to rebuild the dependencies XC.
*/
private createFormulaCellWithDependencies;
private checkCellOutOfSheet;
private checkUselessClearCell;
private checkUselessUpdateCell;
}
interface Validator {
/**
* Combine multiple validation functions into a single function
* returning the list of result of every validation.
*/
batchValidations<T>(...validations: Validation<T>[]): Validation<T>;
/**
* Combine multiple validation functions. Every validation is executed one after
* the other. As soon as one validation fails, it stops and the cancelled reason
* is returned.
*/
chainValidations<T>(...validations: Validation<T>[]): Validation<T>;
checkValidations<T>(command: T, ...validations: Validation<T>[]): CommandResult | CommandResult[];
}
/**
* AbstractChart is the class from which every Chart should inherit.
* The role of this class is to maintain the state of each chart.
*/
declare abstract class AbstractChart {
readonly sheetId: UID;
readonly title: TitleDesign;
abstract readonly type: ChartType;
protected readonly getters: CoreGetters;
readonly humanize: boolean;
constructor(definition: ChartDefinition, sheetId: UID, getters: CoreGetters);
/**
* Validate the chart definition given as arguments. This function will be
* called from allowDispatch function
*/
static validateChartDefinition(validator: Validator, definition: ChartDefinition): CommandResult | CommandResult[];
/**
* Get a new chart definition transformed with the executed command. This
* functions will be called during operational transform process
*/
static transformDefinition(chartSheetId: UID, definition: ChartDefinition, applyChange: RangeAdapter): ChartDefinition;
/**
* Get an empty definition based on the given context
*/
static getDefinitionFromContextCreation(context: ChartCreationContext): ChartDefinition;
/**
* Get the definition of the chart
*/
abstract getDefinition(): ChartDefinition;
/**
* Get the definition of the chart that will be used for excel export.
* If the chart is not supported by Excel, this function returns undefined.
*/
abstract getDefinitionForExcel(getters: CoreGetters): ExcelChartDefinition | undefined;
/**
* This function should be used to update all the ranges of the chart after
* a grid change (add/remove col/row, rename sheet, ...)
*/
abstract updateRanges(rangeAdapters: RangeAdapterFunctions): AbstractChart;
/**
* Duplicate the chart when a sheet is duplicated.
* The ranges that are in the same sheet as the chart are adapted to the new sheetId.
*/
abstract duplicateInDuplicatedSheet(newSheetId: UID): AbstractChart;
/**
* Get a copy a the chart in the given sheetId.
* The ranges of the chart will stay the same as the copied chart.
*/
abstract copyInSheetId(sheetId: UID): AbstractChart;
/**
* Extract the ChartCreationContext of the chart
*/
abstract getContextCreation(): ChartCreationContext;
protected getCommonDataSetAttributesForExcel(labelRange: Range | undefined, dataSets: DataSet[], shouldRemoveFirstLabel: boolean): {
dataSets: ExcelChartDataset[];
labelRange: string | undefined;
};
}
interface FigureChart {
figureId: UID;
chart: AbstractChart;
}
interface ChartState {
readonly charts: Record<UID, FigureChart | undefined>;
}
declare class ChartPlugin extends CorePlugin<ChartState> implements ChartState {
static getters: readonly ["isChartDefined", "getChartDefinition", "getChartType", "getChartIds", "getChart", "getFigureIdFromChartId", "getContextCreationChart"];
readonly charts: Record<UID, FigureChart | undefined>;
private createChart;
private validateChartDefinition;
adaptRanges(rangeAdapters: RangeAdapterFunctions): void;
allowDispatch(cmd: Command): CommandResult | CommandResult[];
handle(cmd: CoreCommand): void;
getContextCreationChart(chartId: UID): ChartCreationContext | undefined;
getChart(chartId: UID): AbstractChart | undefined;
getFigureIdFromChartId(chartId: UID): UID;
getChartType(chartId: UID): ChartType;
isChartDefined(chartId: UID): boolean;
getChartIds(sheetId: UID): string[];
getChartDefinition(chartId: UID): ChartDefinition;
import(data: WorkbookData): void;
export(data: WorkbookData): void;
/**
* Add a figure with tag chart with the given id at the given position
*/
private addFigure;
/**
* Add a chart in the local state. If a chart already exists, this chart is
* replaced
*/
private addChart;
private checkChartDuplicate;
private checkChartExists;
private checkChartChanged;
/** If the command is meant to create a new figure, the position & offset argument need to be defined in the command */
private checkFigureArguments;
}
/**
* https://docs.microsoft.com/en-us/openspecs/office_standards/ms-xlsx/025ea6e4-ad42-43ea-a016-16f4e4688ac8
*/
interface ConditionalFormat {
id: UID;
rule: ConditionalFormatRule;
stopIfTrue?: boolean;
ranges: string[];
}
interface ConditionalFormatInternal extends Omit<ConditionalFormat, "ranges" | "rule"> {
ranges: Range[];
rule: ConditionalFormatRuleInternal;
}
type ConditionalFormatRule = SingleColorRules | ColorScaleRule | IconSetRule | DataBarRule;
type ConditionalFormatRuleInternal = SingleColorRules | ColorScaleRule | IconSetRule | DataBarRuleInternal;
type SingleColorRules = CellIsRule;
interface SingleColorRule {
style: Style;
}
interface CellIsRule extends SingleColorRule {
type: "CellIsRule";
operator: ConditionalFormattingOperatorValues;
values: string[];
dateValue?: DateCriterionValue;
}
type ThresholdType = "value" | "number" | "percentage" | "percentile" | "formula";
type ColorScaleThreshold = {
color: number;
type: ThresholdType;
value?: string;
};
type ColorScaleMidPointThreshold = {
color: number;
type: Exclude<ThresholdType, "value">;
value: string;
};
type IconThreshold = {
type: Exclude<ThresholdType, "value">;
operator: "gt" | "ge";
value: string;
};
interface ColorScaleRule {
type: "ColorScaleRule";
minimum: ColorScaleThreshold;
maximum: ColorScaleThreshold;
midpoint?: ColorScaleMidPointThreshold;
}
interface DataBarRule {
type: "DataBarRule";
color: number;
rangeValues?: string;
}
interface DataBarRuleInternal extends Omit<DataBarRule, "rangeValues"> {
rangeValues?: Range;
}
interface IconSet {
upper: string;
middle: string;
lower: string;
}
interface IconSetRule {
type: "IconSetRule";
icons: IconSet;
upperInflectionPoint: IconThreshold;
lowerInflectionPoint: IconThreshold;
}
declare const cfOperators: readonly ["containsText", "notContainsText", "isGreaterThan", "isGreaterOrEqualTo", "isLessThan", "isLessOrEqualTo", "isBetween", "isNotBetween", "beginsWithText", "endsWithText", "isNotEmpty", "isEmpty", "isNotEqual", "isEqual", "customFormula", "dateIs", "dateIsBefore", "dateIsAfter", "dateIsOnOrBefore", "dateIsOnOrAfter"];
type ConditionalFormattingOperatorValues = (typeof cfOperators)[number];
interface ConditionalFormatState {
readonly cfRules: {
[sheet: string]: ConditionalFormatInternal[];
};
}
declare class ConditionalFormatPlugin extends CorePlugin<ConditionalFormatState> implements ConditionalFormatState {
static getters: readonly ["getConditionalFormats", "getRulesSelection", "getRulesByCell", "getAdaptedCfRanges"];
readonly cfRules: {
[sheet: string]: ConditionalFormatInternal[];
};
adaptCFFormulas({ applyChange, adaptFormulaString }: RangeAdapterFunctions): void;
adaptCFRanges(sheetId: UID, { applyChange }: RangeAdapterFunctions): void;
adaptRanges(rangeAdapters: RangeAdapterFunctions, sheetId: UID): void;
allowDispatch(cmd: Command): CommandResult | CommandResult[];
handle(cmd: CoreCommand): void;
import(data: WorkbookData): void;
export(data: Partial<WorkbookData>): void;
exportForExcel(data: ExcelWorkbookData): void;
/**
* Returns all the conditional format rules defined for the current sheet to display the user
*/
getConditionalFormats(sheetId: UID): ConditionalFormat[];
getRulesSelection(sheetId: UID, selection: Zone[]): UID[];
getRulesByZone(sheetId: UID, zone: Zone): Set<UID>;
getRulesByCell(sheetId: UID, cellCol: number, cellRow: number): Set<ConditionalFormat>;
/**
* Add or remove cells to a given conditional formatting rule and return the adapted CF's XCs.
*/
getAdaptedCfRanges(sheetId: UID, cf: ConditionalFormat, toAdd: Zone[], toRemove: Zone[]): RangeData[] | undefined;
private mapToConditionalFormat;
private mapToConditionalFormatInternal;
/**
* Add or replace a conditional format rule
*/
private addConditionalFormatting;
private checkValidPriorityChange;
private checkEmptyRange;
private checkCFRule;
private checkCFHasChanged;
private checkOperatorArgsNumber;
private checkNaN;
private checkFormulaCompilation;
private checkThresholds;
private checkInflectionPoints;
private checkLowerBiggerThanUpper;
private checkMinBiggerThanMax;
private checkMidBiggerThanMax;
private checkMinBiggerThanMid;
private checkCFValues;
private removeConditionalFormatting;
private changeCFPriority;
}
interface DataValidationRule {
id: UID;
criterion: DataValidationCriterion;
ranges: Range[];
isBlocking?: boolean;
}
type TextContainsCriterion = {
type: "containsText";
values: string[];
};
type TextNotContainsCriterion = {
type: "notContainsText";
values: string[];
};
type TextIsCriterion = {
type: "isEqualText";
values: string[];
};
type TextIsEmailCriterion = {
type: "isEmail";
values: string[];
};
type TextIsLinkCriterion = {
type: "isLink";
values: string[];
};
type DateIsCriterion = {
type: "dateIs";
dateValue: DateCriterionValue;
values: string[];
};
type DateIsBeforeCriterion = {
type: "dateIsBefore";
dateValue: DateCriterionValue;
values: string[];
};
type DateIsOnOrBeforeCriterion = {
type: "dateIsOnOrBefore";
dateValue: DateCriterionValue;
values: string[];
};
type DateIsAfterCriterion = {
type: "dateIsAfter";
dateValue: DateCriterionValue;
values: string[];
};
type DateIsOnOrAfterCriterion = {
type: "dateIsOnOrAfter";
dateValue: DateCriterionValue;
values: string[];
};
type DateIsBetweenCriterion = {
type: "dateIsBetween";
values: string[];
};
type DateIsNotBetweenCriterion = {
type: "dateIsNotBetween";
values: string[];
};
type DateIsValidCriterion = {
type: "dateIsValid";
values: string[];
};
type IsEqualCriterion = {
type: "isEqual";
values: string[];
};
type IsNotEqualCriterion = {
type: "isNotEqual";
values: string[];
};
type IsGreaterThanCriterion = {
type: "isGreaterThan";
values: string[];
};
type IsGreaterOrEqualToCriterion = {
type: "isGreaterOrEqualTo";
values: string[];
};
type IsLessThanCriterion = {
type: "isLessThan";
values: string[];
};
type IsLessOrEqualToCriterion = {
type: "isLessOrEqualTo";
values: string[];
};
type IsBetweenCriterion = {
type: "isBetween";
values: string[];
};
type IsNotBetweenCriterion = {
type: "isNotBetween";
values: string[];
};
type IsCheckboxCriterion = {
type: "isBoolean";
values: string[];
};
type IsValueInListCriterion = {
type: "isValueInList";
values: string[];
colors?: Record<string, Color | undefined>;
displayStyle: "arrow" | "plainText" | "chip";
};
type IsValueInRangeCriterion = {
type: "isValueInRange";
values: string[];
colors?: Record<string, Color | undefined>;
displayStyle: "arrow" | "plainText" | "chip";
};
type CustomFormulaCriterion = {
type: "customFormula";
values: string[];
};
type DataValidationCriterion = TextContainsCriterion | TextNotContainsCriterion | TextIsCriterion | TextIsEmailCriterion | TextIsLinkCriterion | IsBetweenCriterion | DateIsCriterion | DateIsBeforeCriterion | DateIsOnOrBeforeCriterion | DateIsAfterCriterion | DateIsOnOrAfterCriterion | DateIsBetweenCriterion | DateIsNotBetweenCriterion | DateIsValidCriterion | IsEqualCriterion | IsNotEqualCriterion | IsGreaterThanCriterion | IsGreaterOrEqualToCriterion | IsLessThanCriterion | IsLessOrEqualToCriterion | IsNotBetweenCriterion | IsCheckboxCriterion | IsValueInListCriterion | IsValueInRangeCriterion | CustomFormulaCriterion;
type DataValidationCriterionType = DataValidationCriterion["type"];
interface DataValidationState {
readonly rules: {
[sheet: string]: DataValidationRule[];
};
}
declare class DataValidationPlugin extends CorePlugin<DataValidationState> implements DataValidationState {
static getters: readonly ["cellHasListDataValidationIcon", "getDataValidationRule", "getDataValidationRules", "getValidationRuleForCell"];
readonly rules: {
[sheet: string]: DataValidationRule[];
};
adaptRanges(rangeAdapters: RangeAdapterFunctions, sheetId: UID): void;
private adaptDVFormulas;
private adaptDVRanges;
allowDispatch(cmd: Command): CommandResult | CommandResult[];
handle(cmd: CoreCommand): void;
getDataValidationRules(sheetId: UID): DataValidationRule[];
getDataValidationRule(sheetId: UID, id: UID): DataValidationRule | undefined;
getValidationRuleForCell({ sheetId, col, row }: CellPosition): DataValidationRule | undefined;
cellHasListDataValidationIcon(cellPosition: CellPosition): boolean;
private addDataValidationRule;
private removeRangesFromRules;
private removeDataValidationRule;
private setCenterStyleToBooleanCells;
private checkEmptyRange;
import(data: WorkbookData): void;
export(data: Partial<WorkbookData>): void;
exportForExcel(data: ExcelWorkbookData): void;
private checkCriterionTypeIsValid;
private checkCriterionHasValidNumberOfValues;
private checkCriterionValuesAreValid;
private checkValidRange;
}
interface FigureState {
readonly figures: {
[sheet: string]: Record<UID, Figure | undefined> | undefined;
};
readonly insertionOrders: UID[];
}
declare class FigurePlugin extends CorePlugin<FigureState> implements FigureState {
static getters: readonly ["getFigures", "getFigure", "getFigureSheetId"];
readonly figures: {
[sheet: string]: Record<UID, Figure | undefined> | undefined;
};
readonly insertionOrders: UID[];
adaptRanges({ applyChange }: RangeAdapterFunctions, sheetId: UID): void;
allowDispatch(cmd: CoreCommand): CommandResult | CommandResult[];
beforeHandle(cmd: CoreCommand): void;
handle(cmd: CoreCommand): void;
private onColRemove;
private onRowRemove;
private getPositionInSheet;
private updateFigure;
private addFigure;
private deleteSheet;
private removeFigure;
private checkFigureExists;
private checkFigureDuplicate;
private checkFigureAnchorOffset;
getFigures(sheetId: UID): Figure[];
getFigure(sheetId: UID, figureId: string): Figure | undefined;
getFigureSheetId(figureId: string): UID | undefined;
import(data: WorkbookData): void;
export(data: WorkbookData): void;
exportForExcel(data: ExcelWorkbookData): void;
}
interface State {
groups: Record<UID, Record<Dimension, HeaderGroup[]>>;
}
declare class HeaderGroupingPlugin extends CorePlugin<State> {
static getters: readonly ["getHeaderGroups", "getGroupsLayers", "getVisibleGroupLayers", "getHeaderGroup", "getHeaderGroupsInZone", "isGroupFolded", "isRowFolded", "isColFolded"];
private readonly groups;
allowDispatch(cmd: CoreCommand): CommandResult;
handle(cmd: CoreCommand): void;
getHeaderGroups(sheetId: UID, dim: Dimension): HeaderGroup[];
getHeaderGroup(sheetId: UID, dim: Dimension, start: number, end: number): HeaderGroup | undefined;
getHeaderGroupsInZone(sheetId: UID, dim: Dimension, zone: Zone): HeaderGroup[];
/**
* Get all the groups of a sheet in a dimension, and return an array of layers of those groups.
*
* The layering rules are:
* 1) A group containing another group should be on a layer above the group it contains
* 2) The widest/highest groups should be on the left/top layer compared to the groups it contains
* 3) The group should be on the left/top-most layer possible, barring intersections with other groups (see rules 1 and 2)
*/
getGroupsLayers(sheetId: UID, dimension: Dimension): HeaderGroup[][];
/**
* Get all the groups of a sheet in a dimension, and return an array of layers of those groups,
* excluding the groups that are totally hidden.
*/
getVisibleGroupLayers(sheetId: UID, dimension: Dimension): HeaderGroup[][];
isGroupFolded(sheetId: UID, dimension: Dimension, start: number, end: number): boolean;
isRowFolded(sheetId: UID, row: HeaderIndex): boolean;
isColFolded(sheetId: UID, col: HeaderIndex): boolean;
private getGroupId;
/**
* To get layers of groups, and to add/remove headers from groups, we can see each header of a group as a brick. Each
* brick falls down in the pile corresponding to its header, until it hits another brick, or the ground.
*
* With this abstraction, we can very simply group/ungroup headers from groups, and get the layers of groups.
* - grouping headers is done by adding a brick to each header pile
* - un-grouping headers is done by removing a brick from each header pile
* - getting the layers of groups is done by simply letting the brick fall and checking the result
*
* Example:
* We have 2 groups ([A=>E] and [C=>D]), and we want to group headers [C=>F]
*
* Headers : A B C D E F G A B C D E F G A B C D E F G
* Headers to group: [C=>D]: _ _ [C=>F]: _ _ _ _
* | | ==> | | | | ==> ==> Result: 3 groups
* | | ˅ ˅ | | _ _ - [C=>D]
* Groups: ˅ ˅ _ _ ˅ | _ _ _ - [C=>E]
* Groups: _ _ _ _ _ _ _ _ _ _ ˅ _ _ _ _ _ _ - [A=>F]
* @param groups
* @param start start of the range where to add/remove headers
* @param end end of the range where to add/remove headers
* @param delta -1: remove headers, 1: add headers, 0: get layers (don't add/remove anything)
*/
private bricksFallingAlgorithm;
private groupHeaders;
/**
* Ungroup the given headers. The headers will be taken out of the group they are in. This might split a group into two
* if the headers were in the middle of a group. If multiple groups contains a header, it will only be taken out of the
* lowest group in the layering of the groups.
*/
private unGroupHeaders;
private moveGroupsOnHeaderInsertion;
private moveGroupsOnHeaderDeletion;
private doGroupOverlap;
private removeDuplicateGroups;
private findGroupWithStartEnd;
/**
* Fold the given group, and all the groups starting at the same index that are contained inside the given group.
*/
private foldHeaderGroup;
/**
* Unfold the given group, and all the groups starting at the same index that contain the given group.
*/
private unfoldHeaderGroup;
private getGroupIndex;
import(data: WorkbookData): void;
export(data: WorkbookData): void;
exportForExcel(data: ExcelWorkbookData): void;
}
interface HeaderSizeState$1 {
sizes: Record<UID, Record<Dimension, Array<Pixel | undefined>>>;
}
declare class HeaderSizePlugin extends CorePlugin<HeaderSizeState$1> implements HeaderSizeState$1 {
static getters: readonly ["getUserRowSize", "getColSize"];
readonly sizes: Record<UID, Record<Dimension, Array<Pixel | undefined>>>;
handle(cmd: Command): void;
getColSize(sheetId: UID, index: HeaderIndex): Pixel;
getUserRowSize(sheetId: UID, index: HeaderIndex): Pixel | undefined;
import(data: WorkbookData): void;
exportForExcel(data: ExcelWorkbookData): void;
export(data: WorkbookData): void;
/**
* Export the header sizes
*
* @param exportDefaults : if true, export column/row sizes even if they have the default size
*/
exportData(data: WorkbookData, exportDefaults?: boolean): void;
}
declare class HeaderVisibilityPlugin extends CorePlugin {
static getters: readonly ["checkElementsIncludeAllVisibleHeaders", "getHiddenColsGroups", "getHiddenRowsGroups", "isHeaderHiddenByUser", "isRowHiddenByUser", "isColHiddenByUser"];
private readonly hiddenHeaders;
allowDispatch(cmd: Command): CommandResult.Success | CommandResult.NotEnoughElements | CommandResult.InvalidSheetId | CommandResult.TooManyHiddenElements | CommandResult.InvalidHeaderIndex;
handle(cmd: Command): void;
checkElementsIncludeAllVisibleHeaders(sheetId: UID, dimension: Dimension, elements: HeaderIndex[]): boolean;
isHeaderHiddenByUser(sheetId: UID, dimension: Dimension, index: HeaderIndex): boolean;
isRowHiddenByUser(sheetId: UID, index: HeaderIndex): boolean;
isColHiddenByUser(sheetId: UID, index: HeaderIndex): boolean;
getHiddenColsGroups(sheetId: UID): ConsecutiveIndexes[];
getHiddenRowsGroups(sheetId: UID): ConsecutiveIndexes[];
private getAllVisibleHeaders;
import(data: WorkbookData): void;
exportForExcel(data: ExcelWorkbookData): void;
export(data: WorkbookData): void;
exportData(data: WorkbookData, exportDefaults?: boolean): void;
}
type ImageSVG = {
name: string;
width: number;
height: number;
paths: {
path: string;
fillColor: Color;
}[];
};
interface Image$1 {
path: string;
size: FigureSize;
mimetype?: string;
}
declare const AllowedImageMimeTypes: readonly ["image/avif", "image/bmp", "image/gif", "image/vnd.microsoft.icon", "image/jpeg", "image/png", "image/tiff", "image/webp"];
type FilePath = string;
/**
* FileStore manage the transfer of file with the server.
*/
interface FileStore {
/**
* Upload a file to a server and returns its path.
*/
upload(file: File): Promise<FilePath>;
/**
* get File from the server
*/
getFile(filePath: FilePath): Promise<File | Blob>;
}
/**
* ImageProvider can request the user to input an image file before sending it to a server.
*/
interface ImageProviderInterface {
/**
* RequestImage ask the user to input an image file. Then send it to a server trough an FileStore. Finally it return the path and the size of the image in the server.
*/
requestImage(): Promise<Image$1>;
uploadFile(file: File | Blob): Promise<Image$1>;
getImageOriginalSize(path: string): Promise<FigureSize>;
}
interface ImageState {
readonly images: Record<UID, Record<UID, Image$1 | undefined> | undefined>;
}
declare class ImagePlugin extends CorePlugin<ImageState> implements ImageState {
static getters: readonly ["getImage", "getImagePath", "getImageSize"];
readonly fileStore?: FileStore;
readonly images: Record<UID, Record<UID, Image$1 | undefined> | undefined>;
/**
* paths of images synced with the file store server.
*/
readonly syncedImages: Set<Image$1["path"]>;
constructor(config: CorePluginConfig);
allowDispatch(cmd: CoreCommand): CommandResult.Success | CommandResult.InvalidFigureId;
handle(cmd: CoreCommand): void;
getImage(figureId: UID): Image$1;
getImagePath(figureId: UID): string;
getImageSize(figureId: UID): FigureSize;
private addFigure;
import(data: WorkbookData): void;
export(data: WorkbookData): void;
exportForExcel(data: ExcelWorkbookData): void;
}
type SheetMergeCellMap = Record<number, Record<number, number | undefined> | undefined>;
interface MergeState {
readonly merges: Record<UID, Record<number, Range | undefined> | undefined>;
readonly mergeCellMap: Record<UID, SheetMergeCellMap | undefined>;
}
declare class MergePlugin extends CorePlugin<MergeState> implements MergeState {
static getters: readonly ["isInMerge", "isInSameMerge", "isMergeHidden", "getMainCellPosition", "expandZone", "doesIntersectMerge", "doesColumnsHaveCommonMerges", "doesRowsHaveCommonMerges", "getMerges", "getMerge", "getMergesInZone", "isSingleCellOrMerge", "getSelectionRangeString", "isMainCellPosition"];
private nextId;
readonly merges: Record<UID, Record<number, Range | undefined> | undefined>;
readonly mergeCellMap: Record<UID, SheetMergeCellMap | undefined>;
allowDispatch(cmd: CoreCommand): CommandResult | CommandResult[];
handle(cmd: CoreCommand): void;
adaptRanges(rangeAdapters: RangeAdapterFunctions, sheetId: UID): void;
getMerges(sheetId: UID): Merge[];
getMerge({ sheetId, col, row }: CellPosition): Merge | undefined;
getMergesInZone(sheetId: UID, zone: Zone): Merge[];
/**
* Same as `getRangeString` but add all necessary merge to the range to make it a valid selection
*/
getSelectionRangeString(range: Range, forSheetId: UID): string;
/**
* Return true if the zone intersects an existing merge:
* if they have at least a common cell
*/
doesIntersectMerge(sheetId: UID, zone: Zone): boolean;
/**
* Returns true if two columns have at least one merge in common
*/
doesColumnsHaveCommonMerges(sheetId: string, colA: HeaderIndex, colB: HeaderIndex): boolean;
/**
* Returns true if two rows have at least one merge in common
*/
doesRowsHaveCommonMerges(sheetId: string, rowA: HeaderIndex, rowB: HeaderIndex): boolean;
/**
* Add all necessary merge to the current selection to make it valid
*/
expandZone(sheetId: UID, zone: Zone): Zone;
isInSameMerge(sheetId: UID, colA: HeaderIndex, rowA: HeaderIndex, colB: HeaderIndex, rowB: HeaderIndex): boolean;
isInMerge({ sheetId, col, row }: CellPosition): boolean;
getMainCellPosition(position: CellPosition): CellPosition;
isMergeHidden(sheetId: UID, merge: Merge): boolean;
/**
* Check if the zone represents a single cell or a single merge.
*/
isSingleCellOrMerge(sheetId: UID, zone: Zone): boolean;
isMainCellPosition(position: CellPosition): boolean;
/**
* Return true if the current selection requires losing state if it is merged.
* This happens when there is some textual content in other cells than the
* top left.
*/
private isMergeDestructive;
private getMergeById;
private checkDestructiveMerge;
private checkOverlap;
private checkFrozenPanes;
/**
* The content of a merged cell should always be empty.
* Except for the top-left cell.
*/
private checkMergedContentUpdate;
private checkMergeExists;
/**
* Merge the current selection. Note that:
* - it assumes that we have a valid selection (no intersection with other
* merges)
* - it does nothing if the merge is trivial: A1:A1
*/
private addMerge;
private removeMerge;
/**
* Apply a range change on merges of a particular sheet.
*/
private applyRangeChangeOnSheet;
import(data: WorkbookData): void;
private importMerges;
export(data: WorkbookData): void;
exportForExcel(data: ExcelWorkbookData): void;
}
type Aggregator = "array_agg" | "count" | "count_distinct" | "bool_and" | "bool_or" | "max" | "min" | "avg" | "sum";
type Granularity = "day" | "month" | "year" | "second_number" | "minute_number" | "hour_number" | "day_of_week" | "day_of_month" | "iso_week_number" | "month_number" | "quarter_number";
interface PivotCoreDimension {
fieldName: string;
order?: SortDirection;
granularity?: Granularity | string;
isCustomField?: boolean;
parentField?: string;
customGroups?: PivotCustomGroup[];
}
interface PivotCoreMeasure {
/**
* Identifier of the measure, `technicalName:aggregator{:autoIncrementedNumber}`.
* It's used to identify the measure in the pivot formula.
*/
id: string;
userDefinedName?: string;
fieldName: string;
aggregator: Aggregator | string;
isHidden?: boolean;
format?: Format;
computedBy?: {
sheetId: UID;
formula: string;
};
display?: PivotMeasureDisplay;
}
interface CommonPivotCoreDefinition {
columns: PivotCoreDimension[];
rows: PivotCoreDimension[];
measures: PivotCoreMeasure[];
name: string;
deferUpdates?: boolean;
sortedColumn?: PivotSortedColumn;
collapsedDomains?: PivotCollapsedDomains;
customFields?: Record<string, PivotCustomGroupedField>;
style?: PivotStyle;
}
interface PivotSortedColumn {
order: SortDirection;
domain: PivotDomain;
measure: string;
}
interface PivotCollapsedDomains {
COL: PivotDomain[];
ROW: PivotDomain[];
}
interface PivotCustomGroupedField {
parentField: string;
name: string;
groups: PivotCustomGroup[];
}
interface PivotCustomGroup {
name: string;
values: CellValue[];
isOtherGroup?: boolean;
}
interface SpreadsheetPivotCoreDefinition extends CommonPivotCoreDefinition {
type: "SPREADSHEET";
dataSet?: {
sheetId: UID;
zone: Zone;
};
}
interface FakePivotDefinition extends CommonPivotCoreDefinition {
type: "FAKE";
}
type PivotCoreDefinition = SpreadsheetPivotCoreDefinition | FakePivotDefinition;
type TechnicalName = string;
interface PivotField {
name: TechnicalName;
type: string;
string: string;
aggregator?: string;
help?: string;
isCustomField?: boolean;
parentField?: string;
customGroups?: PivotCustomGroup[];
}
type PivotFields = Record<TechnicalName, PivotField | undefined>;
interface PivotMeasure extends PivotCoreMeasure {
displayName: string;
type: string;
isValid: boolean;
}
interface PivotDimension extends PivotCoreDimension {
nameWithGranularity: string;
displayName: string;
type: string;
isValid: boolean;
}
interface PivotTableColumn {
fields: string[];
values: CellValue[];
width: number;
offset: number;
}
interface PivotTableRow {
fields: string[];
values: CellValue[];
indent: number;
}
interface PivotTableData {
cols: PivotTableColumn[][];
rows: PivotTableRow[];
measures: string[];
fieldsType?: Record<string, string | undefined>;
}
interface PivotHeaderCell {
type: "HEADER";
domain: PivotDomain;
dimension: Dimension;
}
interface PivotMeasureHeaderCell {
type: "MEASURE_HEADER";
domain: PivotDomain;
measure: string;
}
interface PivotValueCell {
type: "VALUE";
domain: PivotDomain;
measure: string;
}
interface PivotEmptyCell {
type: "EMPTY";
}
type PivotTableCell = PivotHeaderCell | PivotMeasureHeaderCell | PivotValueCell | PivotEmptyCell;
interface PivotNode {
field: string;
type: string;
value: CellValue;
}
type PivotDomain = PivotNode[];
declare const PREVIOUS_VALUE = "(previous)";
declare const NEXT_VALUE = "(next)";
interface PivotMeasureDisplay {
type: PivotMeasureDisplayType;
fieldNameWithGranularity?: string;
value?: string | boolean | number | typeof PREVIOUS_VALUE | typeof NEXT_VALUE;
}
type PivotMeasureDisplayType = "no_calcul