@guiexpert/table 1.1.93 → 1.1.94

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.
Files changed (68) hide show
  1. package/README.md +13 -0
  2. package/css/main.css +142 -0
  3. package/css/table-classes.css +34 -0
  4. package/css/table-color-vars.css +32 -0
  5. package/css/table-pivot.css +42 -0
  6. package/css/table-row-group.css +25 -0
  7. package/css/table-tree.css +9 -0
  8. package/index.cjs +44 -36
  9. package/index.d.ts +39 -0
  10. package/index.js +6247 -3509
  11. package/lib/table/aggregation/aggregate-internals.d.ts +30 -0
  12. package/lib/table/aggregation/aggregate-spec.if.d.ts +51 -0
  13. package/lib/table/aggregation/aggregate.d.ts +58 -0
  14. package/lib/table/aggregation/aggregator-name.type.d.ts +39 -0
  15. package/lib/table/aggregation/aggregator.if.d.ts +51 -0
  16. package/lib/table/aggregation/aggregators.d.ts +37 -0
  17. package/lib/table/aggregation/create-value-getter.d.ts +18 -0
  18. package/lib/table/aggregation/selection-aggregates.if.d.ts +35 -0
  19. package/lib/table/aggregation/value-accessor.type.d.ts +13 -0
  20. package/lib/table/data/common/row-number-column-def.d.ts +107 -0
  21. package/lib/table/data/common/row-number-columns.d.ts +17 -0
  22. package/lib/table/data/common/row-number-options.d.ts +19 -0
  23. package/lib/table/data/common/row-number-options.if.d.ts +44 -0
  24. package/lib/table/data/tablemodel/areamodel/aggregate-footer-options.if.d.ts +73 -0
  25. package/lib/table/data/tablemodel/areamodel/area-model-aggregate-footer.d.ts +145 -0
  26. package/lib/table/data/tablemodel/areamodel/area-model-cell-groups.d.ts +18 -1
  27. package/lib/table/data/tablemodel/areamodel/area-model-pivot-footer.d.ts +47 -0
  28. package/lib/table/data/tablemodel/areamodel/area-model-pivot.d.ts +250 -0
  29. package/lib/table/data/tablemodel/areamodel/area-model-row-groups.d.ts +314 -0
  30. package/lib/table/data/tablemodel/areamodel/area-model-tree.d.ts +14 -0
  31. package/lib/table/data/tablemodel/areamodel/area-model.if.d.ts +39 -0
  32. package/lib/table/data/tablemodel/areamodel/derived-values-change.if.d.ts +30 -0
  33. package/lib/table/factory/pivot-factory.d.ts +63 -0
  34. package/lib/table/factory/pivot-table-model-para.if.d.ts +44 -0
  35. package/lib/table/factory/row-group-factory.d.ts +70 -0
  36. package/lib/table/factory/row-group-table-model-para.if.d.ts +66 -0
  37. package/lib/table/factory/table-factory.d.ts +45 -1
  38. package/lib/table/instanceof-workaround.d.ts +143 -6
  39. package/lib/table/pivot/area-model-pivot-header.d.ts +9 -0
  40. package/lib/table/pivot/pivot-column-def.d.ts +28 -0
  41. package/lib/table/pivot/pivot-column-info.if.d.ts +25 -0
  42. package/lib/table/pivot/pivot-config.if.d.ts +58 -0
  43. package/lib/table/pivot/pivot-internals.d.ts +13 -0
  44. package/lib/table/pivot/pivot-layout.d.ts +40 -0
  45. package/lib/table/pivot/pivot-result.d.ts +157 -0
  46. package/lib/table/pivot/pivot-table-model.d.ts +86 -0
  47. package/lib/table/pivot/pivot-value.type.d.ts +67 -0
  48. package/lib/table/render-scope.d.ts +61 -4
  49. package/lib/table/renderer/aggregate-cell-renderer.d.ts +27 -0
  50. package/lib/table/renderer/row-number-cell-renderer.d.ts +27 -0
  51. package/lib/table/rowgroup/group-rows-internals.d.ts +14 -0
  52. package/lib/table/rowgroup/group-rows-options.if.d.ts +13 -0
  53. package/lib/table/rowgroup/group-rows.d.ts +48 -0
  54. package/lib/table/rowgroup/row-group-column-def.d.ts +26 -0
  55. package/lib/table/rowgroup/row-group-column-options.if.d.ts +27 -0
  56. package/lib/table/rowgroup/row-group-detail-row.d.ts +8 -0
  57. package/lib/table/rowgroup/row-group-field.type.d.ts +56 -0
  58. package/lib/table/rowgroup/row-group-internals.d.ts +31 -0
  59. package/lib/table/rowgroup/row-group-layout.d.ts +13 -0
  60. package/lib/table/rowgroup/row-group-model-options.if.d.ts +39 -0
  61. package/lib/table/rowgroup/row-group.d.ts +51 -0
  62. package/lib/table/rowgroup/row-group.if.d.ts +48 -0
  63. package/lib/table/selection/selection-aggregator.d.ts +37 -0
  64. package/lib/table/selection/selection-service.d.ts +7 -0
  65. package/lib/table/service/convenience-dom.service.d.ts +5 -0
  66. package/lib/table/table-api.d.ts +112 -1
  67. package/lib/table/table-scope.d.ts +19 -0
  68. package/package.json +3 -2
@@ -0,0 +1,30 @@
1
+ import { AggregatorIf } from './aggregator.if.js';
2
+ import { AggregateSpec } from './aggregate-spec.if.js';
3
+ import { ValueAccessor } from './value-accessor.type.js';
4
+
5
+ /**
6
+ * A spec of {@link AggregateSpecMap} resolved for a pass over rows.
7
+ */
8
+ export interface ResolvedAggregateSpec<T = any> {
9
+ key: string;
10
+ aggregator: AggregatorIf;
11
+ /** where the value comes from: the spec's `value`, otherwise the key as property path */
12
+ value: ValueAccessor<T>;
13
+ /** undefined for `count` (the value does not matter) */
14
+ getValue?: (row: T) => unknown;
15
+ format?: (result: unknown) => string;
16
+ }
17
+ /**
18
+ * Resolves one entry of an {@link AggregateSpecMap}: the aggregator object, the value getter (default: the key as
19
+ * property path) and the format.
20
+ */
21
+ export declare function resolveAggregateSpec<T>(key: string, spec: AggregateSpec<T>): ResolvedAggregateSpec<T>;
22
+ /**
23
+ * Runs resolved specs over the rows in one pass and returns the states (for `merge` by the caller) – the core of
24
+ * {@link aggregateColumns} and of {@link AreaModelAggregateFooter}.
25
+ */
26
+ export declare function aggregateStates<T>(rows: ArrayLike<T>, specs: ResolvedAggregateSpec<T>[]): unknown[];
27
+ /**
28
+ * Like {@link aggregateStates} for models without row objects: the getters get the row index 0 … rowCount-1.
29
+ */
30
+ export declare function aggregateIndexStates(rowCount: number, specs: Pick<ResolvedAggregateSpec<number>, 'aggregator' | 'getValue'>[]): unknown[];
@@ -0,0 +1,51 @@
1
+ import { AggregatorRef } from './aggregator-name.type.js';
2
+ import { ValueAccessor } from './value-accessor.type.js';
3
+
4
+ /**
5
+ * One aggregate in full form: which aggregator, which value, and (in a footer) how it is shown.
6
+ *
7
+ * @example
8
+ * const spec: AggregateSpecIf<Order> = {
9
+ * aggregator: "avg",
10
+ * value: "total", // default: the key of the spec
11
+ * format: v => `${(v as number).toFixed(2)} €` // footer text; Excel gets the number
12
+ * };
13
+ *
14
+ * @since 1.1.94
15
+ * @category Aggregation
16
+ */
17
+ export interface AggregateSpecIf<T = any> {
18
+ /** A built-in aggregator by name or an own one. */
19
+ aggregator: AggregatorRef;
20
+ /** The value of a row. Default: the key of the spec as property path. */
21
+ value?: ValueAccessor<T>;
22
+ /** The text in a footer cell. Default: numbers with at most two decimals (`"1,234.5"`), dates as date, `undefined` empty. */
23
+ format?: (result: unknown) => string;
24
+ }
25
+ /**
26
+ * An aggregate in short form (`"sum"`, an own aggregator) or in full form ({@link AggregateSpecIf}).
27
+ *
28
+ * @example
29
+ * const short: AggregateSpec<Order> = "sum";
30
+ * const full: AggregateSpec<Order> = { aggregator: "sum", value: o => o.quantity * o.price };
31
+ *
32
+ * @since 1.1.94
33
+ * @category Aggregation
34
+ */
35
+ export type AggregateSpec<T = any> = AggregatorRef | AggregateSpecIf<T>;
36
+ /**
37
+ * Several aggregates by key. In {@link aggregateColumns} the key names the result (and is the default property path);
38
+ * in a footer ({@link AreaModelAggregateFooter}) the key is the property of the column that shows the result.
39
+ *
40
+ * @example
41
+ * const specs: AggregateSpecMap<Order> = {
42
+ * quantity: "sum",
43
+ * total: "sum",
44
+ * customer: "countDistinct",
45
+ * avgTotal: { aggregator: "avg", value: "total" } // a key without a column: only in the results
46
+ * };
47
+ *
48
+ * @since 1.1.94
49
+ * @category Aggregation
50
+ */
51
+ export type AggregateSpecMap<T = any> = Record<string, AggregateSpec<T>>;
@@ -0,0 +1,58 @@
1
+ import { AggregatorRef } from './aggregator-name.type.js';
2
+ import { ValueAccessor } from './value-accessor.type.js';
3
+ import { AggregateSpecMap } from './aggregate-spec.if.js';
4
+
5
+ /**
6
+ * Aggregates one value of all rows.
7
+ *
8
+ * @param {ArrayLike<T>} rows - the rows (an array, also filtered or sorted ones)
9
+ * @param {ValueAccessor<T>} value - property path (`"total"`, `"address.zip"`) or function
10
+ * @param {AggregatorRef} aggregator - `"sum"`, `"count"`, `"avg"`, `"min"`, `"max"`, `"countDistinct"`, `"first"`,
11
+ * `"last"` or an own {@link AggregatorIf}
12
+ * @returns {unknown} the result (`sum` of no numbers is `0`, `avg`/`min`/`max` of no numbers `undefined`)
13
+ *
14
+ * @example
15
+ * aggregate(orders, "total", "sum"); // all orders
16
+ * aggregate(orders.filter(o => o.city === "Berlin"), "total", "avg");
17
+ * aggregate(orders, o => o.quantity * o.price, "max"); // a computed value
18
+ *
19
+ * @since 1.1.94
20
+ * @category Aggregation
21
+ */
22
+ export declare function aggregate<T = any>(rows: ArrayLike<T>, value: ValueAccessor<T>, aggregator: AggregatorRef): unknown;
23
+ /**
24
+ * Aggregates several values in **one** pass over the rows. The keys of `specs` name the results; a key is also the
25
+ * default property path.
26
+ *
27
+ * @param {ArrayLike<T>} rows - the rows
28
+ * @param {AggregateSpecMap<T>} specs - key → aggregator name, own aggregator or {@link AggregateSpecIf}
29
+ * @returns {Record<string, unknown>} key → result, in the order of `specs`
30
+ *
31
+ * @example
32
+ * const totals = aggregateColumns(orders, {
33
+ * quantity: "sum",
34
+ * total: "sum",
35
+ * customer: "countDistinct",
36
+ * avgTotal: { aggregator: "avg", value: "total" }
37
+ * });
38
+ * // { quantity: 549812, total: 27481033.5, customer: 412, avgTotal: 274.81 }
39
+ *
40
+ * @since 1.1.94
41
+ * @category Aggregation
42
+ */
43
+ export declare function aggregateColumns<T = any>(rows: ArrayLike<T>, specs: AggregateSpecMap<T>): Record<string, unknown>;
44
+ /**
45
+ * The default text of an aggregate (e.g. in a footer cell or a status bar): numbers with at most two decimals and
46
+ * thousands separators, dates as date (en-US), `null`/`undefined` empty, everything else as text.
47
+ *
48
+ * @param {unknown} value - an aggregation result
49
+ * @returns {string} the text
50
+ *
51
+ * @example
52
+ * formatAggregateValue(1234.5678); // "1,234.57"
53
+ * formatAggregateValue(undefined); // ""
54
+ *
55
+ * @since 1.1.94
56
+ * @category Aggregation
57
+ */
58
+ export declare function formatAggregateValue(value: unknown): string;
@@ -0,0 +1,39 @@
1
+ import { AggregatorIf } from './aggregator.if.js';
2
+
3
+ /**
4
+ * The names of the built-in aggregators ({@link Aggregators}).
5
+ *
6
+ * | name | result | uses |
7
+ * |---|---|---|
8
+ * | `sum` | sum, `0` for no numbers | numbers (`NaN` ignored) |
9
+ * | `count` | number of rows | every row – the value does not matter |
10
+ * | `avg` | sum / count of the numbers, `undefined` for none | numbers |
11
+ * | `min`, `max` | smallest / largest value, `undefined` for none | numbers and valid `Date`s |
12
+ * | `countDistinct` | number of different values | everything except `null`/`undefined`; dates by time |
13
+ * | `first`, `last` | value of the first / last row | every row, the value as it is |
14
+ *
15
+ * Text is never converted to a number (like Excel's SUM over a range): `"12"` does not count. Use an accessor such as
16
+ * `row => Number(row.amount)` for numbers stored as text.
17
+ *
18
+ * @example
19
+ * const name: AggregatorName = "avg";
20
+ * aggregate(orders, "total", name);
21
+ *
22
+ * @since 1.1.94
23
+ * @category Aggregation
24
+ */
25
+ export type AggregatorName = "sum" | "count" | "avg" | "min" | "max" | "countDistinct" | "first" | "last";
26
+ /**
27
+ * A built-in aggregator by name or an own {@link AggregatorIf}.
28
+ *
29
+ * @example
30
+ * const byName: AggregatorRef = "sum";
31
+ * const own: AggregatorRef = { name: "range", init: () => [Infinity, -Infinity],
32
+ * add: ([lo, hi]: number[], v: unknown) => typeof v === "number" ? [Math.min(lo, v), Math.max(hi, v)] : [lo, hi],
33
+ * merge: (a: number[], b: number[]) => [Math.min(a[0], b[0]), Math.max(a[1], b[1])],
34
+ * result: ([lo, hi]: number[]) => hi - lo };
35
+ *
36
+ * @since 1.1.94
37
+ * @category Aggregation
38
+ */
39
+ export type AggregatorRef = AggregatorName | AggregatorIf;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * An aggregation (sum, average, …) as four small functions over a **state**: `init` → `add` per value → `result`.
3
+ * `merge` combines two partial states – the result is the same as one pass over all values. That makes groups
4
+ * (row grouping, pivot) cheap: the state of a group is the merge of the states of its sub-groups, and an average of
5
+ * averages stays correct (`{ sum, count }` instead of a number).
6
+ *
7
+ * The built-in aggregators are in {@link Aggregators}; an own aggregator implements this interface and can be used
8
+ * everywhere a name like `"sum"` is accepted ({@link AggregatorRef}).
9
+ *
10
+ * `add(state, …)` and `merge(a, b)` may change `state` / `a` and return it (no allocation per row with millions of
11
+ * rows); `merge` never changes `b`, so a child state can be merged into several parents. Call `init()` for a fresh
12
+ * state, e.g. `merge(init(), child)` for a parent that must not change the child.
13
+ *
14
+ * @example
15
+ * // the product of all numbers
16
+ * const product: AggregatorIf<number, number> = {
17
+ * name: "product",
18
+ * init: () => 1,
19
+ * add: (state, value) => typeof value === "number" ? state * value : state,
20
+ * merge: (a, b) => a * b,
21
+ * result: state => state
22
+ * };
23
+ * aggregate([{ f: 2 }, { f: 3 }, { f: 7 }], "f", product); // 42
24
+ *
25
+ * @example
26
+ * // partial results: the average of two groups is the average of all rows
27
+ * const avg = Aggregators.avg;
28
+ * const north = [100, 50, 120].reduce((s, v) => avg.add(s, v), avg.init());
29
+ * const south = [80, 70, 30].reduce((s, v) => avg.add(s, v), avg.init());
30
+ * avg.result(avg.merge(north, south)); // 75 – not the mean of 90 and 60
31
+ *
32
+ * @typeParam S - the state
33
+ * @typeParam R - the result
34
+ * @since 1.1.94
35
+ * @category Aggregation
36
+ */
37
+ export interface AggregatorIf<S = any, R = unknown> {
38
+ /** The name, e.g. `"sum"` – the built-in ones use their {@link AggregatorName}. */
39
+ readonly name: string;
40
+ /** The state of the empty set. */
41
+ init(): S;
42
+ /** Takes one value into the state (values the aggregator can't use are ignored); returns the state. */
43
+ add(state: S, value: unknown): S;
44
+ /**
45
+ * Combines two partial states (`a` first, then `b` – matters for `first`/`last`); may change `a` and returns the
46
+ * combined state; never changes `b`.
47
+ */
48
+ merge(a: S, b: S): S;
49
+ /** The result of a state, e.g. `sum / count` for the average. */
50
+ result(state: S): R;
51
+ }
@@ -0,0 +1,37 @@
1
+ import { AggregatorIf } from './aggregator.if.js';
2
+ import { AggregatorName, AggregatorRef } from './aggregator-name.type.js';
3
+
4
+ /**
5
+ * The built-in aggregators by name ({@link AggregatorName}) – each one is an {@link AggregatorIf}, so `merge` combines
6
+ * partial results correctly (the average of groups is the average of all rows).
7
+ *
8
+ * - `sum` and `avg` sum with compensation (Neumaier): `0.1 + 0.2 + 0.3` is `0.6`, and splitting the data into groups
9
+ * does not change the result.
10
+ * - Numeric aggregators use numbers only (`NaN`, text, `null` … are ignored); `min`/`max` also valid `Date`s;
11
+ * `count` counts rows; `countDistinct` ignores `null`/`undefined`; `first`/`last` take the value as it is.
12
+ *
13
+ * @example
14
+ * const { sum } = Aggregators;
15
+ * let state = sum.init();
16
+ * for (const order of orders) state = sum.add(state, order.total);
17
+ * sum.result(state); // the same as aggregate(orders, "total", "sum")
18
+ *
19
+ * @since 1.1.94
20
+ * @category Aggregation
21
+ */
22
+ export declare const Aggregators: Readonly<Record<AggregatorName, AggregatorIf>>;
23
+ /**
24
+ * The aggregator for a name, or the given aggregator itself.
25
+ *
26
+ * @param {AggregatorRef} aggregator - a name like `"sum"` or an own {@link AggregatorIf}
27
+ * @returns {AggregatorIf} the aggregator
28
+ * @throws {Error} for an unknown name (the message lists the built-in names)
29
+ *
30
+ * @example
31
+ * getAggregator("avg").name; // "avg"
32
+ * getAggregator(Aggregators.max); // the same object
33
+ *
34
+ * @since 1.1.94
35
+ * @category Aggregation
36
+ */
37
+ export declare function getAggregator(aggregator: AggregatorRef): AggregatorIf;
@@ -0,0 +1,18 @@
1
+ import { ValueAccessor } from './value-accessor.type.js';
2
+
3
+ /**
4
+ * A function that reads a value from a row: a property path (`"address.city"`, missing parents → `undefined`) or the
5
+ * given function itself.
6
+ *
7
+ * @param {ValueAccessor<T>} value - property path or function
8
+ * @returns {(row: T) => unknown} the getter
9
+ *
10
+ * @example
11
+ * const city = createValueGetter<{ address?: { city: string } }>("address.city");
12
+ * city({ address: { city: "Kiel" } }); // "Kiel"
13
+ * city({}); // undefined
14
+ *
15
+ * @since 1.1.94
16
+ * @category Aggregation
17
+ */
18
+ export declare function createValueGetter<T = any>(value: ValueAccessor<T>): (row: T) => unknown;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Count, sum, average, minimum and maximum of the selected body cells – for a status bar like in a spreadsheet
3
+ * ({@link TableApi.getSelectionAggregates}).
4
+ *
5
+ * Counted are the selected cells of the visible data columns (row number and checkbox columns not); `numericCount`,
6
+ * `sum`, `avg`, `min`, `max` use the cells whose value is a number.
7
+ *
8
+ * @example
9
+ * const a: SelectionAggregatesIf = tableApi.getSelectionAggregates();
10
+ * const text = a.capped ? "selection too large"
11
+ * : a.numericCount ? `Count ${a.count} · Sum ${formatAggregateValue(a.sum)} · Avg ${formatAggregateValue(a.avg)}`
12
+ * : a.count ? `Count ${a.count}` : "";
13
+ *
14
+ * @since 1.1.94
15
+ * @category Aggregation
16
+ */
17
+ export interface SelectionAggregatesIf {
18
+ /** Number of selected cells. */
19
+ count: number;
20
+ /** Number of selected cells with a number. */
21
+ numericCount: number;
22
+ /** Sum of the numbers (`0` without numbers). */
23
+ sum: number;
24
+ /** Average of the numbers (`undefined` without numbers). */
25
+ avg: number | undefined;
26
+ /** Smallest number (`undefined` without numbers). */
27
+ min: number | undefined;
28
+ /** Largest number (`undefined` without numbers). */
29
+ max: number | undefined;
30
+ /**
31
+ * `true` if the selection covers more than {@link SelectionAggregator.maxCells} cells: then nothing is computed
32
+ * (all values 0 / `undefined`) – a partial sum would be wrong.
33
+ */
34
+ capped: boolean;
35
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Where an aggregation gets its value from a row: a property path (`"total"`, `"address.city"`) or a function
3
+ * (computed values, numbers stored as text, …).
4
+ *
5
+ * @example
6
+ * const byPath: ValueAccessor<Order> = "total";
7
+ * const computed: ValueAccessor<Order> = order => order.quantity * order.price;
8
+ *
9
+ * @typeParam T - the row type
10
+ * @since 1.1.94
11
+ * @category Aggregation
12
+ */
13
+ export type ValueAccessor<T = any> = string | ((row: T) => unknown);
@@ -0,0 +1,107 @@
1
+ import { SizeIf } from './size.if.js';
2
+ import { ColumnDefIf } from '../tablemodel/column/column-def.if.js';
3
+ import { CellRendererIf } from '../../renderer/cell-render.if.js';
4
+ import { AreaObjectMapType } from './area-map.type.js';
5
+ import { AreaModelIf } from '../tablemodel/areamodel/area-model.if.js';
6
+ import { BooleanFunction } from './boolean-function.js';
7
+ import { RowNumberOptionsIf } from './row-number-options.if.js';
8
+
9
+ /**
10
+ * A built-in column with running row numbers (1, 2, 3 …) like the row headers of a spreadsheet.
11
+ *
12
+ * The easy way is the factory flag: `TableFactory.createTableModel({ rows, rowNumbersVisible: true })` puts this column
13
+ * in front of the others and fixes it on the left. Put it into `columnDefs` yourself if you build the models yourself
14
+ * – as the **first** column, counted in `fixedLeftColumnCount`.
15
+ *
16
+ * What the table does with it:
17
+ * - the width follows the largest number (`"9"` → `"2000000"`) – after `setRows`, filtering, expanding tree rows;
18
+ * - not sortable, not editable, no resize handle, can't be dragged, no column can be dragged in front of it;
19
+ * - body cells have `role="rowheader"` – screen readers announce the number with the row;
20
+ * - a click on a number selects the row (selection type `"row"` and `"range"`), Shift extends, Ctrl/⌘ toggles;
21
+ * a click on the header cell selects all;
22
+ * - copy ({@link TableApi.copyToClipboard}) and Excel export ({@link TableApi.downloadExcel}) leave it out, unless
23
+ * `exported: true`;
24
+ * - with a {@link CheckboxColumnDef} directly behind it, the checkbox, the tree arrow and
25
+ * `showCheckboxWihoutExtraColumn` move one column to the right.
26
+ *
27
+ * Note: it is a real column – the indices of all other columns are one higher (like with a `CheckboxColumnDef`).
28
+ * Use properties where you can (`tableApi.setColumnVisible("total", false)`, {@link TableApi.getColumnIndex}).
29
+ *
30
+ * @example
31
+ * const withNumbers: ColumnDefIf[] = [new RowNumberColumnDef(), new CheckboxColumnDef(), ...columnDefs];
32
+ * const model = TableFactory.createTableModel({ rows: orders, columnDefs: withNumbers, fixedLeftColumnCount: 2 });
33
+ *
34
+ * @see Training: [Fixed columns](https://gui.expert/training/fixed-columns/)
35
+ *
36
+ * @since 1.1.93
37
+ * @category Row numbers
38
+ */
39
+ export declare class RowNumberColumnDef implements ColumnDefIf {
40
+ /** Marker for {@link isRowNumberColumnDef} (works across copies of the core). */
41
+ readonly type = "RowNumberColumnDef";
42
+ property: string;
43
+ headerLabel: string;
44
+ /** Starts with `minWidthInPx`; the table widens it to fit the largest number. */
45
+ width: SizeIf;
46
+ minWidth: SizeIf;
47
+ maxWidth: SizeIf;
48
+ rendererMap: AreaObjectMapType<CellRendererIf>;
49
+ classes: AreaObjectMapType<string[]>;
50
+ isVisible: BooleanFunction;
51
+ /** The options (defaults from {@link RowNumberOptions}). */
52
+ readonly options: RowNumberOptionsIf;
53
+ /**
54
+ * "original": position of each row in getAllRows() – built when needed, for one array with one length. Checked on
55
+ * every lookup (`rows[position] === row`): rows sorted or replaced in place rebuild it.
56
+ */
57
+ private originalIndex?;
58
+ constructor(options?: Partial<RowNumberOptionsIf>);
59
+ /**
60
+ * The number of a body row (1-based): its position in the view (`"display"`) or in `getAllRows()` (`"original"`).
61
+ *
62
+ * @param {number} rowIndex - row index in the body (the current view)
63
+ * @param {AreaModelIf} bodyModel - the body model
64
+ * @returns {number} the row number
65
+ *
66
+ * @example
67
+ * const columnDef = new RowNumberColumnDef();
68
+ * const rowNumber = columnDef.getRowNumber(0, tableModel.getBodyModel()); // 1
69
+ */
70
+ getRowNumber(rowIndex: number, bodyModel: AreaModelIf): number;
71
+ /**
72
+ * The text of a row number: `options.format(getRowNumber(…))`.
73
+ *
74
+ * @param {number} rowIndex - row index in the body
75
+ * @param {AreaModelIf} bodyModel - the body model
76
+ * @returns {string} the text shown in the cell (and exported with `exported: true`)
77
+ *
78
+ * @example
79
+ * const columnDef = new RowNumberColumnDef({ format: n => n.toLocaleString("en-US") });
80
+ * const text = columnDef.getRowNumberText(1999, tableModel.getBodyModel()); // "2,000"
81
+ */
82
+ getRowNumberText(rowIndex: number, bodyModel: AreaModelIf): string;
83
+ /**
84
+ * The text of the largest number the column can show now – the table measures it for the column width.
85
+ * `"display"`: the row count; `"original"`: the count of all rows (unfiltered). At least the text of 1.
86
+ *
87
+ * @param {AreaModelIf} bodyModel - the body model
88
+ * @returns {string} e.g. `"2000000"`
89
+ *
90
+ * @example
91
+ * const widest = new RowNumberColumnDef().getWidestText(tableModel.getBodyModel()); // "1000" for 1000 rows
92
+ */
93
+ getWidestText(bodyModel: AreaModelIf): string;
94
+ /**
95
+ * True if the numbers are shown without an own `format` (plain digits) – the Excel export then writes numbers.
96
+ *
97
+ * @returns {boolean} false with an own `options.format`
98
+ *
99
+ * @example
100
+ * const plain = new RowNumberColumnDef().hasDefaultFormat(); // true
101
+ */
102
+ hasDefaultFormat(): boolean;
103
+ private hasAllRows;
104
+ /** Position of a row in getAllRows() (0-based), undefined if the model has no getAllRows() or the row is not in it. */
105
+ private getOriginalPosition;
106
+ private buildOriginalIndex;
107
+ }
@@ -0,0 +1,17 @@
1
+ import { ColumnDefIf } from '../tablemodel/column/column-def.if.js';
2
+
3
+ /**
4
+ * 1 if the first column is a {@link RowNumberColumnDef}, otherwise 0 – the offset of the built-in columns that are
5
+ * bound to "the first column": the {@link CheckboxColumnDef}, the tree arrow and the checkbox of
6
+ * `showCheckboxWihoutExtraColumn` sit at this index (behind the row numbers).
7
+ *
8
+ * @param {ColumnDefIf[] | undefined} columnDefs - the column definitions of the table model
9
+ * @returns {0 | 1} the number of leading row number columns
10
+ *
11
+ * @example
12
+ * const firstDataColumn = getLeadingRowNumberColumnCount(tableModel.getColumnDefs());
13
+ *
14
+ * @since 1.1.93
15
+ * @category Row numbers
16
+ */
17
+ export declare function getLeadingRowNumberColumnCount(columnDefs: ColumnDefIf[] | undefined): 0 | 1;
@@ -0,0 +1,19 @@
1
+ import { RowNumberMode, RowNumberOptionsIf } from './row-number-options.if.js';
2
+
3
+ /**
4
+ * The default options of the row number column: numbers of the current view, no thousands separators, header `"#"`,
5
+ * not exported, at least 36 px wide.
6
+ *
7
+ * @example
8
+ * const columnDef = new RowNumberColumnDef({ ...new RowNumberOptions(), headerLabel: "" });
9
+ *
10
+ * @since 1.1.93
11
+ * @category Row numbers
12
+ */
13
+ export declare class RowNumberOptions implements RowNumberOptionsIf {
14
+ mode: RowNumberMode;
15
+ format: (rowNumber: number) => string;
16
+ headerLabel: string;
17
+ exported: boolean;
18
+ minWidthInPx: number;
19
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * How a {@link RowNumberColumnDef} counts:
3
+ * - `"display"` (default): the position in the current view – 1, 2, 3 … also after sorting and filtering
4
+ * (like the row headers of a spreadsheet).
5
+ * - `"original"`: the position in the unsorted, unfiltered rows (`getAllRows()` of the body model) – the number stays
6
+ * with its row. Body models without `getAllRows()` (tree, own area models) count like `"display"`.
7
+ *
8
+ * @since 1.1.93
9
+ * @category Row numbers
10
+ */
11
+ export type RowNumberMode = "display" | "original";
12
+ /**
13
+ * Options of the row number column ({@link RowNumberColumnDef}). Pass any subset – to
14
+ * `new RowNumberColumnDef({ … })` or as `rowNumbersVisible: { … }` to {@link TableFactory.createTableModel}.
15
+ * Defaults: {@link RowNumberOptions}.
16
+ *
17
+ * @example
18
+ * const tableModel = TableFactory.createTableModel({
19
+ * rows: orders,
20
+ * rowNumbersVisible: { mode: "original", format: n => n.toLocaleString("en-US"), exported: true }
21
+ * });
22
+ *
23
+ * @since 1.1.93
24
+ * @category Row numbers
25
+ */
26
+ export interface RowNumberOptionsIf {
27
+ /** `"display"` (default) or `"original"`, see {@link RowNumberMode}. */
28
+ mode: RowNumberMode;
29
+ /**
30
+ * The text of a number. Default `String(n)` – no thousands separators (`"2000000"`).
31
+ * The column width is measured with the text of the largest number, so the text should not get shorter for
32
+ * larger numbers.
33
+ *
34
+ * @example
35
+ * const options: Partial<RowNumberOptionsIf> = { format: n => n.toLocaleString("de-DE") }; // "2.000.000"
36
+ */
37
+ format: (rowNumber: number) => string;
38
+ /** Text of the header cell. Default `"#"` (an empty header cell has no accessible name). */
39
+ headerLabel: string;
40
+ /** `true`: {@link TableApi.copyToClipboard} and {@link TableApi.downloadExcel} contain the numbers. Default `false`. */
41
+ exported: boolean;
42
+ /** The column is never narrower than this (px). Default 36. */
43
+ minWidthInPx: number;
44
+ }
@@ -0,0 +1,73 @@
1
+ import { AggregateSpecMap } from '../../../aggregation/aggregate-spec.if.js';
2
+ import { AreaModelIf } from './area-model.if.js';
3
+
4
+ /**
5
+ * One total row of an {@link AreaModelAggregateFooter}: the aggregates by column property and an optional label.
6
+ *
7
+ * @example
8
+ * const sumRow: AggregateFooterRowIf<Order> = { label: "Sum", aggregates: { quantity: "sum", total: "sum" } };
9
+ * const avgRow: AggregateFooterRowIf<Order> = {
10
+ * label: (rowCount, results) => `Ø of ${rowCount} orders`,
11
+ * aggregates: { total: { aggregator: "avg", format: v => `${(v as number).toFixed(2)} €` } }
12
+ * };
13
+ *
14
+ * @since 1.1.94
15
+ * @category Aggregation
16
+ */
17
+ export interface AggregateFooterRowIf<T = any> {
18
+ /** Key = property of the column that shows the result (a key without a column is only in `getResults()`). */
19
+ aggregates: AggregateSpecMap<T>;
20
+ /**
21
+ * Text in the label column (always set as text, never as HTML). Default: `"6 rows"` – or, in a footer with
22
+ * several rows whose aggregates all use the same built-in aggregator, its word (`"Sum"`, `"Average"`, `"Min"` …).
23
+ */
24
+ label?: string | ((rowCount: number, results: Record<string, unknown>) => string);
25
+ }
26
+ /**
27
+ * The options of an {@link AreaModelAggregateFooter} (and of `TableFactory.createTableModel({ footerAggregates })`).
28
+ *
29
+ * @example
30
+ * const options: AggregateFooterOptionsIf<Order> = {
31
+ * rows: [
32
+ * { label: "Sum", aggregates: { quantity: "sum", total: "sum" } },
33
+ * { label: "Average", aggregates: { quantity: "avg", total: "avg" } }
34
+ * ],
35
+ * labelProperty: "customer", // the labels go into the customer column
36
+ * rowHeight: 36
37
+ * };
38
+ *
39
+ * @since 1.1.94
40
+ * @category Aggregation
41
+ */
42
+ export interface AggregateFooterOptionsIf<T = any> {
43
+ /** One footer row per entry. */
44
+ rows: AggregateFooterRowIf<T>[];
45
+ /** The column of the labels (property). Default: the first data column without an aggregate in that row. */
46
+ labelProperty?: string;
47
+ /** Height of the footer rows in px. Default 34 (the factory uses `defaultRowHeights.footer`). */
48
+ rowHeight?: number;
49
+ /**
50
+ * Which rows are aggregated: `"filtered"` (default) – the rows the body shows (after `externalFilterFunction`;
51
+ * in a tree all leaves that pass the filter, expanded or not); `"all"` – all rows, the filter is ignored.
52
+ */
53
+ source?: "filtered" | "all";
54
+ /** An own source of rows (instead of the body model's rows), e.g. the data of a server response. */
55
+ getRows?: (bodyModel: AreaModelIf) => ArrayLike<T>;
56
+ }
57
+ /**
58
+ * The short and the full forms of a footer configuration:
59
+ * - `{ total: "sum" }` – one row ({@link AggregateSpecMap}),
60
+ * - `[{ label: "Sum", aggregates: … }, …]` – several rows ({@link AggregateFooterRowIf}),
61
+ * - `{ rows: […], labelProperty, rowHeight, source, getRows }` – everything ({@link AggregateFooterOptionsIf}).
62
+ *
63
+ * @example
64
+ * const oneRow: AggregateFooterConfig<Order> = { quantity: "sum", total: "sum" };
65
+ * const twoRows: AggregateFooterConfig<Order> = [
66
+ * { label: "Sum", aggregates: { total: "sum" } },
67
+ * { label: "Max", aggregates: { total: "max" } }
68
+ * ];
69
+ *
70
+ * @since 1.1.94
71
+ * @category Aggregation
72
+ */
73
+ export type AggregateFooterConfig<T = any> = AggregateSpecMap<T> | AggregateFooterRowIf<T>[] | AggregateFooterOptionsIf<T>;