@alaarab/ogrid-core 2.1.2 → 2.1.4

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 (35) hide show
  1. package/dist/esm/index.js +1426 -54
  2. package/package.json +3 -3
  3. package/dist/esm/constants/index.js +0 -3
  4. package/dist/esm/constants/layout.js +0 -13
  5. package/dist/esm/constants/timing.js +0 -10
  6. package/dist/esm/constants/zIndex.js +0 -16
  7. package/dist/esm/types/columnTypes.js +0 -1
  8. package/dist/esm/types/dataGridTypes.js +0 -27
  9. package/dist/esm/types/index.js +0 -2
  10. package/dist/esm/utils/aggregationUtils.js +0 -48
  11. package/dist/esm/utils/cellValue.js +0 -14
  12. package/dist/esm/utils/clientSideData.js +0 -155
  13. package/dist/esm/utils/clipboardHelpers.js +0 -142
  14. package/dist/esm/utils/columnAutosize.js +0 -38
  15. package/dist/esm/utils/columnReorder.js +0 -99
  16. package/dist/esm/utils/columnUtils.js +0 -122
  17. package/dist/esm/utils/dataGridStatusBar.js +0 -15
  18. package/dist/esm/utils/dataGridViewModel.js +0 -206
  19. package/dist/esm/utils/debounce.js +0 -40
  20. package/dist/esm/utils/dom.js +0 -53
  21. package/dist/esm/utils/exportToCsv.js +0 -50
  22. package/dist/esm/utils/fillHelpers.js +0 -47
  23. package/dist/esm/utils/gridContextMenuHelpers.js +0 -80
  24. package/dist/esm/utils/gridRowComparator.js +0 -78
  25. package/dist/esm/utils/index.js +0 -25
  26. package/dist/esm/utils/keyboardNavigation.js +0 -181
  27. package/dist/esm/utils/ogridHelpers.js +0 -67
  28. package/dist/esm/utils/paginationHelpers.js +0 -58
  29. package/dist/esm/utils/selectionHelpers.js +0 -94
  30. package/dist/esm/utils/sortHelpers.js +0 -28
  31. package/dist/esm/utils/statusBarHelpers.js +0 -27
  32. package/dist/esm/utils/undoRedoStack.js +0 -130
  33. package/dist/esm/utils/validation.js +0 -43
  34. package/dist/esm/utils/valueParsers.js +0 -121
  35. package/dist/esm/utils/virtualScroll.js +0 -46
@@ -1,130 +0,0 @@
1
- /**
2
- * Pure undo/redo stack data structure shared across React, Vue, Angular, and JS.
3
- * No framework dependencies — all state is plain arrays.
4
- *
5
- * Usage:
6
- * const stack = new UndoRedoStack<MyEvent>(100);
7
- * stack.push([event]); // single event
8
- * stack.beginBatch();
9
- * stack.push([event1]);
10
- * stack.push([event2]);
11
- * stack.endBatch(); // event1 + event2 are one undo step
12
- * const batch = stack.undo(); // returns the batch to reverse
13
- * const batch = stack.redo(); // returns the batch to re-apply
14
- */
15
- export class UndoRedoStack {
16
- constructor(maxDepth = 100) {
17
- this.history = [];
18
- this.redoStack = [];
19
- this.batch = null;
20
- this.maxDepth = maxDepth;
21
- }
22
- /** Whether there are undo steps available. */
23
- get canUndo() {
24
- return this.history.length > 0;
25
- }
26
- /** Whether there are redo steps available. */
27
- get canRedo() {
28
- return this.redoStack.length > 0;
29
- }
30
- /** Number of history entries. */
31
- get historyLength() {
32
- return this.history.length;
33
- }
34
- /** Number of redo entries. */
35
- get redoLength() {
36
- return this.redoStack.length;
37
- }
38
- /** Whether a batch is currently open. */
39
- get isBatching() {
40
- return this.batch !== null;
41
- }
42
- /**
43
- * Record a group of events as a single undoable step.
44
- * If a batch is open, accumulates into the batch instead.
45
- * Clears the redo stack on any new entry.
46
- */
47
- push(events) {
48
- if (events.length === 0)
49
- return;
50
- if (this.batch !== null) {
51
- this.batch.push(...events);
52
- }
53
- else {
54
- this.history.push(events);
55
- if (this.history.length > this.maxDepth) {
56
- this.history.splice(0, this.history.length - this.maxDepth);
57
- }
58
- // Clear redo stack in-place — avoids allocating a new array on every edit
59
- this.redoStack.length = 0;
60
- }
61
- }
62
- /**
63
- * Record a single event as a step (shorthand for push([event])).
64
- * If a batch is open, accumulates into the batch instead.
65
- */
66
- record(event) {
67
- this.push([event]);
68
- }
69
- /**
70
- * Start a batch — subsequent record/push calls accumulate into one undo step.
71
- * Has no effect if a batch is already open.
72
- */
73
- beginBatch() {
74
- if (this.batch === null) {
75
- this.batch = [];
76
- }
77
- }
78
- /**
79
- * End a batch — commits all accumulated events as one undo step.
80
- * Has no effect if no batch is open or if the batch is empty.
81
- */
82
- endBatch() {
83
- const b = this.batch;
84
- this.batch = null;
85
- if (!b || b.length === 0)
86
- return;
87
- this.history.push(b);
88
- if (this.history.length > this.maxDepth) {
89
- this.history.splice(0, this.history.length - this.maxDepth);
90
- }
91
- this.redoStack.length = 0;
92
- }
93
- /**
94
- * Pop the most recent history entry for undo.
95
- * Returns the batch of events (in original order) to be reversed by the caller,
96
- * or null if there is nothing to undo.
97
- *
98
- * The caller is responsible for applying the events in reverse order.
99
- */
100
- undo() {
101
- const lastBatch = this.history.pop();
102
- if (!lastBatch)
103
- return null;
104
- this.redoStack.push(lastBatch);
105
- return lastBatch;
106
- }
107
- /**
108
- * Pop the most recent redo entry.
109
- * Returns the batch of events (in original order) to be re-applied by the caller,
110
- * or null if there is nothing to redo.
111
- */
112
- redo() {
113
- const nextBatch = this.redoStack.pop();
114
- if (!nextBatch)
115
- return null;
116
- this.history.push(nextBatch);
117
- return nextBatch;
118
- }
119
- /**
120
- * Clear all history and redo state.
121
- * Does not affect any open batch — call endBatch() first if needed.
122
- */
123
- clear() {
124
- this.history = [];
125
- this.redoStack = [];
126
- // Intentionally leaves this.batch untouched. If a batch is open,
127
- // subsequent records will still accumulate until endBatch() is called.
128
- // Callers that want to abort an open batch should call endBatch() first.
129
- }
130
- }
@@ -1,43 +0,0 @@
1
- /**
2
- * Validate column definitions at grid initialization.
3
- * Called once (not per render). Warns on empty/missing/duplicate columnIds.
4
- */
5
- export function validateColumns(columns) {
6
- if (!Array.isArray(columns) || columns.length === 0) {
7
- console.warn('[OGrid] columns prop is empty or not an array');
8
- return;
9
- }
10
- const ids = new Set();
11
- for (const col of columns) {
12
- if (!col.columnId) {
13
- console.warn('[OGrid] Column missing columnId:', col);
14
- }
15
- if (ids.has(col.columnId)) {
16
- console.warn(`[OGrid] Duplicate columnId: "${col.columnId}"`);
17
- }
18
- ids.add(col.columnId);
19
- }
20
- }
21
- /**
22
- * Validate that getRowId returns unique, non-null values.
23
- * Dev-only (skipped in production). Samples the first 100 rows.
24
- * Called once on first data render via a hasValidated flag in the caller.
25
- */
26
- export function validateRowIds(items, getRowId) {
27
- if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production')
28
- return;
29
- const ids = new Set();
30
- const limit = Math.min(items.length, 100);
31
- for (let i = 0; i < limit; i++) {
32
- const id = getRowId(items[i]);
33
- if (id == null) {
34
- console.warn(`[OGrid] getRowId returned null/undefined for row ${i}`);
35
- return;
36
- }
37
- if (ids.has(id)) {
38
- console.warn(`[OGrid] Duplicate row ID "${id}" at index ${i}. getRowId must return unique values.`);
39
- return;
40
- }
41
- ids.add(id);
42
- }
43
- }
@@ -1,121 +0,0 @@
1
- /**
2
- * Run the column's valueParser (if any), or auto-validate select columns.
3
- * Returns `{ valid: true, value }` with the parsed value, or `{ valid: false }` to reject.
4
- */
5
- export function parseValue(newValue, oldValue, item, col) {
6
- // 1. Custom valueParser takes priority
7
- if (col.valueParser) {
8
- const params = {
9
- newValue,
10
- oldValue,
11
- data: item,
12
- column: col,
13
- };
14
- const parsed = col.valueParser(params);
15
- if (parsed === undefined) {
16
- return { valid: false, value: undefined };
17
- }
18
- return { valid: true, value: parsed };
19
- }
20
- // 2. Auto-validate select columns against allowed values
21
- if (col.cellEditor === 'select' &&
22
- col.cellEditorParams?.values != null &&
23
- Array.isArray(col.cellEditorParams.values)) {
24
- const allowedValues = col.cellEditorParams.values;
25
- const strValue = typeof newValue === 'string' ? newValue : String(newValue ?? '');
26
- // Allow clearing (empty string)
27
- if (strValue === '') {
28
- return { valid: true, value: '' };
29
- }
30
- // Case-insensitive match; return canonical value from the options list
31
- const match = allowedValues.find((v) => String(v).toLowerCase() === strValue.toLowerCase());
32
- if (match !== undefined) {
33
- return { valid: true, value: match };
34
- }
35
- return { valid: false, value: undefined };
36
- }
37
- // 3. Auto-validate built-in column types
38
- const colType = col.type;
39
- if (colType === 'date') {
40
- const parsed = dateParser({ newValue, oldValue, data: item, column: col });
41
- return parsed === undefined ? { valid: false, value: undefined } : { valid: true, value: parsed };
42
- }
43
- if (colType === 'boolean') {
44
- const parsed = booleanParser({ newValue, oldValue, data: item, column: col });
45
- return parsed === undefined ? { valid: false, value: undefined } : { valid: true, value: parsed };
46
- }
47
- if (colType === 'numeric') {
48
- const parsed = numberParser({ newValue, oldValue, data: item, column: col });
49
- return parsed === undefined ? { valid: false, value: undefined } : { valid: true, value: parsed };
50
- }
51
- // 4. No parser, not a select column, no built-in type — pass through unchanged
52
- return { valid: true, value: newValue };
53
- }
54
- // --- Built-in parser helpers ---
55
- // Consumers assign these to columns: { valueParser: numberParser }
56
- // Return `undefined` to reject; `null` to clear the cell.
57
- /**
58
- * Parses a value as a number. Strips whitespace and commas.
59
- * Returns `undefined` (reject) if result is NaN.
60
- */
61
- export function numberParser(params) {
62
- const { newValue } = params;
63
- if (newValue === '' || newValue == null)
64
- return null;
65
- const str = String(newValue).replace(/[\s,]/g, '');
66
- const num = Number(str);
67
- return Number.isNaN(num) ? undefined : num;
68
- }
69
- /**
70
- * Parses a currency string. Strips currency symbols ($, €, £, ¥), whitespace, commas.
71
- * Returns `undefined` (reject) if result is NaN.
72
- */
73
- export function currencyParser(params) {
74
- const { newValue } = params;
75
- if (newValue === '' || newValue == null)
76
- return null;
77
- const str = String(newValue)
78
- .replace(/[$\u20AC\u00A3\u00A5]/g, '') // $, €, £, ¥
79
- .replace(/[\s,]/g, '');
80
- const num = Number(str);
81
- return Number.isNaN(num) ? undefined : num;
82
- }
83
- /**
84
- * Parses a date string via `new Date()`. Returns ISO string or `undefined` if invalid.
85
- */
86
- export function dateParser(params) {
87
- const { newValue } = params;
88
- if (newValue === '' || newValue == null)
89
- return null;
90
- const str = String(newValue).trim();
91
- const date = new Date(str);
92
- if (Number.isNaN(date.getTime()))
93
- return undefined;
94
- return date.toISOString();
95
- }
96
- /**
97
- * Validates an email address with a basic regex.
98
- * Returns the trimmed string or `undefined` if invalid.
99
- */
100
- export function emailParser(params) {
101
- const { newValue } = params;
102
- if (newValue === '' || newValue == null)
103
- return null;
104
- const str = String(newValue).trim();
105
- return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str) ? str : undefined;
106
- }
107
- /**
108
- * Parses boolean-like values: true/false/yes/no/1/0.
109
- * Returns `undefined` if not recognized.
110
- */
111
- export function booleanParser(params) {
112
- const { newValue } = params;
113
- if (newValue === '' || newValue == null)
114
- return null;
115
- const str = String(newValue).trim().toLowerCase();
116
- if (['true', 'yes', '1'].includes(str))
117
- return true;
118
- if (['false', 'no', '0'].includes(str))
119
- return false;
120
- return undefined;
121
- }
@@ -1,46 +0,0 @@
1
- /**
2
- * Compute the range of rows that should be rendered for a given scroll position.
3
- *
4
- * @param scrollTop - Current vertical scroll offset (px)
5
- * @param rowHeight - Fixed height of each row (px)
6
- * @param containerHeight - Visible height of the scroll container (px)
7
- * @param totalRows - Total number of rows in the dataset
8
- * @param overscan - Number of extra rows to render above and below the visible area (default: 5)
9
- * @returns The visible range with start/end indices and top/bottom spacer offsets
10
- */
11
- export function computeVisibleRange(scrollTop, rowHeight, containerHeight, totalRows, overscan = 5) {
12
- if (totalRows <= 0 || rowHeight <= 0 || containerHeight <= 0) {
13
- return { startIndex: 0, endIndex: 0, offsetTop: 0, offsetBottom: 0 };
14
- }
15
- const startIndex = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
16
- const endIndex = Math.min(totalRows - 1, Math.ceil((scrollTop + containerHeight) / rowHeight) + overscan);
17
- const offsetTop = startIndex * rowHeight;
18
- const offsetBottom = Math.max(0, (totalRows - endIndex - 1) * rowHeight);
19
- return { startIndex, endIndex, offsetTop, offsetBottom };
20
- }
21
- /**
22
- * Compute the total scrollable height for all rows.
23
- */
24
- export function computeTotalHeight(totalRows, rowHeight) {
25
- return totalRows * rowHeight;
26
- }
27
- /**
28
- * Compute the scrollTop value needed to bring a specific row into view.
29
- *
30
- * @param rowIndex - The row to scroll to
31
- * @param rowHeight - Fixed height of each row (px)
32
- * @param containerHeight - Visible height of the scroll container (px)
33
- * @param align - Where to position the row: 'start' (top), 'center', or 'end' (bottom). Default: 'start'.
34
- * @returns The scrollTop value to set on the container
35
- */
36
- export function getScrollTopForRow(rowIndex, rowHeight, containerHeight, align = 'start') {
37
- const rowTop = rowIndex * rowHeight;
38
- switch (align) {
39
- case 'start':
40
- return rowTop;
41
- case 'center':
42
- return Math.max(0, rowTop - (containerHeight - rowHeight) / 2);
43
- case 'end':
44
- return Math.max(0, rowTop - containerHeight + rowHeight);
45
- }
46
- }