@youp-grid/core 0.1.0

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 ADDED
@@ -0,0 +1,11 @@
1
+ # @youp-grid/core
2
+
3
+ Framework-agnostic data grid core for Youp Grid.
4
+
5
+ ```sh
6
+ npm install @youp-grid/core
7
+ ```
8
+
9
+ ```ts
10
+ import { buildRowModel, type ColumnDef } from "@youp-grid/core";
11
+ ```
@@ -0,0 +1,2 @@
1
+ import type { AggregationResult, AggregationRule, ResolvedColumnDef, RowNode } from "./types.ts";
2
+ export declare function applyAggregation<TRow>(rows: readonly RowNode<TRow>[], columns: readonly ResolvedColumnDef<TRow>[], rules?: readonly AggregationRule[]): AggregationResult[];
@@ -0,0 +1,58 @@
1
+ import { getColumnById } from "./columns.js";
2
+ export function applyAggregation(rows, columns, rules = []) {
3
+ return rules
4
+ .map((rule) => {
5
+ const column = getColumnById(columns, rule.columnId);
6
+ if (!column) {
7
+ return undefined;
8
+ }
9
+ return aggregateColumn(rows, column, rule);
10
+ })
11
+ .filter((result) => Boolean(result));
12
+ }
13
+ function aggregateColumn(rows, column, rule) {
14
+ const numericValues = getNumericValues(rows, column);
15
+ return {
16
+ columnId: column.id,
17
+ function: rule.function,
18
+ label: rule.label ?? getAggregationLabel(rule.function),
19
+ value: getAggregationValue(rule.function, rows.length, numericValues),
20
+ rowCount: rows.length,
21
+ valueCount: numericValues.length,
22
+ };
23
+ }
24
+ function getNumericValues(rows, column) {
25
+ return rows
26
+ .map((row) => column.accessor(row.original))
27
+ .filter((value) => typeof value === "number" && Number.isFinite(value));
28
+ }
29
+ function getAggregationValue(fn, rowCount, values) {
30
+ switch (fn) {
31
+ case "count":
32
+ return rowCount;
33
+ case "sum":
34
+ return values.reduce((sum, value) => sum + value, 0);
35
+ case "avg":
36
+ return values.length > 0
37
+ ? values.reduce((sum, value) => sum + value, 0) / values.length
38
+ : undefined;
39
+ case "min":
40
+ return values.length > 0 ? Math.min(...values) : undefined;
41
+ case "max":
42
+ return values.length > 0 ? Math.max(...values) : undefined;
43
+ }
44
+ }
45
+ function getAggregationLabel(fn) {
46
+ switch (fn) {
47
+ case "sum":
48
+ return "Sum";
49
+ case "avg":
50
+ return "Avg";
51
+ case "min":
52
+ return "Min";
53
+ case "max":
54
+ return "Max";
55
+ case "count":
56
+ return "Count";
57
+ }
58
+ }
@@ -0,0 +1,33 @@
1
+ import type { ResolvedColumnDef, RowNode } from "./types.ts";
2
+ export type GridCellCoordinate = {
3
+ rowIndex: number;
4
+ columnIndex: number;
5
+ };
6
+ export type GridCellRange = {
7
+ anchor: GridCellCoordinate;
8
+ focus: GridCellCoordinate;
9
+ };
10
+ export type NormalizedGridCellRange = {
11
+ startRowIndex: number;
12
+ endRowIndex: number;
13
+ startColumnIndex: number;
14
+ endColumnIndex: number;
15
+ };
16
+ export type ClipboardPasteCell = GridCellCoordinate & {
17
+ value: string;
18
+ };
19
+ export declare function normalizeCellRange(range: GridCellRange): NormalizedGridCellRange;
20
+ export declare function isCellInRange(rowIndex: number, columnIndex: number, range: GridCellRange): boolean;
21
+ export declare function serializeGridRange<TRow>(options: {
22
+ rows: readonly RowNode<TRow>[];
23
+ columns: readonly ResolvedColumnDef<TRow>[];
24
+ range: GridCellRange;
25
+ }): string;
26
+ export declare function parseClipboardText(text: string): string[][];
27
+ export declare function getClipboardPasteCells(options: {
28
+ values: readonly (readonly string[])[];
29
+ startCell: GridCellCoordinate;
30
+ rowCount: number;
31
+ columnCount: number;
32
+ fillRange?: NormalizedGridCellRange;
33
+ }): ClipboardPasteCell[];
@@ -0,0 +1,79 @@
1
+ export function normalizeCellRange(range) {
2
+ return {
3
+ startRowIndex: Math.min(range.anchor.rowIndex, range.focus.rowIndex),
4
+ endRowIndex: Math.max(range.anchor.rowIndex, range.focus.rowIndex),
5
+ startColumnIndex: Math.min(range.anchor.columnIndex, range.focus.columnIndex),
6
+ endColumnIndex: Math.max(range.anchor.columnIndex, range.focus.columnIndex),
7
+ };
8
+ }
9
+ export function isCellInRange(rowIndex, columnIndex, range) {
10
+ const normalized = normalizeCellRange(range);
11
+ return (rowIndex >= normalized.startRowIndex &&
12
+ rowIndex <= normalized.endRowIndex &&
13
+ columnIndex >= normalized.startColumnIndex &&
14
+ columnIndex <= normalized.endColumnIndex);
15
+ }
16
+ export function serializeGridRange(options) {
17
+ const range = normalizeCellRange(options.range);
18
+ const lines = [];
19
+ for (let rowIndex = range.startRowIndex; rowIndex <= range.endRowIndex; rowIndex += 1) {
20
+ const row = options.rows[rowIndex];
21
+ if (!row) {
22
+ continue;
23
+ }
24
+ const values = [];
25
+ for (let columnIndex = range.startColumnIndex; columnIndex <= range.endColumnIndex; columnIndex += 1) {
26
+ const column = options.columns[columnIndex];
27
+ const value = column ? column.accessor(row.original) : "";
28
+ values.push(escapeClipboardCell(formatClipboardValue(value)));
29
+ }
30
+ lines.push(values.join("\t"));
31
+ }
32
+ return lines.join("\n");
33
+ }
34
+ export function parseClipboardText(text) {
35
+ const normalizedText = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
36
+ const trimmedText = normalizedText.endsWith("\n") ? normalizedText.slice(0, -1) : normalizedText;
37
+ if (!trimmedText) {
38
+ return [];
39
+ }
40
+ return trimmedText.split("\n").map((line) => {
41
+ return line.split("\t").map((cell) => {
42
+ return cell.replace(/\\n/g, "\n").replace(/\\t/g, "\t").replace(/\\\\/g, "\\");
43
+ });
44
+ });
45
+ }
46
+ export function getClipboardPasteCells(options) {
47
+ if (options.values.length === 0) {
48
+ return [];
49
+ }
50
+ const rowLimit = options.fillRange
51
+ ? options.fillRange.endRowIndex - options.fillRange.startRowIndex + 1
52
+ : options.values.length;
53
+ const columnLimit = options.fillRange
54
+ ? options.fillRange.endColumnIndex - options.fillRange.startColumnIndex + 1
55
+ : Math.max(...options.values.map((row) => row.length));
56
+ const cells = [];
57
+ for (let rowOffset = 0; rowOffset < rowLimit; rowOffset += 1) {
58
+ const rowIndex = options.startCell.rowIndex + rowOffset;
59
+ if (rowIndex < 0 || rowIndex >= options.rowCount) {
60
+ continue;
61
+ }
62
+ for (let columnOffset = 0; columnOffset < columnLimit; columnOffset += 1) {
63
+ const columnIndex = options.startCell.columnIndex + columnOffset;
64
+ if (columnIndex < 0 || columnIndex >= options.columnCount) {
65
+ continue;
66
+ }
67
+ const valueRow = options.values[rowOffset % options.values.length] ?? [""];
68
+ const value = valueRow[columnOffset % Math.max(1, valueRow.length)] ?? "";
69
+ cells.push({ rowIndex, columnIndex, value });
70
+ }
71
+ }
72
+ return cells;
73
+ }
74
+ function formatClipboardValue(value) {
75
+ return value == null ? "" : String(value);
76
+ }
77
+ function escapeClipboardCell(value) {
78
+ return value.replace(/\\/g, "\\\\").replace(/\t/g, "\\t").replace(/\n/g, "\\n");
79
+ }
@@ -0,0 +1,7 @@
1
+ import type { ColumnState, GridState, ResolvedColumnDef } from "./types.ts";
2
+ export declare function applyColumnState<TRow>(columns: readonly ResolvedColumnDef<TRow>[], columnStates?: readonly ColumnState[]): ResolvedColumnDef<TRow>[];
3
+ export declare function getVisibleColumns<TRow>(columns: readonly ResolvedColumnDef<TRow>[]): ResolvedColumnDef<TRow>[];
4
+ export declare function setColumnHidden(state: GridState, columnId: string, hidden: boolean): GridState;
5
+ export declare function setColumnWidth(state: GridState, columnId: string, width: number): GridState;
6
+ export declare function setColumnPinned(state: GridState, columnId: string, pinned: ColumnState["pinned"] | undefined): GridState;
7
+ export declare function setColumnOrder(state: GridState, columnIds: readonly string[]): GridState;
@@ -0,0 +1,66 @@
1
+ const MIN_COLUMN_WIDTH = 24;
2
+ export function applyColumnState(columns, columnStates = []) {
3
+ if (columnStates.length === 0) {
4
+ return [...columns];
5
+ }
6
+ const stateById = new Map(columnStates.map((state) => [state.columnId, state]));
7
+ return columns
8
+ .map((column, index) => {
9
+ const state = stateById.get(column.id);
10
+ return {
11
+ ...column,
12
+ hidden: state?.hidden ?? column.hidden,
13
+ pinned: state?.pinned ?? column.pinned,
14
+ width: state?.width ?? column.width,
15
+ order: state?.order ?? index,
16
+ };
17
+ })
18
+ .sort((left, right) => {
19
+ return (left.order ?? 0) - (right.order ?? 0);
20
+ })
21
+ .map(({ order, ...column }) => column);
22
+ }
23
+ export function getVisibleColumns(columns) {
24
+ return columns.filter((column) => !column.hidden);
25
+ }
26
+ export function setColumnHidden(state, columnId, hidden) {
27
+ return updateColumnState(state, columnId, { hidden });
28
+ }
29
+ export function setColumnWidth(state, columnId, width) {
30
+ return updateColumnState(state, columnId, {
31
+ width: Math.max(MIN_COLUMN_WIDTH, Math.round(width)),
32
+ });
33
+ }
34
+ export function setColumnPinned(state, columnId, pinned) {
35
+ return updateColumnState(state, columnId, { pinned });
36
+ }
37
+ export function setColumnOrder(state, columnIds) {
38
+ const knownColumnIds = new Set(columnIds);
39
+ const existingStates = (state.columns ?? []).filter((column) => knownColumnIds.has(column.columnId));
40
+ const statesById = new Map(existingStates.map((column) => [column.columnId, column]));
41
+ const orderedStates = columnIds.map((columnId, order) => ({
42
+ ...statesById.get(columnId),
43
+ columnId,
44
+ order,
45
+ }));
46
+ return {
47
+ ...state,
48
+ columns: orderedStates,
49
+ };
50
+ }
51
+ function updateColumnState(state, columnId, patch) {
52
+ const columns = state.columns ?? [];
53
+ const existing = columns.find((column) => column.columnId === columnId);
54
+ const nextColumnState = {
55
+ ...existing,
56
+ columnId,
57
+ ...patch,
58
+ };
59
+ return {
60
+ ...state,
61
+ columns: [
62
+ ...columns.filter((column) => column.columnId !== columnId),
63
+ nextColumnState,
64
+ ],
65
+ };
66
+ }
@@ -0,0 +1,3 @@
1
+ import type { ColumnDef, ResolvedColumnDef } from "./types.ts";
2
+ export declare function normalizeColumns<TRow>(columns: readonly ColumnDef<TRow>[]): ResolvedColumnDef<TRow>[];
3
+ export declare function getColumnById<TRow>(columns: readonly ResolvedColumnDef<TRow>[], columnId: string): ResolvedColumnDef<TRow> | undefined;
@@ -0,0 +1,44 @@
1
+ export function normalizeColumns(columns) {
2
+ const seen = new Set();
3
+ return columns.map((column) => {
4
+ const id = resolveColumnId(column);
5
+ if (seen.has(id)) {
6
+ throw new Error(`Duplicate grid column id: ${id}`);
7
+ }
8
+ seen.add(id);
9
+ return {
10
+ ...column,
11
+ id,
12
+ headerName: column.headerName ?? id,
13
+ accessor: column.accessor ?? createFieldAccessor(column.field),
14
+ };
15
+ });
16
+ }
17
+ export function getColumnById(columns, columnId) {
18
+ return columns.find((column) => column.id === columnId);
19
+ }
20
+ function resolveColumnId(column) {
21
+ if (column.id) {
22
+ return column.id;
23
+ }
24
+ if (column.field) {
25
+ return String(column.field);
26
+ }
27
+ throw new Error("Column requires either `id` or `field`.");
28
+ }
29
+ function createFieldAccessor(field) {
30
+ if (!field) {
31
+ throw new Error("Column without `field` requires an explicit `accessor`.");
32
+ }
33
+ return (row) => {
34
+ return getNestedValue(row, String(field));
35
+ };
36
+ }
37
+ function getNestedValue(row, path) {
38
+ return path.split(".").reduce((value, key) => {
39
+ if (value == null || typeof value !== "object") {
40
+ return undefined;
41
+ }
42
+ return value[key];
43
+ }, row);
44
+ }
package/dist/csv.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ import type { ResolvedColumnDef, RowNode } from "./types.ts";
2
+ export type CsvCellFormatter<TRow> = (context: {
3
+ row: RowNode<TRow>;
4
+ column: ResolvedColumnDef<TRow>;
5
+ value: unknown;
6
+ }) => unknown;
7
+ export type ExportGridCsvOptions<TRow> = {
8
+ rows: readonly RowNode<TRow>[];
9
+ columns: readonly ResolvedColumnDef<TRow>[];
10
+ includeHeaders?: boolean;
11
+ delimiter?: string;
12
+ lineBreak?: string;
13
+ formatCell?: CsvCellFormatter<TRow>;
14
+ };
15
+ export declare function exportGridCsv<TRow>(options: ExportGridCsvOptions<TRow>): string;
package/dist/csv.js ADDED
@@ -0,0 +1,30 @@
1
+ export function exportGridCsv(options) {
2
+ const delimiter = options.delimiter ?? ",";
3
+ const lineBreak = options.lineBreak ?? "\n";
4
+ const lines = [];
5
+ if (options.includeHeaders ?? true) {
6
+ lines.push(options.columns.map((column) => escapeCsvCell(column.headerName, delimiter)).join(delimiter));
7
+ }
8
+ for (const row of options.rows) {
9
+ lines.push(options.columns
10
+ .map((column) => {
11
+ const value = column.accessor(row.original);
12
+ const formattedValue = options.formatCell
13
+ ? options.formatCell({ row, column, value })
14
+ : formatCsvValue(column, row.original, value);
15
+ return escapeCsvCell(formattedValue, delimiter);
16
+ })
17
+ .join(delimiter));
18
+ }
19
+ return lines.join(lineBreak);
20
+ }
21
+ function formatCsvValue(column, row, value) {
22
+ return column.valueFormatter ? column.valueFormatter(value, row) : value;
23
+ }
24
+ function escapeCsvCell(value, delimiter) {
25
+ const text = value == null ? "" : String(value);
26
+ if (!text.includes(delimiter) && !text.includes("\"") && !text.includes("\n") && !text.includes("\r")) {
27
+ return text;
28
+ }
29
+ return `"${text.replace(/"/g, "\"\"")}"`;
30
+ }
@@ -0,0 +1,17 @@
1
+ import type { GridCellCoordinate, NormalizedGridCellRange } from "./clipboard.ts";
2
+ export type GridFillHandleCell<TValue = unknown> = GridCellCoordinate & {
3
+ sourceRowIndex: number;
4
+ sourceColumnIndex: number;
5
+ value: TValue;
6
+ };
7
+ export declare function getFillHandleTargetRange(options: {
8
+ sourceRange: NormalizedGridCellRange;
9
+ targetCell: GridCellCoordinate;
10
+ rowCount: number;
11
+ columnCount: number;
12
+ }): NormalizedGridCellRange | undefined;
13
+ export declare function getFillHandleCells<TValue>(options: {
14
+ sourceRange: NormalizedGridCellRange;
15
+ targetRange: NormalizedGridCellRange;
16
+ getValue: (cell: GridCellCoordinate) => TValue;
17
+ }): GridFillHandleCell<TValue>[];
@@ -0,0 +1,73 @@
1
+ export function getFillHandleTargetRange(options) {
2
+ if (options.rowCount === 0 || options.columnCount === 0) {
3
+ return undefined;
4
+ }
5
+ const targetRowIndex = clamp(options.targetCell.rowIndex, 0, options.rowCount - 1);
6
+ const targetColumnIndex = clamp(options.targetCell.columnIndex, 0, options.columnCount - 1);
7
+ const range = options.sourceRange;
8
+ const targetInSourceRows = targetRowIndex >= range.startRowIndex && targetRowIndex <= range.endRowIndex;
9
+ const targetInSourceColumns = targetColumnIndex >= range.startColumnIndex && targetColumnIndex <= range.endColumnIndex;
10
+ if (targetInSourceRows && targetInSourceColumns) {
11
+ return undefined;
12
+ }
13
+ if (targetRowIndex > range.endRowIndex) {
14
+ return {
15
+ startRowIndex: range.endRowIndex + 1,
16
+ endRowIndex: targetRowIndex,
17
+ startColumnIndex: range.startColumnIndex,
18
+ endColumnIndex: range.endColumnIndex,
19
+ };
20
+ }
21
+ if (targetRowIndex < range.startRowIndex) {
22
+ return {
23
+ startRowIndex: targetRowIndex,
24
+ endRowIndex: range.startRowIndex - 1,
25
+ startColumnIndex: range.startColumnIndex,
26
+ endColumnIndex: range.endColumnIndex,
27
+ };
28
+ }
29
+ if (targetColumnIndex > range.endColumnIndex) {
30
+ return {
31
+ startRowIndex: range.startRowIndex,
32
+ endRowIndex: range.endRowIndex,
33
+ startColumnIndex: range.endColumnIndex + 1,
34
+ endColumnIndex: targetColumnIndex,
35
+ };
36
+ }
37
+ if (targetColumnIndex < range.startColumnIndex) {
38
+ return {
39
+ startRowIndex: range.startRowIndex,
40
+ endRowIndex: range.endRowIndex,
41
+ startColumnIndex: targetColumnIndex,
42
+ endColumnIndex: range.startColumnIndex - 1,
43
+ };
44
+ }
45
+ return undefined;
46
+ }
47
+ export function getFillHandleCells(options) {
48
+ const sourceRowCount = options.sourceRange.endRowIndex - options.sourceRange.startRowIndex + 1;
49
+ const sourceColumnCount = options.sourceRange.endColumnIndex - options.sourceRange.startColumnIndex + 1;
50
+ const cells = [];
51
+ for (let rowIndex = options.targetRange.startRowIndex; rowIndex <= options.targetRange.endRowIndex; rowIndex += 1) {
52
+ const sourceRowIndex = options.sourceRange.startRowIndex +
53
+ ((rowIndex - options.targetRange.startRowIndex) % sourceRowCount);
54
+ for (let columnIndex = options.targetRange.startColumnIndex; columnIndex <= options.targetRange.endColumnIndex; columnIndex += 1) {
55
+ const sourceColumnIndex = options.sourceRange.startColumnIndex +
56
+ ((columnIndex - options.targetRange.startColumnIndex) % sourceColumnCount);
57
+ cells.push({
58
+ rowIndex,
59
+ columnIndex,
60
+ sourceRowIndex,
61
+ sourceColumnIndex,
62
+ value: options.getValue({
63
+ rowIndex: sourceRowIndex,
64
+ columnIndex: sourceColumnIndex,
65
+ }),
66
+ });
67
+ }
68
+ }
69
+ return cells;
70
+ }
71
+ function clamp(value, min, max) {
72
+ return Math.min(Math.max(value, min), max);
73
+ }
@@ -0,0 +1,3 @@
1
+ import type { FilterRule, ResolvedColumnDef, RowNode } from "./types.ts";
2
+ export declare function applyFilters<TRow>(rows: readonly RowNode<TRow>[], columns: readonly ResolvedColumnDef<TRow>[], filters?: readonly FilterRule[]): RowNode<TRow>[];
3
+ export declare function defaultFilterPredicate(value: unknown, filter: FilterRule): boolean;
@@ -0,0 +1,68 @@
1
+ import { getColumnById } from "./columns.js";
2
+ export function applyFilters(rows, columns, filters = []) {
3
+ const activeFilters = filters.filter((filter) => hasUsableFilterValue(filter));
4
+ if (activeFilters.length === 0) {
5
+ return [...rows];
6
+ }
7
+ return rows.filter((row) => {
8
+ return activeFilters.every((filter) => {
9
+ const column = getColumnById(columns, filter.columnId);
10
+ if (!column) {
11
+ return true;
12
+ }
13
+ const value = column.accessor(row.original);
14
+ if (column.filterPredicate) {
15
+ return column.filterPredicate(value, filter, row.original);
16
+ }
17
+ return defaultFilterPredicate(value, filter);
18
+ });
19
+ });
20
+ }
21
+ export function defaultFilterPredicate(value, filter) {
22
+ switch (filter.operator) {
23
+ case "contains":
24
+ return stringify(value).includes(stringify(filter.value));
25
+ case "equals":
26
+ return value === filter.value;
27
+ case "startsWith":
28
+ return stringify(value).startsWith(stringify(filter.value));
29
+ case "endsWith":
30
+ return stringify(value).endsWith(stringify(filter.value));
31
+ case "gt":
32
+ return comparePrimitive(value, filter.value) > 0;
33
+ case "gte":
34
+ return comparePrimitive(value, filter.value) >= 0;
35
+ case "lt":
36
+ return comparePrimitive(value, filter.value) < 0;
37
+ case "lte":
38
+ return comparePrimitive(value, filter.value) <= 0;
39
+ case "between":
40
+ return isBetween(value, filter.value);
41
+ case "isEmpty":
42
+ return value == null || value === "";
43
+ case "isNotEmpty":
44
+ return value != null && value !== "";
45
+ case "in":
46
+ return Array.isArray(filter.value) && filter.value.includes(value);
47
+ }
48
+ }
49
+ function hasUsableFilterValue(filter) {
50
+ return (filter.operator === "isEmpty" ||
51
+ filter.operator === "isNotEmpty" ||
52
+ filter.value !== undefined);
53
+ }
54
+ function stringify(value) {
55
+ return String(value ?? "").toLocaleLowerCase();
56
+ }
57
+ function comparePrimitive(left, right) {
58
+ if (typeof left === "number" && typeof right === "number") {
59
+ return left - right;
60
+ }
61
+ return stringify(left).localeCompare(stringify(right));
62
+ }
63
+ function isBetween(value, range) {
64
+ if (!Array.isArray(range) || range.length !== 2) {
65
+ return true;
66
+ }
67
+ return comparePrimitive(value, range[0]) >= 0 && comparePrimitive(value, range[1]) <= 0;
68
+ }
@@ -0,0 +1,28 @@
1
+ import type { GridRowId } from "./types.ts";
2
+ export type GridCellValueHistoryChange = {
3
+ rowId: GridRowId;
4
+ rowIndex: number;
5
+ columnId: string;
6
+ previousValue: unknown;
7
+ value: unknown;
8
+ };
9
+ export type GridValueHistoryEntry = {
10
+ changes: readonly GridCellValueHistoryChange[];
11
+ };
12
+ export type GridValueHistoryState = {
13
+ undoStack: GridValueHistoryEntry[];
14
+ redoStack: GridValueHistoryEntry[];
15
+ };
16
+ export declare function createValueHistoryState(): GridValueHistoryState;
17
+ export declare function pushValueHistoryEntry(state: GridValueHistoryState, entry: GridValueHistoryEntry, options?: {
18
+ maxEntries?: number;
19
+ }): GridValueHistoryState;
20
+ export declare function undoValueHistory(state: GridValueHistoryState): {
21
+ state: GridValueHistoryState;
22
+ entry?: GridValueHistoryEntry;
23
+ };
24
+ export declare function redoValueHistory(state: GridValueHistoryState): {
25
+ state: GridValueHistoryState;
26
+ entry?: GridValueHistoryEntry;
27
+ };
28
+ export declare function invertValueHistoryEntry(entry: GridValueHistoryEntry): GridValueHistoryEntry;
@@ -0,0 +1,54 @@
1
+ export function createValueHistoryState() {
2
+ return {
3
+ undoStack: [],
4
+ redoStack: [],
5
+ };
6
+ }
7
+ export function pushValueHistoryEntry(state, entry, options = {}) {
8
+ if (entry.changes.length === 0) {
9
+ return state;
10
+ }
11
+ const maxEntries = options.maxEntries ?? 100;
12
+ const nextEntry = {
13
+ changes: [...entry.changes],
14
+ };
15
+ return {
16
+ undoStack: [...state.undoStack, nextEntry].slice(-maxEntries),
17
+ redoStack: [],
18
+ };
19
+ }
20
+ export function undoValueHistory(state) {
21
+ const entry = state.undoStack[state.undoStack.length - 1];
22
+ if (!entry) {
23
+ return { state };
24
+ }
25
+ return {
26
+ state: {
27
+ undoStack: state.undoStack.slice(0, -1),
28
+ redoStack: [...state.redoStack, entry],
29
+ },
30
+ entry,
31
+ };
32
+ }
33
+ export function redoValueHistory(state) {
34
+ const entry = state.redoStack[state.redoStack.length - 1];
35
+ if (!entry) {
36
+ return { state };
37
+ }
38
+ return {
39
+ state: {
40
+ undoStack: [...state.undoStack, entry],
41
+ redoStack: state.redoStack.slice(0, -1),
42
+ },
43
+ entry,
44
+ };
45
+ }
46
+ export function invertValueHistoryEntry(entry) {
47
+ return {
48
+ changes: entry.changes.map((change) => ({
49
+ ...change,
50
+ previousValue: change.value,
51
+ value: change.previousValue,
52
+ })),
53
+ };
54
+ }
@@ -0,0 +1,21 @@
1
+ export { applyColumnState, getVisibleColumns, setColumnHidden, setColumnOrder, setColumnPinned, setColumnWidth, } from "./column-state.ts";
2
+ export { applyAggregation } from "./aggregation.ts";
3
+ export { isCellInRange, getClipboardPasteCells, normalizeCellRange, parseClipboardText, serializeGridRange, } from "./clipboard.ts";
4
+ export type { ClipboardPasteCell, GridCellCoordinate, GridCellRange, NormalizedGridCellRange, } from "./clipboard.ts";
5
+ export { getColumnById, normalizeColumns } from "./columns.ts";
6
+ export { getFillHandleCells, getFillHandleTargetRange } from "./fill-handle.ts";
7
+ export type { GridFillHandleCell } from "./fill-handle.ts";
8
+ export { exportGridCsv } from "./csv.ts";
9
+ export type { CsvCellFormatter, ExportGridCsvOptions } from "./csv.ts";
10
+ export { applyFilters, defaultFilterPredicate } from "./filtering.ts";
11
+ export { getInfiniteScrollTrigger } from "./infinite-scroll.ts";
12
+ export { applyPagination } from "./pagination.ts";
13
+ export { buildRowModel } from "./row-model.ts";
14
+ export { applyRowGrouping, isRowGroupNode } from "./row-grouping.ts";
15
+ export { applySorting } from "./sorting.ts";
16
+ export { clearSelection, setRowSelected, setSelectedRows, toggleRowSelected } from "./selection.ts";
17
+ export { clearFilter, clearSort, acknowledgeRemoteCache, cancelRemoteRequest, createRemoteCacheKey, createGridState, failRemoteRequest, finishRemoteRequest, invalidateRemoteCache, isActiveRemoteRequest, setCursorPage, setCursorPageSize, setCursorPagination, setAggregation, setFilter, setPagination, setRemoteCache, setRowGrouping, setSort, startRemoteRequest, toggleRowGroupExpanded, toggleSort, } from "./state.ts";
18
+ export { getVirtualRange } from "./virtualizer.ts";
19
+ export { createValueHistoryState, invertValueHistoryEntry, pushValueHistoryEntry, redoValueHistory, undoValueHistory, } from "./history.ts";
20
+ export type { GridCellValueHistoryChange, GridValueHistoryEntry, GridValueHistoryState, } from "./history.ts";
21
+ export type { Accessor, AggregationFunctionName, AggregationResult, AggregationRule, BuildRowModelOptions, ColumnPin, ColumnState, ColumnComparator, ColumnDef, ColumnFilterPredicate, CursorPaginationState, FilterOperator, FilterRule, GridRowId, GridRowModelType, GridState, InfiniteScrollTrigger, InfiniteScrollTriggerOptions, PaginationState, ResolvedColumnDef, RemoteCacheState, RemoteRequestState, RemoteRequestStatus, RowModel, RowDisplayNode, RowGroupNode, RowGroupingState, RowNode, SortDirection, SortRule, ValueFormatter, ValueParser, VirtualItem, VirtualRange, VirtualRangeOptions, } from "./types.ts";
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ export { applyColumnState, getVisibleColumns, setColumnHidden, setColumnOrder, setColumnPinned, setColumnWidth, } from "./column-state.js";
2
+ export { applyAggregation } from "./aggregation.js";
3
+ export { isCellInRange, getClipboardPasteCells, normalizeCellRange, parseClipboardText, serializeGridRange, } from "./clipboard.js";
4
+ export { getColumnById, normalizeColumns } from "./columns.js";
5
+ export { getFillHandleCells, getFillHandleTargetRange } from "./fill-handle.js";
6
+ export { exportGridCsv } from "./csv.js";
7
+ export { applyFilters, defaultFilterPredicate } from "./filtering.js";
8
+ export { getInfiniteScrollTrigger } from "./infinite-scroll.js";
9
+ export { applyPagination } from "./pagination.js";
10
+ export { buildRowModel } from "./row-model.js";
11
+ export { applyRowGrouping, isRowGroupNode } from "./row-grouping.js";
12
+ export { applySorting } from "./sorting.js";
13
+ export { clearSelection, setRowSelected, setSelectedRows, toggleRowSelected } from "./selection.js";
14
+ export { clearFilter, clearSort, acknowledgeRemoteCache, cancelRemoteRequest, createRemoteCacheKey, createGridState, failRemoteRequest, finishRemoteRequest, invalidateRemoteCache, isActiveRemoteRequest, setCursorPage, setCursorPageSize, setCursorPagination, setAggregation, setFilter, setPagination, setRemoteCache, setRowGrouping, setSort, startRemoteRequest, toggleRowGroupExpanded, toggleSort, } from "./state.js";
15
+ export { getVirtualRange } from "./virtualizer.js";
16
+ export { createValueHistoryState, invertValueHistoryEntry, pushValueHistoryEntry, redoValueHistory, undoValueHistory, } from "./history.js";
@@ -0,0 +1,2 @@
1
+ import type { InfiniteScrollTrigger, InfiniteScrollTriggerOptions } from "./types.ts";
2
+ export declare function getInfiniteScrollTrigger(options: InfiniteScrollTriggerOptions): InfiniteScrollTrigger;