@odoo/o-spreadsheet
Version:
A spreadsheet component
1,569 lines (1,525 loc) • 528 kB
TypeScript
import * as chart_js from 'chart.js';
import { ChartConfiguration, Point, Chart, Color as Color$1, ChartType as ChartType$1 } from 'chart.js';
import * as ChartGeo from 'chartjs-chart-geo';
import * as GeoJSON$1 from 'geojson';
import * as _odoo_owl from '@odoo/owl';
import { ComponentConstructor, Component } from '@odoo/owl';
import * as chart_js_dist_types_utils from 'chart.js/dist/types/utils';
import * as chart_js_dist_types_geometric from 'chart.js/dist/types/geometric';
import * as chart_js_dist_types_basic from 'chart.js/dist/types/basic';
interface Figure {
id: UID;
x: Pixel;
y: Pixel;
width: Pixel;
height: Pixel;
tag: string;
}
interface FigureSize {
width: Pixel;
height: Pixel;
}
interface ExcelFigureSize {
cx: number;
cy: number;
}
type ResizeDirection = -1 | 0 | 1;
/**
* Image source given to <img src="..."/>
*/
type ImageSrc = string;
interface Image$1 {
path: string;
size: FigureSize;
mimetype?: string;
}
type XLSXExportFile = XLSXExportImageFile | XLSXExportXMLFile;
interface XLSXExportXMLFile {
path: string;
content: string;
contentType?: string;
}
interface XLSXExportImageFile {
path: string;
imageSrc: string;
}
interface XLSXExport {
name: string;
files: XLSXExportFile[];
}
/**
* Standardized XLSX hexadecimal color (with or without alpha channel).
* Note that the alpha channel goes first! AARRGGBB
* e.g. "1E5010" or "331E5010"
*/
type XlsxHexColor = string & Alias;
type VerticalAxisPosition = "left" | "right";
type LegendPosition = "top" | "bottom" | "left" | "right" | "none";
interface ComboBarChartDefinition {
readonly dataSets: CustomizedDataSet[];
readonly dataSetsHaveTitle: boolean;
readonly labelRange?: string;
readonly title: TitleDesign;
readonly background?: Color;
readonly legendPosition: LegendPosition;
readonly aggregated?: boolean;
readonly axesDesign?: AxesDesign;
readonly showValues?: boolean;
}
interface BarChartDefinition extends ComboBarChartDefinition {
readonly type: "bar";
readonly stacked: boolean;
readonly horizontal?: boolean;
}
type BarChartRuntime = {
chartJsConfig: ChartConfiguration;
background: Color;
};
interface ComboChartDefinition extends ComboBarChartDefinition {
readonly dataSets: ComboChartDataSet[];
readonly type: "combo";
}
type ComboChartDataSet = CustomizedDataSet & {
type?: "bar" | "line";
};
type ComboChartRuntime = {
chartJsConfig: ChartConfiguration;
background: Color;
};
interface GaugeChartDefinition {
readonly type: "gauge";
readonly title: TitleDesign;
readonly dataRange?: string;
readonly sectionRule: SectionRule;
readonly background?: Color;
}
interface SectionRule {
readonly colors: ColorSet;
readonly rangeMin: string;
readonly rangeMax: string;
readonly lowerInflectionPoint: SectionThreshold;
readonly upperInflectionPoint: SectionThreshold;
}
interface ColorSet {
readonly lowerColor: Color;
readonly middleColor: Color;
readonly upperColor: Color;
}
interface SectionThreshold {
readonly type: "number" | "percentage";
readonly value: string;
readonly operator: "<" | "<=";
}
interface GaugeValue {
value: number;
label: string;
}
interface GaugeInflectionValue extends GaugeValue {
operator: "<" | "<=";
}
interface GaugeChartRuntime {
background: Color;
title: TitleDesign;
minValue: GaugeValue;
maxValue: GaugeValue;
gaugeValue?: GaugeValue;
inflectionValues: GaugeInflectionValue[];
colors: Color[];
}
interface GeoChartDefinition {
readonly type: "geo";
readonly dataSets: CustomizedDataSet[];
readonly dataSetsHaveTitle: boolean;
readonly labelRange?: string;
readonly title: TitleDesign;
readonly background?: Color;
readonly legendPosition: LegendPosition;
readonly axesDesign?: AxesDesign;
readonly aggregated?: boolean;
readonly colorScale?: GeoChartColorScale;
readonly missingValueColor?: Color;
readonly region?: string;
}
type GeoChartRuntime = {
chartJsConfig: ChartConfiguration;
background: Color;
};
interface GeoChartCustomColorScale {
minColor: Color;
midColor?: Color;
maxColor: Color;
}
type GeoChartColorScale = GeoChartCustomColorScale | "blues" | "cividis" | "greens" | "greys" | "oranges" | "purples" | "rainbow" | "reds" | "viridis";
type GeoChartProjection = "azimuthalEqualArea" | "azimuthalEquidistant" | "gnomonic" | "orthographic" | "stereographic" | "equalEarth" | "albers" | "albersUsa" | "conicConformal" | "conicEqualArea" | "conicEquidistant" | "equirectangular" | "mercator" | "transverseMercator" | "naturalEarth1";
interface GeoChartRegion {
id: string;
label: string;
defaultProjection: GeoChartProjection;
}
interface GeoChartRuntimeGenerationArgs extends ChartRuntimeGenerationArgs {
availableRegions: GeoChartRegion[];
getGeoJsonFeatures: (region: string) => GeoJSON.Feature[] | undefined;
geoFeatureNameToId: (region: string, featureName: string) => string | undefined;
}
interface LineChartDefinition {
readonly type: "line";
readonly dataSets: CustomizedDataSet[];
readonly dataSetsHaveTitle: boolean;
readonly labelRange?: string;
readonly title: TitleDesign;
readonly background?: Color;
readonly legendPosition: LegendPosition;
readonly labelsAsText: boolean;
readonly stacked: boolean;
readonly aggregated?: boolean;
readonly cumulative: boolean;
readonly axesDesign?: AxesDesign;
readonly fillArea?: boolean;
readonly showValues?: boolean;
}
type LineChartRuntime = {
chartJsConfig: ChartConfiguration;
background: Color;
};
interface PieChartDefinition {
readonly type: "pie";
readonly dataSets: CustomizedDataSet[];
readonly dataSetsHaveTitle: boolean;
readonly labelRange?: string;
readonly title: TitleDesign;
readonly background?: Color;
readonly legendPosition: LegendPosition;
readonly aggregated?: boolean;
readonly axesDesign?: AxesDesign;
readonly isDoughnut?: boolean;
readonly showValues?: boolean;
}
type PieChartRuntime = {
chartJsConfig: ChartConfiguration;
background: Color;
};
interface PyramidChartDefinition extends Omit<BarChartDefinition, "type"> {
readonly type: "pyramid";
}
type PyramidChartRuntime = {
chartJsConfig: ChartConfiguration;
background: Color;
};
interface RadarChartDefinition {
readonly dataSets: CustomizedDataSet[];
readonly dataSetsHaveTitle: boolean;
readonly labelRange?: string;
readonly title: TitleDesign;
readonly background?: Color;
readonly legendPosition: LegendPosition;
readonly aggregated?: boolean;
readonly type: "radar";
readonly stacked: boolean;
readonly axesDesign?: AxesDesign;
readonly fillArea?: boolean;
readonly showValues?: boolean;
}
type RadarChartRuntime = {
chartJsConfig: ChartConfiguration;
background: Color;
};
interface ScatterChartDefinition extends Omit<LineChartDefinition, "type" | "stacked" | "cumulative"> {
readonly type: "scatter";
}
type ScatterChartRuntime = LineChartRuntime;
interface ScorecardChartDefinition {
readonly type: "scorecard";
readonly title: TitleDesign;
readonly keyValue?: string;
readonly baseline?: string;
readonly baselineMode: BaselineMode;
readonly baselineDescr?: string;
readonly background?: Color;
readonly baselineColorUp: Color;
readonly baselineColorDown: Color;
readonly humanize?: boolean;
}
type BaselineMode = "text" | "difference" | "percentage" | "progress";
type BaselineArrowDirection = "neutral" | "up" | "down";
interface ProgressBar {
readonly value: number;
readonly color: Color;
}
interface ScorecardChartRuntime {
readonly title: TitleDesign;
readonly keyValue: string;
readonly baselineDisplay: string;
readonly baselineColor?: string;
readonly baselineArrow: BaselineArrowDirection;
readonly baselineDescr?: string;
readonly background: Color;
readonly fontColor: Color;
readonly keyValueStyle?: Style;
readonly baselineStyle?: Style;
readonly progressBar?: ProgressBar;
}
interface WaterfallChartDefinition {
readonly type: "waterfall";
readonly dataSets: CustomizedDataSet[];
readonly dataSetsHaveTitle: boolean;
readonly labelRange?: string;
readonly title: TitleDesign;
readonly background?: Color;
readonly verticalAxisPosition: VerticalAxisPosition;
readonly legendPosition: LegendPosition;
readonly aggregated?: boolean;
readonly showSubTotals: boolean;
readonly showConnectorLines: boolean;
readonly firstValueAsSubtotal?: boolean;
readonly positiveValuesColor?: Color;
readonly negativeValuesColor?: Color;
readonly subTotalValuesColor?: Color;
readonly axesDesign?: AxesDesign;
readonly showValues?: boolean;
}
type WaterfallChartRuntime = {
chartJsConfig: ChartConfiguration;
background: Color;
};
declare const CHART_TYPES: readonly ["line", "bar", "pie", "scorecard", "gauge", "scatter", "combo", "waterfall", "pyramid", "radar", "geo"];
type ChartType = (typeof CHART_TYPES)[number];
type ChartDefinition = LineChartDefinition | PieChartDefinition | BarChartDefinition | ScorecardChartDefinition | GaugeChartDefinition | ScatterChartDefinition | ComboChartDefinition | WaterfallChartDefinition | PyramidChartDefinition | RadarChartDefinition | GeoChartDefinition;
type ChartWithDataSetDefinition = Extract<ChartDefinition, {
dataSets: CustomizedDataSet[];
labelRange?: string;
}>;
type ChartJSRuntime = LineChartRuntime | PieChartRuntime | BarChartRuntime | ComboChartRuntime | ScatterChartRuntime | WaterfallChartRuntime | PyramidChartRuntime | RadarChartRuntime | GeoChartRuntime;
type ChartRuntime = ChartJSRuntime | ScorecardChartRuntime | GaugeChartRuntime;
interface LabelValues {
readonly values: string[];
readonly formattedValues: string[];
}
interface DatasetValues {
readonly label?: string;
readonly data: any[];
readonly hidden?: boolean;
}
interface DatasetDesign {
readonly backgroundColor?: string;
readonly yAxisId?: string;
readonly label?: string;
}
interface AxisDesign {
readonly title?: TitleDesign;
}
interface AxesDesign {
readonly x?: AxisDesign;
readonly y?: AxisDesign;
readonly y1?: AxisDesign;
}
interface TitleDesign {
readonly text?: string;
readonly bold?: boolean;
readonly italic?: boolean;
readonly align?: Align;
readonly color?: Color;
readonly fontSize?: number;
}
type TrendType = "polynomial" | "exponential" | "logarithmic" | "trailingMovingAverage";
interface TrendConfiguration {
type?: TrendType;
order?: number;
color?: Color;
display?: boolean;
window?: number;
}
type CustomizedDataSet = {
readonly dataRange: string;
readonly trend?: TrendConfiguration;
} & DatasetDesign;
type AxisType = "category" | "linear" | "time";
interface DataSet {
readonly labelCell?: Range;
readonly dataRange: Range;
readonly rightYAxis?: boolean;
readonly backgroundColor?: Color;
readonly customLabel?: string;
}
interface ExcelChartDataset {
readonly label?: {
text?: string;
} | {
reference?: string;
};
readonly range: string;
readonly backgroundColor?: Color;
readonly rightYAxis?: boolean;
}
type ExcelChartType = "line" | "bar" | "pie" | "combo" | "scatter" | "radar";
interface ExcelChartDefinition {
readonly title?: TitleDesign;
readonly type: ExcelChartType;
readonly dataSets: ExcelChartDataset[];
readonly labelRange?: string;
readonly backgroundColor: XlsxHexColor;
readonly fontColor: XlsxHexColor;
readonly legendPosition: LegendPosition;
readonly stacked?: boolean;
readonly cumulative?: boolean;
readonly verticalAxis?: {
useLeftAxis?: boolean;
useRightAxis?: boolean;
};
readonly axesDesign?: AxesDesign;
}
interface ChartCreationContext {
readonly range?: CustomizedDataSet[];
readonly title?: TitleDesign;
readonly background?: string;
readonly auxiliaryRange?: string;
readonly aggregated?: boolean;
readonly stacked?: boolean;
readonly cumulative?: boolean;
readonly dataSetsHaveTitle?: boolean;
readonly labelsAsText?: boolean;
readonly showSubTotals?: boolean;
readonly showConnectorLines?: boolean;
readonly firstValueAsSubtotal?: boolean;
readonly legendPosition?: LegendPosition;
readonly axesDesign?: AxesDesign;
readonly fillArea?: boolean;
readonly showValues?: boolean;
}
type ChartAxisFormats = {
[axisId: string]: Format | undefined;
} | undefined;
interface ChartRuntimeGenerationArgs {
dataSetsValues: DatasetValues[];
axisFormats: ChartAxisFormats;
labels: string[];
locale: Locale;
trendDataSetsValues?: (Point[] | undefined)[];
axisType?: AxisType;
}
/** Generic definition of chart to create a runtime: omit the chart type and the dataRange of the dataSets*/
type GenericDefinition<T extends ChartWithDataSetDefinition> = Partial<Omit<T, "dataSets" | "type">> & {
dataSets?: Omit<T["dataSets"][number], "dataRange">[];
};
/**
* This is a generic event bus based on the Owl event bus.
* This bus however ensures type safety across events and subscription callbacks.
*/
declare class EventBus<Event extends {
type: string;
}> {
subscriptions: {
[eventType: string]: Subscription[];
};
/**
* Add a listener for the 'eventType' events.
*
* Note that the 'owner' of this event can be anything, but will more likely
* be a component or a class. The idea is that the callback will be called with
* the proper owner bound.
*
* Also, the owner should be kind of unique. This will be used to remove the
* listener.
*/
on<T extends Event["type"], E extends Extract<Event, {
type: T;
}>>(type: T, owner: any, callback: (r: Omit<E, "type">) => void): void;
/**
* Emit an event of type 'eventType'. Any extra arguments will be passed to
* the listeners callback.
*/
trigger<T extends Event["type"], E extends Extract<Event, {
type: T;
}>>(type: T, payload?: Omit<E, "type">): void;
/**
* Remove a listener
*/
off<T extends Event["type"]>(eventType: T, owner: any): void;
/**
* Remove all subscriptions.
*/
clear(): void;
}
type Callback = (...args: any[]) => void;
interface Subscription {
owner: any;
callback: Callback;
}
declare class SelectiveHistory<T = unknown> {
private HEAD_BRANCH;
private HEAD_OPERATION;
private tree;
private readonly applyOperation;
private readonly revertOperation;
private readonly buildEmpty;
private readonly buildTransformation;
/**
* The selective history is a data structure used to register changes/updates of a state.
* Each change/update is called an "operation".
* The data structure allows to easily cancel (and redo) any operation individually.
* An operation can be represented by any data structure. It can be a "command", a "diff", etc.
* However it must have the following properties:
* - it can be applied to modify the state
* - it can be reverted on the state such that it was never executed.
* - it can be transformed given other operation (Operational Transformation)
*
* Since this data structure doesn't know anything about the state nor the structure of
* operations, the actual work must be performed by external functions given as parameters.
* @param initialOperationId
* @param applyOperation a function which can apply an operation to the state
* @param revertOperation a function which can revert an operation from the state
* @param buildEmpty a function returning an "empty" operation.
* i.e an operation that leaves the state unmodified once applied or reverted
* (used for internal implementation)
* @param buildTransformation Factory used to build transformations
*/
constructor(args: {
initialOperationId: UID;
applyOperation: (data: T) => void;
revertOperation: (data: T) => void;
buildEmpty: (id: UID) => T;
buildTransformation: TransformationFactory<T>;
});
/**
* Return the operation identified by its id.
*/
get(operationId: UID): T;
/**
* Append a new operation as the last one
*/
append(operationId: UID, data: T): void;
/**
* Insert a new operation after a specific operation (may not be the last operation).
* Following operations will be transformed according
* to the new operation.
*/
insert(operationId: UID, data: T, insertAfter: UID): void;
/**
* @param operationId operation to undo
* @param undoId the id of the "undo operation"
* @param insertAfter the id of the operation after which to insert the undo
*/
undo(operationId: UID, undoId: UID, insertAfter: UID): void;
/**
* @param operationId operation to redo
* @param redoId the if of the "redo operation"
* @param insertAfter the id of the operation after which to insert the redo
*/
redo(operationId: UID, redoId: UID, insertAfter: UID): void;
rebase(operationId: UID): void;
/**
* Revert the state as it was *before* the given operation was executed.
*/
private revertBefore;
/**
* Revert the state as it was *after* the given operation was executed.
*/
private revertTo;
/**
* Revert an execution
*/
private revert;
/**
* Replay the operations between the current HEAD_BRANCH and the end of the tree
*/
private fastForward;
}
type ClientId = string;
interface Client {
id: ClientId;
name: string;
position?: ClientPosition;
}
interface ClientPosition {
sheetId: UID;
col: HeaderIndex;
row: HeaderIndex;
}
interface RemoteRevisionReceivedEvent {
type: "remote-revision-received";
commands: readonly CoreCommand[];
}
interface RevisionAcknowledgedEvent {
type: "revision-acknowledged";
revisionId: UID;
}
interface RevisionUndone {
type: "revision-undone";
revisionId: UID;
commands: readonly CoreCommand[];
}
interface RevisionRedone {
type: "revision-redone";
revisionId: UID;
commands: readonly CoreCommand[];
}
interface CollaborativeEventReceived {
type: "collaborative-event-received";
}
interface UnexpectedRevisionIdEvent {
type: "unexpected-revision-id";
}
interface NewLocalStateUpdateEvent {
type: "new-local-state-update";
id: UID;
}
interface SnapshotEvent {
type: "snapshot";
}
type CollaborativeEvent = NewLocalStateUpdateEvent | UnexpectedRevisionIdEvent | RemoteRevisionReceivedEvent | RevisionAcknowledgedEvent | RevisionUndone | RevisionRedone | SnapshotEvent | CollaborativeEventReceived;
type CollaborativeEventTypes = CollaborativeEvent["type"];
interface RangePart {
readonly colFixed: boolean;
readonly rowFixed: boolean;
}
interface Range extends Cloneable<Range> {
readonly zone: Readonly<Zone>;
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;
readonly rangeData: RangeData;
}
interface RangeData {
_zone: Zone | UnboundedZone;
_sheetId: UID;
}
/**
* 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 TextRule extends SingleColorRule {
text: string;
}
interface CellIsRule extends SingleColorRule {
type: "CellIsRule";
operator: ConditionalFormattingOperatorValues;
values: string[];
}
interface ExpressionRule extends SingleColorRule {
type: "ExpressionRule";
}
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;
}
interface ContainsTextRule extends TextRule {
type: "ContainsTextRule";
}
interface NotContainsTextRule extends TextRule {
type: "NotContainsTextRule";
}
interface BeginsWithRule extends TextRule {
type: "BeginsWithRule";
}
interface EndsWithRule extends TextRule {
type: "EndsWithRule";
}
interface containsBlanksRule extends TextRule {
type: "containsBlanksRule";
}
interface notContainsBlanksRule extends TextRule {
type: "notContainsBlanksRule";
}
interface containsErrorsRule extends SingleColorRule {
type: "containsErrorsRule";
}
interface notContainsErrorsRule extends SingleColorRule {
type: "notContainsErrorsRule";
}
interface TimePeriodRule extends SingleColorRule {
type: "TimePeriodRule";
timePeriod: string;
}
interface AboveAverageRule extends SingleColorRule {
type: "AboveAverageRule";
aboveAverage: boolean;
equalAverage: boolean;
}
interface Top10Rule extends SingleColorRule {
type: "Top10Rule";
percent: boolean;
bottom: boolean;
rank: number;
}
type ConditionalFormattingOperatorValues = "BeginsWith" | "Between" | "ContainsText" | "IsEmpty" | "IsNotEmpty" | "EndsWith" | "Equal" | "GreaterThan" | "GreaterThanOrEqual" | "LessThan" | "LessThanOrEqual" | "NotBetween" | "NotContains" | "NotEqual";
declare const PREVIOUS_VALUE = "(previous)";
declare const NEXT_VALUE = "(next)";
type Aggregator = "array_agg" | "count" | "count_distinct" | "bool_and" | "bool_or" | "max" | "min" | "avg" | "sum";
type Granularity = "day" | "week" | "month" | "quarter" | "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;
}
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;
}
interface PivotSortedColumn {
order: SortDirection;
domain: PivotDomain;
measure: string;
}
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;
}
type PivotFields = Record<TechnicalName, PivotField | undefined>;
interface PivotMeasure extends PivotCoreMeasure {
displayName: string;
type: string;
isValid: boolean;
}
interface PivotDimension$1 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;
}
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 PivotTimeAdapterNotNull<T> {
normalizeFunctionValue: (value: Exclude<CellValue, null>) => T;
toValueAndFormat: (normalizedValue: T, locale?: Locale) => FunctionResultObject;
toFunctionValue: (normalizedValue: T) => string;
}
interface PivotTimeAdapter<T> {
normalizeFunctionValue: (value: CellValue) => T | null;
toValueAndFormat: (normalizedValue: T, locale?: Locale) => FunctionResultObject;
toFunctionValue: (normalizedValue: T) => string;
}
interface PivotNode {
field: string;
type: string;
value: CellValue;
}
type PivotDomain = PivotNode[];
/** Pivot domain splitted for the domain related to the pivot's rows and columns */
interface PivotColRowDomain {
colDomain: PivotDomain;
rowDomain: PivotDomain;
}
interface PivotMeasureDisplay {
type: PivotMeasureDisplayType;
fieldNameWithGranularity?: string;
value?: string | boolean | number | typeof PREVIOUS_VALUE | typeof NEXT_VALUE;
}
type PivotMeasureDisplayType = "no_calculations" | "%_of_grand_total" | "%_of_col_total" | "%_of_row_total" | "%_of_parent_row_total" | "%_of_parent_col_total" | "index" | "%_of_parent_total" | "running_total" | "%_running_total" | "rank_asc" | "rank_desc" | "%_of" | "difference_from" | "%_difference_from";
interface DimensionTreeNode {
value: CellValue;
field: string;
type: string;
children: DimensionTree;
width: number;
}
type DimensionTree = DimensionTreeNode[];
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 ComputedTableStyle {
borders: Border$1[][];
styles: Style[][];
}
interface TableElementStyle {
border?: TableBorder;
style?: Style;
size?: number;
}
interface TableBorder extends Border$1 {
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";
interface Dependencies {
references: string[];
numbers: number[];
strings: string[];
}
interface HeaderData {
size?: number;
isHidden?: boolean;
}
interface FigureData<T> {
id: UID;
x: Pixel;
y: Pixel;
width: Pixel;
height: Pixel;
tag: string;
data: T;
}
interface SheetData {
id: string;
name: string;
colNumber: number;
rowNumber: number;
cells: {
[key: string]: string | undefined;
};
styles: {
[zone: string]: number;
};
formats: {
[zone: string]: number;
};
borders: {
[zone: string]: number;
};
merges: string[];
figures: FigureData<any>[];
cols: {
[key: number]: HeaderData;
};
rows: {
[key: number]: HeaderData;
};
conditionalFormats: ConditionalFormat[];
dataValidationRules: DataValidationRuleData[];
tables: TableData[];
areGridLinesVisible?: boolean;
isVisible: boolean;
panes?: PaneDivision;
headerGroups?: Record<Dimension, HeaderGroup[]>;
color?: Color;
}
interface WorkbookSettings {
locale: Locale;
}
type PivotData = {
formulaId: string;
} & PivotCoreDefinition;
interface WorkbookData {
version: number;
sheets: SheetData[];
styles: {
[key: number]: Style;
};
formats: {
[key: number]: Format;
};
borders: {
[key: number]: Border$1;
};
pivots: {
[key: string]: PivotData;
};
pivotNextId: number;
revisionId: UID;
uniqueFigureIds: boolean;
settings: WorkbookSettings;
customTableStyles: {
[key: string]: TableStyleData;
};
}
interface ExcelWorkbookData extends WorkbookData {
sheets: ExcelSheetData[];
}
interface ExcelSheetData extends Omit<SheetData, "figureTables" | "cols" | "rows"> {
cellValues: {
[xc: string]: CellValue | undefined;
};
formulaSpillRanges: {
[xc: string]: string;
};
charts: FigureData<ExcelChartDefinition>[];
images: FigureData<Image$1>[];
tables: ExcelTableData[];
cols: {
[key: number]: ExcelHeaderData;
};
rows: {
[key: number]: ExcelHeaderData;
};
}
interface ExcelHeaderData extends HeaderData {
outlineLevel?: number;
collapsed?: boolean;
}
interface TableData {
range: string;
config?: TableConfig;
type?: CoreTableType;
}
interface DataValidationRuleData extends Omit<DataValidationRule, "ranges"> {
ranges: string[];
}
interface ExcelTableData {
range: string;
filters: ExcelFilterData[];
config: TableConfig;
}
interface ExcelFilterData {
colId: number;
displayedValues: string[];
displayBlanks?: boolean;
}
interface TableStyleData {
templateName: TableStyleTemplateName;
primaryColor: string;
displayName: string;
}
interface AbstractMessage {
version: number;
}
interface RemoteRevisionMessage extends AbstractMessage {
type: "REMOTE_REVISION";
clientId: ClientId;
commands: readonly CoreCommand[];
nextRevisionId: UID;
serverRevisionId: UID;
timestamp?: number;
}
interface RevisionUndoneMessage extends AbstractMessage {
type: "REVISION_UNDONE";
undoneRevisionId: UID;
nextRevisionId: UID;
serverRevisionId: UID;
}
interface RevisionRedoneMessage extends AbstractMessage {
type: "REVISION_REDONE";
redoneRevisionId: UID;
nextRevisionId: UID;
serverRevisionId: UID;
}
interface ClientJoinedMessage extends AbstractMessage {
type: "CLIENT_JOINED";
client: Required<Client>;
}
interface ClientLeftMessage extends AbstractMessage {
type: "CLIENT_LEFT";
clientId: ClientId;
}
interface ClientMovedMessage extends AbstractMessage {
type: "CLIENT_MOVED";
client: Required<Client>;
}
/**
* Send a snapshot of the spreadsheet to the collaborative server
*/
interface SnapshotMessage extends AbstractMessage {
type: "SNAPSHOT";
data: WorkbookData;
serverRevisionId: UID;
nextRevisionId: UID;
}
/**
* Notify all clients that the server has a new snapshot of the
* spreadsheet and that the previous history may be lost.
*/
interface SnapshotCreatedMessage extends AbstractMessage {
type: "SNAPSHOT_CREATED";
serverRevisionId: UID;
nextRevisionId: UID;
}
type CollaborationMessage = RevisionUndoneMessage | RevisionRedoneMessage | RemoteRevisionMessage | SnapshotMessage | SnapshotCreatedMessage | ClientMovedMessage | ClientJoinedMessage | ClientLeftMessage;
type StateUpdateMessage = Extract<CollaborationMessage, {
nextRevisionId: UID;
}>;
type NewMessageCallback<T = any> = (message: T) => void;
/**
* The transport service allows to communicate between multiple clients.
* A client can send any message to others.
* The service will handle all networking details internally.
*/
interface TransportService<T = any> {
/**
* Send a message to all clients
*/
sendMessage: (message: T) => Promise<void>;
/**
* Register a callback function which will be called each time
* a new message is received.
* The new message is given to the callback.
*
* ```js
* transportService.onNewMessage(id, (message) => {
* // ... handle the new message
* })
* ```
* The `id` is used to unregister this callback when the session is closed.
*/
onNewMessage: (id: UID, callback: NewMessageCallback<T>) => void;
/**
* Unregister a callback linked to the given id
*/
leave: (id: UID) => void;
}
declare class Revision implements RevisionData {
readonly rootCommand?: Command | undefined;
readonly timestamp?: number | undefined;
readonly id: UID;
readonly clientId: ClientId;
private _commands;
private _changes;
/**
* A revision represents a whole client action (Create a sheet, merge a Zone, Undo, ...).
* A revision contains the following information:
* - id: ID of the revision
* - commands: CoreCommands that are linked to the action, and should be
* dispatched in other clients
* - clientId: Client who initiated the action
* - changes: List of changes applied on the state.
*/
constructor(id: UID, clientId: ClientId, commands: readonly CoreCommand[], rootCommand?: Command | undefined, changes?: readonly HistoryChange[], timestamp?: number | undefined);
setChanges(changes: readonly HistoryChange[]): void;
get commands(): readonly CoreCommand[];
get changes(): readonly HistoryChange[];
}
declare class Session extends EventBus<CollaborativeEvent> {
private revisions;
private transportService;
private serverRevisionId;
/**
* Positions of the others client.
*/
private clients;
private clientId;
/**
* Id of the server revision
*/
private debouncedMove;
private pendingMessages;
private waitingAck;
/**
* Flag used to block all commands when an undo or redo is triggered, until
* it is accepted on the server
*/
private waitingUndoRedoAck;
private isReplayingInitialRevisions;
private processedRevisions;
private lastRevisionMessage;
private uuidGenerator;
private lastLocalOperation;
/**
* Manages the collaboration between multiple users on the same spreadsheet.
* It can forward local state changes to other users to ensure they all eventually
* reach the same state.
* It also manages the positions of each clients in the spreadsheet to provide
* a visual indication of what other users are doing in the spreadsheet.
*
* @param revisions
* @param transportService communication channel used to send and receive messages
* between all connected clients
* @param client the client connected locally
* @param serverRevisionId
*/
constructor(revisions: SelectiveHistory<Revision>, transportService: TransportService<CollaborationMessage>, serverRevisionId?: UID);
canApplyOptimisticUpdate(): boolean;
/**
* Add a new revision to the collaborative session.
* It will be transmitted to all other connected clients.
*/
save(rootCommand: Command, commands: CoreCommand[], changes: HistoryChange[]): void;
undo(revisionId: UID): void;
redo(revisionId: UID): void;
/**
* Notify that the position of the client has changed
*/
move(position: ClientPosition): void;
join(client?: Client): void;
loadInitialMessages(messages: StateUpdateMessage[]): void;
/**
* Notify the server that the user client left the collaborative session
*/
leave(data?: Lazy<WorkbookData>): Promise<void>;
/**
* Send a snapshot of the spreadsheet to the collaboration server
*/
snapshot(data: WorkbookData): Promise<void>;
getClient(): Client;
getConnectedClients(): Set<Client>;
getRevisionId(): UID;
isFullySynchronized(): boolean;
/**
* Get the last local revision
* */
getLastLocalNonEmptyRevision(): Revision | undefined;
private _move;
/**
* Handles messages received from other clients in the collaborative
* session.
*/
private onMessageReceived;
private onClientMoved;
/**
* Register the new client and send your
* own position back.
*/
private onClientJoined;
private onClientLeft;
private sendUpdateMessage;
/**
* Send the next pending message
*/
private sendPendingMessage;
private acknowledge;
private isAlreadyProcessed;
isWrongServerRevisionId(message: CollaborationMessage): boolean;
private dropPendingHistoryMessages;
}
/**
* RGBA to HEX representation (#RRGGBBAA).
*
* https://css-tricks.com/converting-color-spaces-in-javascript/
*/
declare function rgbaToHex(rgba: RGBA): Color;
/**
* Color string to RGBA representation
*/
declare function colorToRGBA(color: Color): RGBA;
declare class ColorGenerator {
private preferredColors;
private currentColorIndex;
protected palette: Color[];
constructor(paletteSize: number, preferredColors?: (string | undefined)[]);
next(): string;
}
/**
* Convert a (col) number to the corresponding letter.
*
* Examples:
* 0 => 'A'
* 25 => 'Z'
* 26 => 'AA'
* 27 => 'AB'
*/
declare function numberToLetters(n: number): string;
declare function lettersToNumber(letters: string): number;
/**
* Convert a "XC" coordinate to cartesian coordinates.
*
* Examples:
* A1 => [0,0]
* B3 => [1,2]
*
* Note: it also accepts lowercase coordinates, but not fixed references
*/
declare function toCartesian(xc: string): Position$1;
/**
* Convert from cartesian coordinate to the "XC" coordinate system.
*
* Examples:
* - 0,0 => A1
* - 1,2 => B3
* - 0,0, {colFixed: false, rowFixed: true} => A$1
* - 1,2, {colFixed: true, rowFixed: false} => $B3
*/
declare function toXC(col: HeaderIndex, row: HeaderIndex, rangePart?: RangePart): string;
/**
* A DateTime object that can be used to manipulate spreadsheet dates.
* Conceptually, a spreadsheet date is simply a number with a date format,
* and it is timezone-agnostic.
* This DateTime object consistently uses UTC time to represent a naive date and time.
*/
declare class DateTime {
private jsDate;
constructor(year: number, month: number, day: number, hours?: number, minutes?: number, seconds?: number);
static fromTimestamp(timestamp: number): DateTime;
static now(): DateTime;
toString(): string;
toLocaleDateString(): string;
getTime(): number;
getFullYear(): number;
getMonth(): number;
getQuarter(): number;
getDate(): number;
getDay(): number;
getHours(): number;
getMinutes(): number;
getSeconds(): number;
getIsoWeek(): number;
setFullYear(year: number): number;
setMonth(month: number): number;
setDate(date: number): number;
setHours(hours: number): number;
setMinutes(minutes: number): number;
setSeconds(seconds: number): number;
}
declare function isDateTime(str: string, locale: Locale): boolean;
interface FormatWidth {
availableWidth: number;
measureText: (text: string) => number;
}
/**
* Formats a cell value with its format.
*/
declare function formatValue(value: CellValue, { format, locale, formatWidth }: LocaleFormat & {
formatWidth?: FormatWidth;
}): FormattedValue;
declare function createCurrencyFormat(currency: Partial<Currency>): Format;
interface SearchOptions {
matchCase: boolean;
exactMatch: boolean;
searchFormulas: boolean;
searchScope: "allSheets" | "activeSheet" | "specificRange";
specificRange?: Range;
}
/**
* Deep copy arrays, plain objects and primitive values.
* Throws an error for other types such as class instances.
* Sparse arrays remain sparse.
*/
declare function deepCopy<T>(obj: T): T;
declare function unquote(string: string, quoteChar?: "'" | '"'): string;
/** Replace the excel-excluded characters of a sheetName */
declare function sanitizeSheetName(sheetName: string, replacementChar?: string): string;
declare function isMarkdownLink(str: string): boolean;
/**
* Build a markdown link from a label and an url
*/
declare function markdownLink(label: string, url: string): string;
declare function parseMarkdownLink(str: string): {
url: string;
label: string;
};
/**
* This helper function can be used as a type guard when filtering arrays.
* const foo: number[] = [1, 2, undefined, 4].filter(isDefined)
*/
declare function isDefined<T>(argument: T | undefined): argument is T;
/**
* Lazy value computed by the provided function.
*/
declare function lazy<T>(fn: (() => T) | T): Lazy<T>;
/**
* Compares two objects.
*/
declare function deepEquals(o1: any, o2: any): boolean;
declare function getUniqueText(text: string, texts: string[], options?: {
compute?: (text: string, increment: number) => string;
start?: number;
computeFirstOne?: boolean;
}): string;
/**
* Return true if the argument is a "number string".
*
* Note that "" (empty string) does not count as a number string
*/
declare function isNumber(value: string | undefined, locale: Locale): boolean;
interface ConstructorArgs {
readonly zone: Readonly<Zone | 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;
}
declare class RangeImpl implements Range {
private getSheetSize;
private readonly _zone;
readonly parts: Range["parts"];
readonly invalidXc?: string;
readonly prefixSheet: boolean;
readonly sheetId: UID;
readonly invalidSheetName?: string;
constructor(args: ConstructorArgs, getSheetSize: (sheetId: UID) => ZoneDimension);
static fromRange(range: Range, getters: CoreGetters): RangeImpl;
get unboundedZone(): UnboundedZone;
get zone(): Readonly<Zone>;
static getRangeParts(xc: string, zone: UnboundedZone): RangePart[];
get isFullCol(): boolean;
get isFullRow(): boolean;
get rangeData(): RangeData;
/**
* Check that a zone is valid regarding the order of top-bottom and left-right.
* Left should be smaller than right, top should be smaller than bottom.
* If it's not the case, simply invert them, and invert the linked parts
*/
orderZone(): RangeImpl;
/**
*
* @param rangeParams optional, values to put in the cloned range instead of the current values of the range
*/
clone(rangeParams?: Partial<ConstructorArgs>): RangeImpl;
}
declare function splitReference(ref: string): {
sheetName?: string;
xc: string;
};
declare function computeTextWidth(context: CanvasRenderingContext2D, text: string, style: Style, fontUnit?: "px" | "pt"): number;
declare class UuidGenerator {
/**
* Generates a custom UUID using a simple 36^12 method (8-character alphanumeric string with lowercase letters)
* This has a higher chance of collision than a UUIDv4, but not only faster to generate than an UUIDV4,
* it also has a smaller size, which is preferable to alleviate the overall data size.
*
* This method is preferable when generating uuids for the core data (sheetId, figureId, etc)
* as they will appear several times in the revisions and local history.
*
*/
smallUuid(): string;
/**
* Generates an UUIDV4, has astronomically low chance of collision, but is larger in size than the smallUuid.
* This method should be used when you need to avoid collisions at all costs, like the id of a revision.
*/
uuidv4(): string;
}
/**
* Convert from a cartesian reference to a (possibly unbounded) Zone
*
* Examples:
* "A1" ==> Top 0, Bottom 0, Left: 0, Right: 0
* "B1:B3" ==> Top 0, Bottom 3, Left: 1, Right: 1
* "B:B" ==> Top 0, Bottom undefined, Left: 1, Right: 1
* "B2:B" ==> Top 1, Bottom undefined, Left: 1, Right: 1, hasHeader: 1
* "Sheet1!A1" ==> Top 0, Bottom 0, Left: 0, Right: 0
* "Sheet1!B1:B3" ==> Top 0, Bottom 3, Left: 1, Right: 1
*
* @param xc the string reference to convert
*
*/
declare function toUnboundedZone(xc: string): UnboundedZone;
/**
* Convert from a cartesian reference to a Zone.
* Will return throw an error if given a unbounded zone (eg : A:A).
*
* Examples:
* "A1" ==> Top 0, Bottom 0, Left: 0, Right: 0
* "B1:B3" ==> Top 0, Bottom 2, Left: 1, Right: 1
* "Sheet1!A1" ==> Top 0, Bottom 0, Left: 0, Right: 0
* "Sheet1!B1:B3" ==> Top 0, Bottom 2, Left: 1, Right: 1
*
* @param xc the string reference to convert
*
*/
declare function toZone(xc: string): Zone;
/**
* Expand a zone after inserting columns or rows.
*
* Don't resize the zone if a col/row was added right before/after the row but only move the zone.
*/
declare function expandZoneOnInsertion<Z extends UnboundedZone | Zone>(zone: Z, start: "left" | "top", base: number, position: "after" | "before", quantity: number): Z;
/**
* Reduce a zone after deletion of elements
*/
declare function reduceZoneOnDeletion<Z extends UnboundedZone | Zone>(zone: Z, start: "left" | "top", elements: number[]): Z | undefined;
/**
* Compute the union of multiple zones.
*/
declare function union(...zones: Zone[]): Zone;
/**
* Return true if two zones overlap, false otherwise.
*/
declare function overlap(z1: Zone, z2: Zone): boolean;
declare function isInside(col: number, row: number, zone: Zone): boolean;
/**
* This function will compare the modifications of selection to determine
* a cell that is part of the new zone and not the previous one.
*/
declare function findCellInNewZone(oldZone: Zone, currentZone: Zone): Position$1;
declare function positionToZone(position: Position$1): Zone;
/**
* Merge contiguous and overlapping zones that are in the array into bigger zones
*/
declare function mergeContiguousZones(zones: Zone[]): Zone[];
type SelectionEventOptions = {
scrollIntoView?: boolean;
unbounded?: boolean;
};
interface SelectionEvent {
anchor: AnchorZone;
previousAnchor: AnchorZone;
mode: "newAnchor" | "overrideSelection" | "updateAnchor";
options: SelectionEventOptions;
}
interface StreamCallbacks<Event> {
handleEvent: (event: Event) => void;
/** this callback will only be called when another consumer captures the stream,
* not when the current consumer decides to release itself */
release?: () => void;
}
type StatefulStream<Event, State> = {
capture(owner: unknown, state: State, callbacks: StreamCallbacks<Event>): void;
registerAsDefault: (owner: unknown, state: State, callbacks: StreamCallbacks<Event>) => void;
resetDefaultAnchor: (owner: unknown, state: State) => void;
resetAnchor: (owner: unknown, state: State) => void;
observe: (owner: unknown, callbacks: StreamCallbacks<Event>) => void;
detachObserver: (owner: unknown) => void;
release: (owner: unknown) => void;
getBackToDefault(): void;
};
/**
* Allows to select cells in the grid and update the selection
*/
interface SelectionProcessor {
selectZone(anchor: AnchorZone, options?: SelectionEventOptions): DispatchResult;
selectCell(col: number, row: number): DispatchResult;
moveAnchorCell(direction: Direction$1, step: SelectionStep): DispatchResult;
setAnchorCorner(col: number, row: number): DispatchResult;
addCellToSelection(col: number, row: number): DispatchResult;
resizeAnchorZone(direction: Direction$1, step: SelectionStep): DispatchResult;
selectColumn(index: number, mode: SelectionEvent["mode"]): Dispat