@guiexpert/table 1.1.94 → 1.1.96
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/css/main.css +192 -0
- package/css/table-calc.css +7 -0
- package/css/table-color-vars.css +46 -0
- package/css/table-fill-batch.css +58 -0
- package/css/table-row-drag.css +81 -0
- package/index.cjs +39 -37
- package/index.d.ts +28 -0
- package/index.js +5501 -1934
- package/lib/table/action/action-id.type.d.ts +1 -1
- package/lib/table/aria/aria-texts.d.ts +11 -0
- package/lib/table/aria/aria-texts.if.d.ts +87 -0
- package/lib/table/batch-edit/batch-edit-options.d.ts +21 -0
- package/lib/table/batch-edit/batch-edit-options.if.d.ts +20 -0
- package/lib/table/batch-edit/batch-edit-service.d.ts +104 -0
- package/lib/table/batch-edit/cell-change.if.d.ts +39 -0
- package/lib/table/batch-edit/cell-value-change.if.d.ts +18 -0
- package/lib/table/batch-edit/pending-cell-changes.d.ts +104 -0
- package/lib/table/calc/column-values.d.ts +55 -0
- package/lib/table/calc/show-values-as-internals.d.ts +4 -0
- package/lib/table/calc/show-values-as.d.ts +87 -0
- package/lib/table/calc/show-values-as.type.d.ts +55 -0
- package/lib/table/calc/value-getter-context.if.d.ts +35 -0
- package/lib/table/calc/value-getter.type.d.ts +36 -0
- package/lib/table/data/common/event/ge-batch-edit-event.d.ts +46 -0
- package/lib/table/data/common/event/ge-model-change-event.d.ts +27 -1
- package/lib/table/data/common/event/ge-row-drag-event.d.ts +89 -0
- package/lib/table/data/options/table-options.d.ts +6 -0
- package/lib/table/data/options/table-options.if.d.ts +44 -0
- package/lib/table/data/tablemodel/areamodel/abstract-area-model.d.ts +66 -0
- package/lib/table/data/tablemodel/areamodel/area-model-aggregate-footer.d.ts +5 -0
- package/lib/table/data/tablemodel/areamodel/area-model-array-of-arrays.d.ts +24 -0
- package/lib/table/data/tablemodel/areamodel/area-model-object-array.d.ts +70 -0
- package/lib/table/data/tablemodel/areamodel/area-model-pivot.d.ts +31 -0
- package/lib/table/data/tablemodel/areamodel/area-model-row-groups.d.ts +23 -1
- package/lib/table/data/tablemodel/areamodel/area-model-tree.d.ts +83 -0
- package/lib/table/data/tablemodel/areamodel/area-model.if.d.ts +55 -0
- package/lib/table/data/tablemodel/column/column-def.d.ts +31 -1
- package/lib/table/data/tablemodel/column/column-def.if.d.ts +86 -0
- package/lib/table/event-adapter.d.ts +7 -0
- package/lib/table/event-listener.if.d.ts +32 -0
- package/lib/table/factory/table-factory.d.ts +11 -0
- package/lib/table/fill/compute-fill-changes.d.ts +67 -0
- package/lib/table/fill/fill-direction.type.d.ts +7 -0
- package/lib/table/fill/fill-handle-options.d.ts +29 -0
- package/lib/table/fill/fill-handle-options.if.d.ts +35 -0
- package/lib/table/fill/fill-handle-service.d.ts +55 -0
- package/lib/table/fill/fill-series.d.ts +60 -0
- package/lib/table/fill/fill-value-context.if.d.ts +36 -0
- package/lib/table/formula/compile-formula.d.ts +86 -0
- package/lib/table/formula/evaluator.d.ts +19 -0
- package/lib/table/formula/formula-ast.if.d.ts +42 -0
- package/lib/table/formula/formula-error.d.ts +59 -0
- package/lib/table/formula/formula-options.if.d.ts +41 -0
- package/lib/table/formula/formula-values.d.ts +13 -0
- package/lib/table/formula/functions.d.ts +18 -0
- package/lib/table/formula/parser.d.ts +10 -0
- package/lib/table/formula/tokenizer.d.ts +22 -0
- package/lib/table/pivot/pivot-value.type.d.ts +13 -0
- package/lib/table/render-scope.d.ts +81 -0
- package/lib/table/renderer/edit/input-cell-renderer.d.ts +1 -1
- package/lib/table/renderer/edit/select-cell-renderer.d.ts +1 -1
- package/lib/table/row-drag/move-rows.d.ts +157 -0
- package/lib/table/row-drag/row-drag-options.d.ts +28 -0
- package/lib/table/row-drag/row-drag-options.if.d.ts +36 -0
- package/lib/table/row-drag/row-drag-service.d.ts +130 -0
- package/lib/table/row-drag/row-drop-target.if.d.ts +29 -0
- package/lib/table/service/excel-service.d.ts +6 -0
- package/lib/table/service/excel-service.if.d.ts +35 -0
- package/lib/table/table-api.d.ts +277 -2
- package/lib/table/table-scope.d.ts +121 -0
- package/package.json +1 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How {@link computeFillValues} continues the source values:
|
|
3
|
+
* - `"auto"`: the default rules – one number is copied, several numbers continue as a linear series, dates and texts
|
|
4
|
+
* with a trailing number count up, everything else repeats;
|
|
5
|
+
* - `"alternate"`: the other choice for numbers, dates and texts with a number (⌥/Alt or Ctrl while dragging the fill
|
|
6
|
+
* handle): one number counts up by 1, a series is copied;
|
|
7
|
+
* - `"copy"`: always repeat the source values (Ctrl/⌘+D, Ctrl/⌘+R).
|
|
8
|
+
*
|
|
9
|
+
* @category Fill handle & batch edit
|
|
10
|
+
* @since 1.1.96
|
|
11
|
+
*/
|
|
12
|
+
export type FillMode = "auto" | "alternate" | "copy";
|
|
13
|
+
/**
|
|
14
|
+
* Computes the values of a fill (fill handle, Ctrl/⌘+D): `count` values that continue `sourceValues` – forward
|
|
15
|
+
* (down/right) or backward (up/left: the value directly in front of the source first).
|
|
16
|
+
*
|
|
17
|
+
* | source | `"auto"` | `"alternate"` |
|
|
18
|
+
* |---|---|---|
|
|
19
|
+
* | one number `5` | 5, 5, 5 | 6, 7, 8 |
|
|
20
|
+
* | numbers `1, 2` | 3, 4, 5 (linear; uneven steps: best-fit line) | 1, 2, 1 |
|
|
21
|
+
* | date `2026-10-14` (`Date` or ISO text) | +1 day each; several dates a month apart: +1 month (month ends stay month ends) | copied |
|
|
22
|
+
* | text with a trailing number `Item 9` | `Item 10`, `Item 11` (leading zeros stay) | copied |
|
|
23
|
+
* | anything else | repeated: `A, B` → `A, B, A, B` | repeated |
|
|
24
|
+
*
|
|
25
|
+
* The type stays: a date text stays a text in the same format, a `Date` stays a `Date`, a number written as text
|
|
26
|
+
* stays a text. Decimal noise is rounded (0.1, 0.2 → 0.3, not 0.30000000000000004).
|
|
27
|
+
*
|
|
28
|
+
* @param {unknown[]} sourceValues - the values of one line (column or row) of the source range, in display order
|
|
29
|
+
* @param {number} count - the number of values to compute
|
|
30
|
+
* @param {boolean} [backward=false] - fill up/left: the values in front of the source, nearest first
|
|
31
|
+
* @param {FillMode} [mode="auto"] - see {@link FillMode}
|
|
32
|
+
* @returns {unknown[]} `count` values, nearest to the source first
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* computeFillValues([1, 2], 3); // [3, 4, 5]
|
|
36
|
+
* computeFillValues([5], 3); // [5, 5, 5]
|
|
37
|
+
* computeFillValues([5], 3, false, "alternate"); // [6, 7, 8]
|
|
38
|
+
* computeFillValues(["2026-10-14"], 2); // ["2026-10-15", "2026-10-16"]
|
|
39
|
+
* computeFillValues(["Item 9"], 2); // ["Item 10", "Item 11"]
|
|
40
|
+
* computeFillValues([1, 2], 2, true); // [0, -1] (filled upwards)
|
|
41
|
+
*
|
|
42
|
+
* @category Fill handle & batch edit
|
|
43
|
+
* @since 1.1.96
|
|
44
|
+
*/
|
|
45
|
+
export declare function computeFillValues(sourceValues: unknown[], count: number, backward?: boolean, mode?: FillMode): unknown[];
|
|
46
|
+
/**
|
|
47
|
+
* `true` if {@link computeFillValues} continues the values as a series, `false` if it repeats them.
|
|
48
|
+
*
|
|
49
|
+
* @param {unknown[]} sourceValues - the values of one line of the source range
|
|
50
|
+
* @param {FillMode} [mode="auto"] - see {@link FillMode}
|
|
51
|
+
* @returns {boolean} whether the fill is a series
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* isFillSeries([5]); // false – one number is copied
|
|
55
|
+
* isFillSeries([1, 2]); // true
|
|
56
|
+
*
|
|
57
|
+
* @category Fill handle & batch edit
|
|
58
|
+
* @since 1.1.96
|
|
59
|
+
*/
|
|
60
|
+
export declare function isFillSeries(sourceValues: unknown[], mode?: FillMode): boolean;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { FillDirection } from './fill-direction.type.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What an own fill function ({@link FillHandleOptionsIf.fillValue}) gets for each filled cell.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const weekdays = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
|
8
|
+
* const fillValue = (ctx: FillValueContextIf) => {
|
|
9
|
+
* const last = ctx.sourceValues[ctx.sourceValues.length - 1];
|
|
10
|
+
* const i = weekdays.indexOf(String(last));
|
|
11
|
+
* return i < 0 || ctx.copy ? undefined : weekdays[(((i + ctx.step) % 7) + 7) % 7]; // undefined = default
|
|
12
|
+
* };
|
|
13
|
+
*
|
|
14
|
+
* @category Fill handle & batch edit
|
|
15
|
+
* @since 1.1.96
|
|
16
|
+
*/
|
|
17
|
+
export interface FillValueContextIf {
|
|
18
|
+
/** The values of the source line (the column when filling down/up, the row when filling right/left), as shown. */
|
|
19
|
+
sourceValues: unknown[];
|
|
20
|
+
/** 1, 2, 3 … after the source (down/right), −1, −2 … in front of it (up/left). */
|
|
21
|
+
step: number;
|
|
22
|
+
/** The direction of the fill. */
|
|
23
|
+
direction: FillDirection;
|
|
24
|
+
/** Display index of the filled cell's row. */
|
|
25
|
+
rowIndex: number;
|
|
26
|
+
/** Model index of the filled cell's column. */
|
|
27
|
+
columnIndex: number;
|
|
28
|
+
/** The property of the column (`""` without a column definition). */
|
|
29
|
+
property: string;
|
|
30
|
+
/** The row object of the filled cell (`undefined` for own area models without row objects). */
|
|
31
|
+
row: unknown;
|
|
32
|
+
/** The value the table would use (series or copy). */
|
|
33
|
+
defaultValue: unknown;
|
|
34
|
+
/** `true` if the values are copied (⌥/Alt on a series, Ctrl/⌘+D, Ctrl/⌘+R). */
|
|
35
|
+
copy: boolean;
|
|
36
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { FormulaNode } from './formula-ast.if.js';
|
|
2
|
+
import { FormulaError } from './formula-error.js';
|
|
3
|
+
import { FormulaOptionsIf, FormulaValue } from './formula-options.if.js';
|
|
4
|
+
import { ValueGetterContextIf } from '../calc/value-getter-context.if.js';
|
|
5
|
+
import { ValueGetter } from '../calc/value-getter.type.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The names of the built-in formula functions (upper case), e.g. for the help text of an own formula input.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* hint.textContent = `Functions: ${FORMULA_FUNCTION_NAMES.join(", ")}`;
|
|
12
|
+
*
|
|
13
|
+
* @since 1.1.95
|
|
14
|
+
* @category Calculated columns & formulas
|
|
15
|
+
*/
|
|
16
|
+
export declare const FORMULA_FUNCTION_NAMES: readonly string[];
|
|
17
|
+
/**
|
|
18
|
+
* A formula compiled once ({@link compileFormula}): the AST, the referenced fields and `evaluate()` for a row.
|
|
19
|
+
* A formula with a syntax error or an unknown function has `error` set; `evaluate()` then always returns it.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const f = compileFormula("[price] * [quantity] * 1.19");
|
|
23
|
+
* f.fields; // ["price", "quantity"]
|
|
24
|
+
* f.evaluate({ price: 1299, quantity: 2 }); // 3091.62
|
|
25
|
+
*
|
|
26
|
+
* @since 1.1.95
|
|
27
|
+
* @category Calculated columns & formulas
|
|
28
|
+
*/
|
|
29
|
+
export interface CompiledFormula {
|
|
30
|
+
/** The formula text as given. */
|
|
31
|
+
readonly source: string;
|
|
32
|
+
/** The syntax tree; `undefined` if the formula has an error. */
|
|
33
|
+
readonly ast?: FormulaNode;
|
|
34
|
+
/** The error of the formula itself (`#ERROR!`, `#NAME?` for an unknown function); `undefined` if it is valid. */
|
|
35
|
+
readonly error?: FormulaError;
|
|
36
|
+
/** The referenced fields (`[price]` → `"price"`), each once, in order of appearance. */
|
|
37
|
+
readonly fields: readonly string[];
|
|
38
|
+
/** True if the formula uses a column aggregate (`SUM([total])` …). */
|
|
39
|
+
readonly usesAggregates: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Evaluates the formula for a row. Never throws: errors are returned as {@link FormulaError}.
|
|
42
|
+
* Without a context, column aggregates (`SUM([x])`) return `#VALUE!`.
|
|
43
|
+
*/
|
|
44
|
+
evaluate(row: unknown, context?: ValueGetterContextIf): FormulaValue;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Compiles a formula once – no `eval`, no `new Function` (works with a strict Content-Security-Policy, user input
|
|
48
|
+
* cannot run code). The result evaluates rows; never throws.
|
|
49
|
+
*
|
|
50
|
+
* Syntax (details: instructions.md „Formulas“):
|
|
51
|
+
* - fields in brackets: `[price]`, `[address.city]`, `[Unit price]` – own properties of the row or calculated columns
|
|
52
|
+
* - numbers `12`, `1.5`, `1e3`, texts `"a"` / `'a'`, `TRUE`, `FALSE`
|
|
53
|
+
* - operators: `+ - * / ^` (power), `&` (text), `= <> < <= > >=`; `-2^2 = -4`
|
|
54
|
+
* - functions: `ROUND(x, 2)`, `IF(c, a, b)`, `IFERROR`, `AND`, `OR`, `NOT`, `ABS`, `MOD`, `SQRT`, `POWER`, `FLOOR`,
|
|
55
|
+
* `CEILING`, `CONCAT`, `LEN`, `UPPER`, `LOWER`, `TRIM`, `ISBLANK`; `SUM AVG MIN MAX COUNT` – with one field the
|
|
56
|
+
* aggregate of the column (`[total] / SUM([total])`), otherwise of the arguments
|
|
57
|
+
*
|
|
58
|
+
* @param {string} source - the formula, e.g. `"[price] * [quantity] * 1.19"` (a leading `=` is ignored)
|
|
59
|
+
* @param {FormulaOptionsIf} [options] - own functions
|
|
60
|
+
* @returns {CompiledFormula} the compiled formula
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* const gross = compileFormula("ROUND([price] * [quantity] * 1.19, 2)");
|
|
64
|
+
* gross.evaluate({ price: 25, quantity: 10 }); // 297.5
|
|
65
|
+
* compileFormula("[price] / 0").evaluate({ price: 1 }); // FormulaError #DIV/0!
|
|
66
|
+
* compileFormula("[price] *").error?.code; // "#ERROR!"
|
|
67
|
+
*
|
|
68
|
+
* @since 1.1.95
|
|
69
|
+
* @category Calculated columns & formulas
|
|
70
|
+
*/
|
|
71
|
+
export declare function compileFormula(source: string, options?: FormulaOptionsIf): CompiledFormula;
|
|
72
|
+
/**
|
|
73
|
+
* The {@link ValueGetter} of a formula – what `ColumnDef.create({ formula })` sets as `valueGetter`.
|
|
74
|
+
*
|
|
75
|
+
* @param {CompiledFormula | string} formula - a compiled formula or its text
|
|
76
|
+
* @param {FormulaOptionsIf} [options] - own functions (only with a text)
|
|
77
|
+
* @returns {ValueGetter} the getter
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* const column = ColumnDef.create({ property: "gross", headerLabel: "Gross" });
|
|
81
|
+
* column.valueGetter = createFormulaValueGetter("[net] * 1.19");
|
|
82
|
+
*
|
|
83
|
+
* @since 1.1.95
|
|
84
|
+
* @category Calculated columns & formulas
|
|
85
|
+
*/
|
|
86
|
+
export declare function createFormulaValueGetter(formula: CompiledFormula | string, options?: FormulaOptionsIf): ValueGetter;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FormulaNode } from './formula-ast.if.js';
|
|
2
|
+
import { FormulaFunction, FormulaValue } from './formula-options.if.js';
|
|
3
|
+
import { ValueGetterContextIf } from '../calc/value-getter-context.if.js';
|
|
4
|
+
|
|
5
|
+
type Evaluate = (row: unknown, context: ValueGetterContextIf | undefined) => FormulaValue;
|
|
6
|
+
/** Reads a field: own properties only (no prototype chain), path segments separated by ".". */
|
|
7
|
+
export declare function readField(row: unknown, name: string, context?: ValueGetterContextIf, path?: string[]): FormulaValue;
|
|
8
|
+
/** Compiles an AST into closures. Never throws at evaluation time (see {@link FormulaEvaluator.evaluate}). */
|
|
9
|
+
export declare class FormulaEvaluator {
|
|
10
|
+
private readonly functions;
|
|
11
|
+
constructor(functions: Map<string, FormulaFunction>);
|
|
12
|
+
/** The evaluation function of a (checked) AST. */
|
|
13
|
+
compile(node: FormulaNode): Evaluate;
|
|
14
|
+
/** Evaluates an AST once (compiles it each time – for single use). */
|
|
15
|
+
evaluate(node: FormulaNode, row: unknown, context?: ValueGetterContextIf): FormulaValue;
|
|
16
|
+
private node;
|
|
17
|
+
private call;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A node of a compiled formula (abstract syntax tree). Read-only; the evaluator walks it – no code is generated
|
|
3
|
+
* (no `eval`, no `new Function`).
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* const ast = compileFormula("[price] * 2").ast;
|
|
7
|
+
* // { kind: "binary", op: "*", left: { kind: "field", name: "price" }, right: { kind: "literal", value: 2 } }
|
|
8
|
+
*
|
|
9
|
+
* @since 1.1.95
|
|
10
|
+
* @category Calculated columns & formulas
|
|
11
|
+
*/
|
|
12
|
+
export type FormulaNode = {
|
|
13
|
+
readonly kind: "literal";
|
|
14
|
+
readonly value: number | string | boolean;
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: "field";
|
|
17
|
+
readonly name: string;
|
|
18
|
+
} | {
|
|
19
|
+
readonly kind: "unary";
|
|
20
|
+
readonly op: "-" | "+";
|
|
21
|
+
readonly operand: FormulaNode;
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: "binary";
|
|
24
|
+
readonly op: FormulaBinaryOperator;
|
|
25
|
+
readonly left: FormulaNode;
|
|
26
|
+
readonly right: FormulaNode;
|
|
27
|
+
} | {
|
|
28
|
+
readonly kind: "call";
|
|
29
|
+
readonly name: string;
|
|
30
|
+
readonly args: readonly FormulaNode[];
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* The binary operators of a formula: arithmetic (`+ - * / ^`), text concatenation (`&`) and comparisons
|
|
34
|
+
* (`=`/`==`, `<>`/`!=`, `<`, `<=`, `>`, `>=`; normalized to `=` and `<>`).
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* const op: FormulaBinaryOperator = "&"; // "Total: " & [total]
|
|
38
|
+
*
|
|
39
|
+
* @since 1.1.95
|
|
40
|
+
* @category Calculated columns & formulas
|
|
41
|
+
*/
|
|
42
|
+
export type FormulaBinaryOperator = "+" | "-" | "*" | "/" | "^" | "&" | "=" | "<>" | "<" | "<=" | ">" | ">=";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The error codes of a formula – like in a spreadsheet:
|
|
3
|
+
*
|
|
4
|
+
* | Code | Meaning |
|
|
5
|
+
* |---|---|
|
|
6
|
+
* | `#ERROR!` | syntax error (the whole column shows it) |
|
|
7
|
+
* | `#NAME?` | unknown field or function |
|
|
8
|
+
* | `#VALUE!` | wrong type, e.g. `"abc" * 2` |
|
|
9
|
+
* | `#DIV/0!` | division by zero |
|
|
10
|
+
* | `#NUM!` | the result is not a finite number (`SQRT(-1)`, overflow) |
|
|
11
|
+
* | `#CIRC!` | circular reference between calculated columns |
|
|
12
|
+
*
|
|
13
|
+
* @since 1.1.95
|
|
14
|
+
* @category Calculated columns & formulas
|
|
15
|
+
*/
|
|
16
|
+
export type FormulaErrorCode = "#ERROR!" | "#NAME?" | "#VALUE!" | "#DIV/0!" | "#NUM!" | "#CIRC!";
|
|
17
|
+
/**
|
|
18
|
+
* An error value of a formula. Formulas never throw: a cell shows the {@link FormulaErrorCode} (`toString()`), the
|
|
19
|
+
* table adds the CSS class `ge-table-cell-error` and shows the message as tooltip. Errors propagate through
|
|
20
|
+
* operators and functions (`[a] / 0 + 1` → `#DIV/0!`), `IFERROR(x, fallback)` catches them, aggregators skip them.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* const result = compileFormula("[price] / [quantity]").evaluate({ price: 10, quantity: 0 });
|
|
24
|
+
* if (isFormulaError(result)) {
|
|
25
|
+
* console.log(result.code, result.message); // "#DIV/0!" "Division by zero"
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* @since 1.1.95
|
|
29
|
+
* @category Calculated columns & formulas
|
|
30
|
+
*/
|
|
31
|
+
export declare class FormulaError {
|
|
32
|
+
readonly code: FormulaErrorCode;
|
|
33
|
+
readonly message: string;
|
|
34
|
+
readonly position?: number | undefined;
|
|
35
|
+
/** Marker (works across copies of the core): {@link isFormulaError}. */
|
|
36
|
+
readonly type = "FormulaError";
|
|
37
|
+
/**
|
|
38
|
+
* @param {FormulaErrorCode} code - the code shown in the cell
|
|
39
|
+
* @param {string} message - a short English explanation (tooltip); never contains HTML
|
|
40
|
+
* @param {number} [position] - for syntax errors: the position in the formula text (0-based)
|
|
41
|
+
*/
|
|
42
|
+
constructor(code: FormulaErrorCode, message: string, position?: number | undefined);
|
|
43
|
+
/** The code, e.g. `"#DIV/0!"` – what a cell shows. */
|
|
44
|
+
toString(): string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* True for an error value of a formula ({@link FormulaError}) – also for one created by another copy of the core.
|
|
48
|
+
*
|
|
49
|
+
* @param {unknown} value - any value
|
|
50
|
+
* @returns {boolean} whether it is a formula error
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* const value = tableApi.getRowValue(row, "margin");
|
|
54
|
+
* if (!isFormulaError(value)) console.log(value);
|
|
55
|
+
*
|
|
56
|
+
* @since 1.1.95
|
|
57
|
+
* @category Calculated columns & formulas
|
|
58
|
+
*/
|
|
59
|
+
export declare function isFormulaError(value: unknown): value is FormulaError;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { FormulaError } from './formula-error.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A value inside a formula: a number, a text, a boolean, blank (`null`) or an error.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const fn: FormulaFunction = (x: FormulaValue) => typeof x === "number" ? x * 1.19 : x;
|
|
8
|
+
*
|
|
9
|
+
* @since 1.1.95
|
|
10
|
+
* @category Calculated columns & formulas
|
|
11
|
+
*/
|
|
12
|
+
export type FormulaValue = number | string | boolean | null | FormulaError;
|
|
13
|
+
/**
|
|
14
|
+
* An own function for formulas. It gets the evaluated arguments (never an error – an error argument is returned
|
|
15
|
+
* without calling the function) and returns a number, text, boolean or `null`. Anything else, an exception or
|
|
16
|
+
* `NaN` becomes `#VALUE!` resp. `#NUM!`.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* const VAT: FormulaFunction = (net) => Number(net) * 0.19;
|
|
20
|
+
* compileFormula("VAT([price])", { functions: { VAT } });
|
|
21
|
+
*
|
|
22
|
+
* @since 1.1.95
|
|
23
|
+
* @category Calculated columns & formulas
|
|
24
|
+
*/
|
|
25
|
+
export type FormulaFunction = (...args: FormulaValue[]) => unknown;
|
|
26
|
+
/**
|
|
27
|
+
* Options of {@link compileFormula}.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* const options: FormulaOptionsIf = {
|
|
31
|
+
* functions: { NET: (gross) => Number(gross) / 1.19 }
|
|
32
|
+
* };
|
|
33
|
+
* ColumnDef.create({ property: "net", headerLabel: "Net", formula: "NET([gross])", formulaOptions: options });
|
|
34
|
+
*
|
|
35
|
+
* @since 1.1.95
|
|
36
|
+
* @category Calculated columns & formulas
|
|
37
|
+
*/
|
|
38
|
+
export interface FormulaOptionsIf {
|
|
39
|
+
/** Own functions by name (case-insensitive). They may replace built-in ones. */
|
|
40
|
+
functions?: Record<string, FormulaFunction>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { FormulaError } from './formula-error.js';
|
|
2
|
+
import { FormulaValue } from './formula-options.if.js';
|
|
3
|
+
|
|
4
|
+
export declare function isBlank(v: FormulaValue): boolean;
|
|
5
|
+
/** A value from the data (a field) as formula value: Date → ms, function/object → #VALUE!. */
|
|
6
|
+
export declare function fromData(v: unknown, name: string, trusted?: boolean): FormulaValue;
|
|
7
|
+
export declare function toNumber(v: FormulaValue): number | FormulaError;
|
|
8
|
+
export declare function toText(v: FormulaValue): string | FormulaError;
|
|
9
|
+
export declare function toBoolean(v: FormulaValue): boolean | FormulaError;
|
|
10
|
+
/** A number result: NaN / ±Infinity → #NUM!, -0 → 0. */
|
|
11
|
+
export declare function numberResult(n: number): number | FormulaError;
|
|
12
|
+
/** Compares two values: numbers numerically, texts case-insensitively, blank = 0 = "" = FALSE. */
|
|
13
|
+
export declare function compareValues(a: FormulaValue, b: FormulaValue): number | FormulaError;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { FormulaValue } from './formula-options.if.js';
|
|
2
|
+
|
|
3
|
+
/** A built-in function with eagerly evaluated arguments (errors are returned before the call). */
|
|
4
|
+
export interface BuiltInFunction {
|
|
5
|
+
readonly min: number;
|
|
6
|
+
readonly max: number;
|
|
7
|
+
readonly fn: (args: FormulaValue[]) => FormulaValue;
|
|
8
|
+
}
|
|
9
|
+
/** Functions with lazily evaluated arguments – handled by the evaluator itself. */
|
|
10
|
+
export declare const LAZY_FUNCTIONS: Record<string, {
|
|
11
|
+
min: number;
|
|
12
|
+
max: number;
|
|
13
|
+
}>;
|
|
14
|
+
/** SUM, AVG … with exactly one field reference: an aggregate over the (filtered) rows of the table. */
|
|
15
|
+
export declare const AGGREGATE_FUNCTIONS: Record<string, "sum" | "avg" | "min" | "max" | "count">;
|
|
16
|
+
/** Rounds half away from zero (like Excel) without binary artefacts: ROUND(1.005, 2) = 1.01. */
|
|
17
|
+
export declare function roundHalfAwayFromZero(x: number, digits: number): number;
|
|
18
|
+
export declare const BUILT_IN_FUNCTIONS: Record<string, BuiltInFunction>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FormulaNode } from './formula-ast.if.js';
|
|
2
|
+
|
|
3
|
+
/** The maximum length of a formula (characters). */
|
|
4
|
+
export declare const MAX_FORMULA_LENGTH = 10000;
|
|
5
|
+
/** The maximum nesting depth (parentheses, function calls, unary operators). */
|
|
6
|
+
export declare const MAX_FORMULA_DEPTH = 64;
|
|
7
|
+
/** The maximum number of binary operators (a long chain is a deep tree, too). */
|
|
8
|
+
export declare const MAX_FORMULA_OPERATORS = 1000;
|
|
9
|
+
/** Parses a formula into an AST. Throws a {@link FormulaSyntaxError}. */
|
|
10
|
+
export declare function parseFormula(source: string): FormulaNode;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { FormulaError } from './formula-error.js';
|
|
2
|
+
|
|
3
|
+
/** The kinds of tokens of a formula. */
|
|
4
|
+
export type FormulaTokenKind = "number" | "string" | "field" | "ident" | "op" | "(" | ")" | "," | "eof";
|
|
5
|
+
/** One token: kind, text (number/string already decoded) and position in the source. */
|
|
6
|
+
export interface FormulaToken {
|
|
7
|
+
readonly kind: FormulaTokenKind;
|
|
8
|
+
readonly text: string;
|
|
9
|
+
readonly value?: number;
|
|
10
|
+
readonly pos: number;
|
|
11
|
+
}
|
|
12
|
+
/** Thrown by tokenizer and parser, caught by `compileFormula` – never leaves the formula module. */
|
|
13
|
+
export declare class FormulaSyntaxError extends Error {
|
|
14
|
+
readonly pos: number;
|
|
15
|
+
constructor(message: string, pos: number);
|
|
16
|
+
toFormulaError(): FormulaError;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Splits a formula into tokens. Whitespace is ignored. Throws a {@link FormulaSyntaxError} for an unknown character,
|
|
20
|
+
* an unterminated string or field reference.
|
|
21
|
+
*/
|
|
22
|
+
export declare function tokenize(source: string): FormulaToken[];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ValueAccessor } from '../aggregation/value-accessor.type.js';
|
|
2
2
|
import { AggregatorRef } from '../aggregation/aggregator-name.type.js';
|
|
3
3
|
import { AggregatorIf } from '../aggregation/aggregator.if.js';
|
|
4
|
+
import { ShowValuesAsConfig, ShowValuesAsIf } from '../calc/show-values-as.type.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* One value of a pivot table in full form: where the value of a row comes from, how it is aggregated, and how its
|
|
@@ -32,6 +33,16 @@ export interface PivotValueIf<T = any> {
|
|
|
32
33
|
label?: string;
|
|
33
34
|
/** The text of a result in a cell. Default: numbers with at most two decimals (`"1,234.5"`). Excel gets the raw value. */
|
|
34
35
|
format?: (result: unknown) => string;
|
|
36
|
+
/**
|
|
37
|
+
* „Show values as“ (since 1.1.95): `"percentOfRowTotal"` (each pivot row = 100 %), `"percentOfColumnTotal"`,
|
|
38
|
+
* `"percentOfGrandTotal"` or `"percentOfParentTotal"` (share of the parent row group). The cells then hold the
|
|
39
|
+
* fraction (Excel: number with percent format), the text is a percentage; `format` is not used. Other modes of
|
|
40
|
+
* {@link ShowValuesAs} don't apply to a pivot (the value is shown).
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* values: [{ value: "umsatz", showValuesAs: "percentOfRowTotal" }]
|
|
44
|
+
*/
|
|
45
|
+
showValuesAs?: ShowValuesAsConfig;
|
|
35
46
|
}
|
|
36
47
|
/**
|
|
37
48
|
* A value of a pivot table: a property path or function (summed) or the full form {@link PivotValueIf}.
|
|
@@ -64,4 +75,6 @@ export interface PivotValueInfoIf {
|
|
|
64
75
|
readonly aggregator: AggregatorIf;
|
|
65
76
|
/** The format of a result, if one was given. */
|
|
66
77
|
readonly format?: (result: unknown) => string;
|
|
78
|
+
/** „Show values as“, if one was given (since 1.1.95). */
|
|
79
|
+
readonly showValuesAs?: ShowValuesAsIf;
|
|
67
80
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { RowDragService } from './row-drag/row-drag-service.js';
|
|
2
|
+
import { BatchEditService } from './batch-edit/batch-edit-service.js';
|
|
3
|
+
import { FillHandleService } from './fill/fill-handle-service.js';
|
|
1
4
|
import { TableOverlayChange } from './overlay/table-overlay.js';
|
|
2
5
|
import { EleScope } from './ele-scope.js';
|
|
3
6
|
import { TableModelIf } from './data/tablemodel/table-model.if.js';
|
|
@@ -85,7 +88,80 @@ export declare class RenderScope extends EleScope {
|
|
|
85
88
|
* first body row, see `TableScope`. `undefined`: the focus is in the body ({@link FocusModelIf}).
|
|
86
89
|
*/
|
|
87
90
|
protected headerFocus?: [number, number];
|
|
91
|
+
/**
|
|
92
|
+
* Row drag of this table (drag handles, pointer and keyboard drag) – created by {@link TableScope}.
|
|
93
|
+
* @since 1.1.95
|
|
94
|
+
*/
|
|
95
|
+
rowDragService?: RowDragService;
|
|
96
|
+
/**
|
|
97
|
+
* Batch edit of this table (pending values, shown in the cells) – created by {@link TableScope}.
|
|
98
|
+
* @since 1.1.96
|
|
99
|
+
*/
|
|
100
|
+
batchEditService?: BatchEditService;
|
|
101
|
+
/**
|
|
102
|
+
* Fill handle of this table – created by {@link TableScope}.
|
|
103
|
+
* @since 1.1.96
|
|
104
|
+
*/
|
|
105
|
+
fillHandleService?: FillHandleService;
|
|
88
106
|
constructor(hostElement: HTMLDivElement, tableModel: TableModelIf, dom: ConvenienceDomService, tableOptions: TableOptionsIf);
|
|
107
|
+
/**
|
|
108
|
+
* The DOM service of this table (all DOM access of the table goes through it).
|
|
109
|
+
*
|
|
110
|
+
* @returns {ConvenienceDomService} the service
|
|
111
|
+
* @since 1.1.95
|
|
112
|
+
*/
|
|
113
|
+
getDomService(): ConvenienceDomService;
|
|
114
|
+
/**
|
|
115
|
+
* The visible body in client (viewport) coordinates – including fixed west/east columns, without the scroll bar –
|
|
116
|
+
* and the content pixels scrolled out at its top. Row drag computes the row under the pointer with it.
|
|
117
|
+
*
|
|
118
|
+
* @returns {{ top: number, height: number, left: number, width: number, contentScrollTop: number }} the geometry
|
|
119
|
+
* @since 1.1.95
|
|
120
|
+
*/
|
|
121
|
+
getBodyViewport(): {
|
|
122
|
+
top: number;
|
|
123
|
+
height: number;
|
|
124
|
+
left: number;
|
|
125
|
+
width: number;
|
|
126
|
+
contentScrollTop: number;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* The rectangle of a body cell in host coordinates (relative to the padding box of the host) – computed from the
|
|
130
|
+
* row and column positions, also for cells that are not rendered – and the visible part of its area (`clip…`: the
|
|
131
|
+
* body between header and footer, horizontally the fixed west/east area or the scrollable center).
|
|
132
|
+
*
|
|
133
|
+
* @param {number} rowIndex - display index
|
|
134
|
+
* @param {number} columnIndex - model index
|
|
135
|
+
* @returns {{ left: number, top: number, width: number, height: number, clipLeft: number, clipRight: number, clipTop: number, clipBottom: number }} the geometry
|
|
136
|
+
* @since 1.1.96
|
|
137
|
+
*/
|
|
138
|
+
getBodyCellRectInHost(rowIndex: number, columnIndex: number): {
|
|
139
|
+
left: number;
|
|
140
|
+
top: number;
|
|
141
|
+
width: number;
|
|
142
|
+
height: number;
|
|
143
|
+
clipLeft: number;
|
|
144
|
+
clipRight: number;
|
|
145
|
+
clipTop: number;
|
|
146
|
+
clipBottom: number;
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* The body cell at a point in host coordinates, clamped to the body (a point above the body = row 0, right of the
|
|
150
|
+
* columns = the last column …) – computed, not read from the DOM.
|
|
151
|
+
*
|
|
152
|
+
* @param {number} x - x relative to the host's padding box
|
|
153
|
+
* @param {number} y - y relative to the host's padding box
|
|
154
|
+
* @returns {[number, number]} row and column index, `[-1, -1]` without rows or columns
|
|
155
|
+
* @since 1.1.96
|
|
156
|
+
*/
|
|
157
|
+
getBodyCellAtHostPoint(x: number, y: number): [number, number];
|
|
158
|
+
/**
|
|
159
|
+
* Scroll bar pixels per content pixel: 1, below 1 for a capped scroll height ({@link isScrollHeightCapped}).
|
|
160
|
+
*
|
|
161
|
+
* @returns {number} the factor for `scrollTop` changes
|
|
162
|
+
* @since 1.1.95
|
|
163
|
+
*/
|
|
164
|
+
getScrollerToContentRatioY(): number;
|
|
89
165
|
isEditing(): boolean;
|
|
90
166
|
/**
|
|
91
167
|
* Resets the editor renderer by clearing its values and state.
|
|
@@ -193,6 +269,11 @@ export declare class RenderScope extends EleScope {
|
|
|
193
269
|
* @returns {void}
|
|
194
270
|
*/
|
|
195
271
|
updateCells(events: TableCellUpdateEventIf[], repaintAll?: boolean): void;
|
|
272
|
+
/**
|
|
273
|
+
* After `updateCells()` without a repaint: draws the rendered cells of calculated and „Show values as“ columns of
|
|
274
|
+
* the body again (they depend on the changed cells, e.g. `total = price * quantity` or a share of the total).
|
|
275
|
+
*/
|
|
276
|
+
protected rerenderCalculatedCells(): void;
|
|
196
277
|
/**
|
|
197
278
|
* After `updateCells()` without a repaint: draws the rendered aggregate cells of the group rows of a row grouping
|
|
198
279
|
* again (they follow the changed rows; labels and counts don't change – a moved row repaints the whole table).
|
|
@@ -6,5 +6,5 @@ import { RendererCleanupFnType } from '../renderer-cleanup-fn.type.js';
|
|
|
6
6
|
|
|
7
7
|
/** @category Renderers & editing */
|
|
8
8
|
export declare class InputCellRenderer implements CellRendererIf {
|
|
9
|
-
render(cellDiv: HTMLDivElement, rowIndex: number, columnIndex: number, areaIdent: AreaIdent, areaModel: AreaModelIf,
|
|
9
|
+
render(cellDiv: HTMLDivElement, rowIndex: number, columnIndex: number, areaIdent: AreaIdent, areaModel: AreaModelIf, cellValue: any, domService: DomServiceIf): RendererCleanupFnType | undefined;
|
|
10
10
|
}
|
|
@@ -10,5 +10,5 @@ export declare class SelectCellRenderer implements CellRendererIf {
|
|
|
10
10
|
protected options: ValueLabelIf[];
|
|
11
11
|
constructor(options: ValueLabelIf[]);
|
|
12
12
|
static create(values: string[]): SelectCellRenderer;
|
|
13
|
-
render(cellDiv: HTMLDivElement, rowIndex: number, columnIndex: number, areaIdent: AreaIdent, areaModel: AreaModelIf,
|
|
13
|
+
render(cellDiv: HTMLDivElement, rowIndex: number, columnIndex: number, areaIdent: AreaIdent, areaModel: AreaModelIf, cellValue: any, domService: DomServiceIf): RendererCleanupFnType | undefined;
|
|
14
14
|
}
|