gp-grid-core 0.1.1 → 0.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.
package/README.md CHANGED
@@ -1,362 +1,423 @@
1
- # gp-grid-core
2
-
3
- A framework-agnostic TypeScript library for building high-performance data grids with virtual scrolling, supporting 150,000+ rows with ease.
4
-
5
- ## Philosophy
6
-
7
- **gp-grid-core** is built on three core principles:
8
-
9
- ### 1. Slot-Based Virtual Scrolling
10
-
11
- Instead of rendering all rows, the grid maintains a pool of reusable "slots" (DOM containers) that are recycled as users scroll. This approach:
12
-
13
- - Renders only visible rows plus a small overscan buffer
14
- - Recycles DOM elements instead of creating/destroying them
15
- - Maintains consistent performance regardless of dataset size
16
-
17
- ### 2. Instruction-Based Architecture
18
-
19
- The core emits declarative **instructions** (commands) that describe what the UI should do, rather than manipulating the DOM directly. This pattern:
20
-
21
- - Keeps the core framework-agnostic (works with React, Vue, Svelte, vanilla JS)
22
- - Enables batched updates for optimal rendering performance
23
- - Provides a clean separation between logic and presentation
24
-
25
- ### 3. DataSource Abstraction
26
-
27
- Data fetching is abstracted through a `DataSource` interface, supporting both:
28
-
29
- - **Client-side**: All data loaded in memory, with local sorting/filtering
30
- - **Server-side**: Data fetched on-demand from an API with server-side operations
31
-
32
- ## Installation
33
-
34
- npm/pnpm/yarn
35
-
36
- ```bash
37
- pnpm add gp-grid-core
38
- ```
39
-
40
- ## Architecture Overview
41
-
42
- ### GridCore
43
-
44
- The main orchestrator class that manages:
45
-
46
- - Viewport tracking and scroll synchronization
47
- - Slot pool lifecycle (create, assign, move, destroy)
48
- - Data fetching and caching
49
- - Sort and filter state
50
-
51
- ```typescript
52
- import { GridCore, createClientDataSource } from "gp-grid-core";
53
-
54
- const dataSource = createClientDataSource(myData);
55
-
56
- const grid = new GridCore({
57
- columns: [
58
- { field: "name", cellDataType: "text", width: 150 },
59
- { field: "age", cellDataType: "number", width: 80 },
60
- ],
61
- dataSource,
62
- rowHeight: 36,
63
- headerHeight: 40,
64
- overscan: 3,
65
- });
66
-
67
- // Subscribe to instructions
68
- grid.onBatchInstruction((instructions) => {
69
- // Handle UI updates based on instructions
70
- instructions.forEach((instruction) => {
71
- switch (instruction.type) {
72
- case "CREATE_SLOT":
73
- // Create a new row container
74
- break;
75
- case "ASSIGN_SLOT":
76
- // Assign row data to a slot
77
- break;
78
- case "MOVE_SLOT":
79
- // Position slot via translateY
80
- break;
81
- // ... handle other instructions
82
- }
83
- });
84
- });
85
-
86
- // Initialize and start
87
- await grid.initialize();
88
- ```
89
-
90
- ### Managers
91
-
92
- GridCore includes specialized managers for complex behaviors:
93
-
94
- - **SelectionManager**: Handles cell selection, range selection, keyboard navigation
95
- - **FillManager**: Implements Excel-like fill handle drag operations
96
-
97
- ### Instruction Types
98
-
99
- The core emits these instruction types:
100
-
101
- | Instruction | Description |
102
- |-------------|-------------|
103
- | `CREATE_SLOT` | Create a new slot in the DOM pool |
104
- | `DESTROY_SLOT` | Remove a slot from the pool |
105
- | `ASSIGN_SLOT` | Assign row data to a slot |
106
- | `MOVE_SLOT` | Update slot position (translateY) |
107
- | `SET_ACTIVE_CELL` | Update active cell highlight |
108
- | `SET_SELECTION_RANGE` | Update selection range |
109
- | `START_EDIT` / `STOP_EDIT` | Toggle edit mode |
110
- | `COMMIT_EDIT` | Commit edited value |
111
- | `UPDATE_HEADER` | Update header with sort state |
112
- | `DATA_LOADING` / `DATA_LOADED` / `DATA_ERROR` | Data fetch lifecycle |
113
-
114
- ## Data Sources
115
-
116
- ### Client-Side Data Source
117
-
118
- For datasets that can be loaded entirely in memory. Sorting and filtering are performed client-side.
119
-
120
- ```typescript
121
- import { createClientDataSource } from "gp-grid-core";
122
-
123
- interface Person {
124
- id: number;
125
- name: string;
126
- age: number;
127
- email: string;
128
- }
129
-
130
- const data: Person[] = [
131
- { id: 1, name: "Alice", age: 30, email: "alice@example.com" },
132
- { id: 2, name: "Bob", age: 25, email: "bob@example.com" },
133
- // ... more rows
134
- ];
135
-
136
- const dataSource = createClientDataSource(data);
137
- ```
138
-
139
- **With custom field accessor** (for nested properties):
140
-
141
- ```typescript
142
- const dataSource = createClientDataSource(data, {
143
- getFieldValue: (row, field) => {
144
- // Custom logic for accessing nested fields
145
- if (field === "address.city") {
146
- return row.address?.city;
147
- }
148
- return row[field];
149
- },
150
- });
151
- ```
152
-
153
- ### Server-Side Data Source
154
-
155
- For large datasets that require server-side pagination, sorting, and filtering.
156
-
157
- ```typescript
158
- import { createServerDataSource, DataSourceRequest, DataSourceResponse } from "gp-grid-core";
159
-
160
- interface Person {
161
- id: number;
162
- name: string;
163
- age: number;
164
- }
165
-
166
- const dataSource = createServerDataSource<Person>(async (request: DataSourceRequest) => {
167
- // Build query parameters from request
168
- const params = new URLSearchParams({
169
- page: String(request.pagination.pageIndex),
170
- pageSize: String(request.pagination.pageSize),
171
- });
172
-
173
- // Add sort parameters
174
- if (request.sort && request.sort.length > 0) {
175
- params.set("sortBy", request.sort.map(s => `${s.colId}:${s.direction}`).join(","));
176
- }
177
-
178
- // Add filter parameters
179
- if (request.filter) {
180
- Object.entries(request.filter).forEach(([field, value]) => {
181
- params.set(`filter_${field}`, value);
182
- });
183
- }
184
-
185
- // Fetch from your API
186
- const response = await fetch(`/api/people?${params}`);
187
- const data = await response.json();
188
-
189
- return {
190
- rows: data.items,
191
- totalRows: data.totalCount,
192
- };
193
- });
194
- ```
195
-
196
- ### DataSource Interface
197
-
198
- Both data source types implement this interface:
199
-
200
- ```typescript
201
- interface DataSource<TData = Row> {
202
- fetch(request: DataSourceRequest): Promise<DataSourceResponse<TData>>;
203
- }
204
-
205
- interface DataSourceRequest {
206
- pagination: {
207
- pageIndex: number;
208
- pageSize: number;
209
- };
210
- sort?: SortModel[];
211
- filter?: FilterModel;
212
- }
213
-
214
- interface DataSourceResponse<TData> {
215
- rows: TData[];
216
- totalRows: number;
217
- }
218
- ```
219
-
220
- ## Types Reference
221
-
222
- ### ColumnDefinition
223
-
224
- ```typescript
225
- interface ColumnDefinition {
226
- field: string; // Property path in row data
227
- colId?: string; // Unique column ID (defaults to field)
228
- cellDataType: CellDataType; // "text" | "number" | "boolean" | "date" | "object"
229
- width: number; // Column width in pixels
230
- headerName?: string; // Display name (defaults to field)
231
- editable?: boolean; // Enable cell editing
232
- cellRenderer?: string; // Custom renderer key
233
- editRenderer?: string; // Custom edit renderer key
234
- headerRenderer?: string; // Custom header renderer key
235
- }
236
- ```
237
-
238
- ### Renderer Params
239
-
240
- When building framework adapters, these params are passed to custom renderers:
241
-
242
- ```typescript
243
- interface CellRendererParams {
244
- value: CellValue;
245
- rowData: Row;
246
- column: ColumnDefinition;
247
- rowIndex: number;
248
- colIndex: number;
249
- isActive: boolean;
250
- isSelected: boolean;
251
- isEditing: boolean;
252
- }
253
-
254
- interface EditRendererParams extends CellRendererParams {
255
- initialValue: CellValue;
256
- onValueChange: (newValue: CellValue) => void;
257
- onCommit: () => void;
258
- onCancel: () => void;
259
- }
260
-
261
- interface HeaderRendererParams {
262
- column: ColumnDefinition;
263
- colIndex: number;
264
- sortDirection?: SortDirection;
265
- sortIndex?: number;
266
- onSort: (direction: SortDirection | null, addToExisting: boolean) => void;
267
- }
268
- ```
269
-
270
- ## Creating a Framework Adapter
271
-
272
- To integrate gp-grid-core with any UI framework:
273
-
274
- 1. **Subscribe to instructions** using `onBatchInstruction()`
275
- 2. **Maintain UI state** by processing instructions
276
- 3. **Render slots** based on the slot pool state
277
- 4. **Forward user interactions** back to GridCore
278
-
279
- ### Example: Minimal Adapter Pattern
280
-
281
- ```typescript
282
- import { GridCore, GridInstruction } from "gp-grid-core";
283
-
284
- class MyGridAdapter {
285
- private core: GridCore;
286
- private slots: Map<string, SlotUIElement> = new Map();
287
-
288
- constructor(options: GridCoreOptions) {
289
- this.core = new GridCore(options);
290
-
291
- // Process instructions to update UI
292
- this.core.onBatchInstruction((instructions) => {
293
- this.processInstructions(instructions);
294
- this.render();
295
- });
296
- }
297
-
298
- private processInstructions(instructions: GridInstruction[]) {
299
- for (const instr of instructions) {
300
- switch (instr.type) {
301
- case "CREATE_SLOT":
302
- this.slots.set(instr.slotId, this.createSlotElement());
303
- break;
304
- case "DESTROY_SLOT":
305
- this.slots.delete(instr.slotId);
306
- break;
307
- case "ASSIGN_SLOT":
308
- const slot = this.slots.get(instr.slotId);
309
- if (slot) {
310
- slot.rowIndex = instr.rowIndex;
311
- slot.rowData = instr.rowData;
312
- }
313
- break;
314
- case "MOVE_SLOT":
315
- const moveSlot = this.slots.get(instr.slotId);
316
- if (moveSlot) {
317
- moveSlot.translateY = instr.translateY;
318
- }
319
- break;
320
- }
321
- }
322
- }
323
-
324
- // Handle scroll events
325
- onScroll(scrollTop: number, scrollLeft: number, width: number, height: number) {
326
- this.core.setViewport(scrollTop, scrollLeft, width, height);
327
- }
328
-
329
- // Handle cell click
330
- onCellClick(row: number, col: number, modifiers: { shift: boolean; ctrl: boolean }) {
331
- this.core.selection.startSelection({ row, col }, modifiers);
332
- }
333
-
334
- async initialize() {
335
- await this.core.initialize();
336
- }
337
- }
338
- ```
339
-
340
- ## API Reference
341
-
342
- ### GridCore Methods
343
-
344
- | Method | Description |
345
- |--------|-------------|
346
- | `initialize()` | Initialize grid and load initial data |
347
- | `setViewport(scrollTop, scrollLeft, width, height)` | Update viewport on scroll/resize |
348
- | `setSort(colId, direction, addToExisting)` | Set column sort |
349
- | `setFilter(colId, value)` | Set column filter |
350
- | `startEdit(row, col)` | Start editing a cell |
351
- | `commitEdit()` | Commit current edit |
352
- | `cancelEdit()` | Cancel current edit |
353
- | `refresh()` | Refetch data from source |
354
- | `getRowCount()` | Get total row count |
355
- | `getRowData(rowIndex)` | Get data for a specific row |
356
-
357
- ### GridCore Properties
358
-
359
- | Property | Description |
360
- |----------|-------------|
361
- | `selection` | SelectionManager instance |
362
- | `fill` | FillManager instance |
1
+ # gp-grid-core 🏁 🏎️
2
+
3
+ A framework-agnostic TypeScript library for building high-performance data grids with high (millions) number of rows with ease.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Philosophy](#philosophy)
8
+ - [Installation](#installation)
9
+ - [Architecture Overview](#architecture-overview)
10
+ - [Data Sources](#data-sources)
11
+ - [Types Reference](#types-reference)
12
+ - [Creating a Framework Adapter](#creating-a-framework-adapter)
13
+ - [API Reference](#api-reference)
14
+ - [Donations](#donations)
15
+
16
+ ## Available implementations
17
+
18
+ - [**gp-grid-react**](https://www.npmjs.com/package/gp-grid-react) | Official
19
+
20
+ ## Philosophy
21
+
22
+ **gp-grid-core** is built on three core principles:
23
+
24
+ ### 1. Slot-Based Virtual Scrolling
25
+
26
+ Instead of rendering all rows, the grid maintains a pool of reusable "slots" (DOM containers) that are recycled as users scroll. This approach:
27
+
28
+ - Renders only visible rows plus a small overscan buffer
29
+ - Recycles DOM elements instead of creating/destroying them
30
+ - Maintains consistent performance regardless of dataset size
31
+
32
+ ### 2. Instruction-Based Architecture
33
+
34
+ The core emits declarative **instructions** (commands) that describe what the UI should do, rather than manipulating the DOM directly. This pattern:
35
+
36
+ - Keeps the core framework-agnostic (works with React, Vue, Svelte, vanilla JS)
37
+ - Enables batched updates for optimal rendering performance
38
+ - Provides a clean separation between logic and presentation
39
+
40
+ ### 3. DataSource Abstraction
41
+
42
+ Data fetching is abstracted through a `DataSource` interface, supporting both:
43
+
44
+ - **Client-side**: All data loaded in memory, with local sorting/filtering
45
+ - **Server-side**: Data fetched on-demand from an API with server-side operations
46
+
47
+ ## Installation
48
+
49
+ npm/pnpm/yarn
50
+
51
+ ```bash
52
+ pnpm add gp-grid-core
53
+ ```
54
+
55
+ ## Architecture Overview
56
+
57
+ ### GridCore
58
+
59
+ The main orchestrator class that manages:
60
+
61
+ - Viewport tracking and scroll synchronization
62
+ - Slot pool lifecycle (create, assign, move, destroy)
63
+ - Data fetching and caching
64
+ - Sort and filter state
65
+
66
+ ```typescript
67
+ import { GridCore, createClientDataSource } from "gp-grid-core";
68
+
69
+ const dataSource = createClientDataSource(myData);
70
+
71
+ const grid = new GridCore({
72
+ columns: [
73
+ { field: "name", cellDataType: "text", width: 150 },
74
+ { field: "age", cellDataType: "number", width: 80 },
75
+ ],
76
+ dataSource,
77
+ rowHeight: 36,
78
+ headerHeight: 40,
79
+ overscan: 3,
80
+ });
81
+
82
+ // Subscribe to instructions
83
+ grid.onBatchInstruction((instructions) => {
84
+ // Handle UI updates based on instructions
85
+ instructions.forEach((instruction) => {
86
+ switch (instruction.type) {
87
+ case "CREATE_SLOT":
88
+ // Create a new row container
89
+ break;
90
+ case "ASSIGN_SLOT":
91
+ // Assign row data to a slot
92
+ break;
93
+ case "MOVE_SLOT":
94
+ // Position slot via translateY
95
+ break;
96
+ // ... handle other instructions
97
+ }
98
+ });
99
+ });
100
+
101
+ // Initialize and start
102
+ await grid.initialize();
103
+ ```
104
+
105
+ ### Managers
106
+
107
+ GridCore includes specialized managers for complex behaviors:
108
+
109
+ - **SelectionManager**: Handles cell selection, range selection, keyboard navigation
110
+ - **FillManager**: Implements Excel-like fill handle drag operations
111
+
112
+ ### Instruction Types
113
+
114
+ The core emits these instruction types:
115
+
116
+ | Instruction | Description |
117
+ | --------------------------------------------- | --------------------------------- |
118
+ | `CREATE_SLOT` | Create a new slot in the DOM pool |
119
+ | `DESTROY_SLOT` | Remove a slot from the pool |
120
+ | `ASSIGN_SLOT` | Assign row data to a slot |
121
+ | `MOVE_SLOT` | Update slot position (translateY) |
122
+ | `SET_ACTIVE_CELL` | Update active cell highlight |
123
+ | `SET_SELECTION_RANGE` | Update selection range |
124
+ | `START_EDIT` / `STOP_EDIT` | Toggle edit mode |
125
+ | `COMMIT_EDIT` | Commit edited value |
126
+ | `UPDATE_HEADER` | Update header with sort state |
127
+ | `DATA_LOADING` / `DATA_LOADED` / `DATA_ERROR` | Data fetch lifecycle |
128
+
129
+ ## Data Sources
130
+
131
+ ### Client-Side Data Source
132
+
133
+ For datasets that can be loaded entirely in memory. Sorting and filtering are performed client-side.
134
+
135
+ ```typescript
136
+ import { createClientDataSource } from "gp-grid-core";
137
+
138
+ interface Person {
139
+ id: number;
140
+ name: string;
141
+ age: number;
142
+ email: string;
143
+ }
144
+
145
+ const data: Person[] = [
146
+ { id: 1, name: "Alice", age: 30, email: "alice@example.com" },
147
+ { id: 2, name: "Bob", age: 25, email: "bob@example.com" },
148
+ // ... more rows
149
+ ];
150
+
151
+ const dataSource = createClientDataSource(data);
152
+ ```
153
+
154
+ **With custom field accessor** (for nested properties):
155
+
156
+ ```typescript
157
+ const dataSource = createClientDataSource(data, {
158
+ getFieldValue: (row, field) => {
159
+ // Custom logic for accessing nested fields
160
+ if (field === "address.city") {
161
+ return row.address?.city;
162
+ }
163
+ return row[field];
164
+ },
165
+ });
166
+ ```
167
+
168
+ ### Server-Side Data Source
169
+
170
+ For large datasets that require server-side pagination, sorting, and filtering.
171
+
172
+ ```typescript
173
+ import {
174
+ createServerDataSource,
175
+ DataSourceRequest,
176
+ DataSourceResponse,
177
+ } from "gp-grid-core";
178
+
179
+ interface Person {
180
+ id: number;
181
+ name: string;
182
+ age: number;
183
+ }
184
+
185
+ const dataSource = createServerDataSource<Person>(
186
+ async (request: DataSourceRequest) => {
187
+ // Build query parameters from request
188
+ const params = new URLSearchParams({
189
+ page: String(request.pagination.pageIndex),
190
+ pageSize: String(request.pagination.pageSize),
191
+ });
192
+
193
+ // Add sort parameters
194
+ if (request.sort && request.sort.length > 0) {
195
+ params.set(
196
+ "sortBy",
197
+ request.sort.map((s) => `${s.colId}:${s.direction}`).join(","),
198
+ );
199
+ }
200
+
201
+ // Add filter parameters
202
+ if (request.filter) {
203
+ Object.entries(request.filter).forEach(([field, value]) => {
204
+ params.set(`filter_${field}`, value);
205
+ });
206
+ }
207
+
208
+ // Fetch from your API
209
+ const response = await fetch(`/api/people?${params}`);
210
+ const data = await response.json();
211
+
212
+ return {
213
+ rows: data.items,
214
+ totalRows: data.totalCount,
215
+ };
216
+ },
217
+ );
218
+ ```
219
+
220
+ ### DataSource Interface
221
+
222
+ Both data source types implement this interface:
223
+
224
+ ```typescript
225
+ interface DataSource<TData = Row> {
226
+ fetch(request: DataSourceRequest): Promise<DataSourceResponse<TData>>;
227
+ }
228
+
229
+ interface DataSourceRequest {
230
+ pagination: {
231
+ pageIndex: number;
232
+ pageSize: number;
233
+ };
234
+ sort?: SortModel[];
235
+ filter?: FilterModel;
236
+ }
237
+
238
+ interface DataSourceResponse<TData> {
239
+ rows: TData[];
240
+ totalRows: number;
241
+ }
242
+ ```
243
+
244
+ ## Types Reference
245
+
246
+ ### ColumnDefinition
247
+
248
+ ```typescript
249
+ interface ColumnDefinition {
250
+ field: string; // Property path in row data
251
+ colId?: string; // Unique column ID (defaults to field)
252
+ cellDataType: CellDataType; // "text" | "number" | "boolean" | "date" | "object"
253
+ width: number; // Column width in pixels
254
+ headerName?: string; // Display name (defaults to field)
255
+ editable?: boolean; // Enable cell editing
256
+ cellRenderer?: string; // Custom renderer key
257
+ editRenderer?: string; // Custom edit renderer key
258
+ headerRenderer?: string; // Custom header renderer key
259
+ }
260
+ ```
261
+
262
+ ### Renderer Params
263
+
264
+ When building framework adapters, these params are passed to custom renderers:
265
+
266
+ ```typescript
267
+ interface CellRendererParams {
268
+ value: CellValue;
269
+ rowData: Row;
270
+ column: ColumnDefinition;
271
+ rowIndex: number;
272
+ colIndex: number;
273
+ isActive: boolean;
274
+ isSelected: boolean;
275
+ isEditing: boolean;
276
+ }
277
+
278
+ interface EditRendererParams extends CellRendererParams {
279
+ initialValue: CellValue;
280
+ onValueChange: (newValue: CellValue) => void;
281
+ onCommit: () => void;
282
+ onCancel: () => void;
283
+ }
284
+
285
+ interface HeaderRendererParams {
286
+ column: ColumnDefinition;
287
+ colIndex: number;
288
+ sortDirection?: SortDirection;
289
+ sortIndex?: number;
290
+ onSort: (direction: SortDirection | null, addToExisting: boolean) => void;
291
+ }
292
+ ```
293
+
294
+ ## Creating a Framework Adapter
295
+
296
+ To integrate gp-grid-core with any UI framework:
297
+
298
+ 1. **Subscribe to instructions** using `onBatchInstruction()`
299
+ 2. **Maintain UI state** by processing instructions
300
+ 3. **Render slots** based on the slot pool state
301
+ 4. **Forward user interactions** back to GridCore
302
+
303
+ ### Example: Minimal Adapter Pattern
304
+
305
+ ```typescript
306
+ import { GridCore, GridInstruction } from "gp-grid-core";
307
+
308
+ class MyGridAdapter {
309
+ private core: GridCore;
310
+ private slots: Map<string, SlotUIElement> = new Map();
311
+
312
+ constructor(options: GridCoreOptions) {
313
+ this.core = new GridCore(options);
314
+
315
+ // Process instructions to update UI
316
+ this.core.onBatchInstruction((instructions) => {
317
+ this.processInstructions(instructions);
318
+ this.render();
319
+ });
320
+ }
321
+
322
+ private processInstructions(instructions: GridInstruction[]) {
323
+ for (const instr of instructions) {
324
+ switch (instr.type) {
325
+ case "CREATE_SLOT":
326
+ this.slots.set(instr.slotId, this.createSlotElement());
327
+ break;
328
+ case "DESTROY_SLOT":
329
+ this.slots.delete(instr.slotId);
330
+ break;
331
+ case "ASSIGN_SLOT":
332
+ const slot = this.slots.get(instr.slotId);
333
+ if (slot) {
334
+ slot.rowIndex = instr.rowIndex;
335
+ slot.rowData = instr.rowData;
336
+ }
337
+ break;
338
+ case "MOVE_SLOT":
339
+ const moveSlot = this.slots.get(instr.slotId);
340
+ if (moveSlot) {
341
+ moveSlot.translateY = instr.translateY;
342
+ }
343
+ break;
344
+ }
345
+ }
346
+ }
347
+
348
+ // Handle scroll events
349
+ onScroll(
350
+ scrollTop: number,
351
+ scrollLeft: number,
352
+ width: number,
353
+ height: number,
354
+ ) {
355
+ this.core.setViewport(scrollTop, scrollLeft, width, height);
356
+ }
357
+
358
+ // Handle cell click
359
+ onCellClick(
360
+ row: number,
361
+ col: number,
362
+ modifiers: { shift: boolean; ctrl: boolean },
363
+ ) {
364
+ this.core.selection.startSelection({ row, col }, modifiers);
365
+ }
366
+
367
+ async initialize() {
368
+ await this.core.initialize();
369
+ }
370
+ }
371
+ ```
372
+
373
+ ## API Reference
374
+
375
+ ### GridCore Methods
376
+
377
+ | Method | Description |
378
+ | --------------------------------------------------- | ------------------------------------- |
379
+ | `initialize()` | Initialize grid and load initial data |
380
+ | `setViewport(scrollTop, scrollLeft, width, height)` | Update viewport on scroll/resize |
381
+ | `setSort(colId, direction, addToExisting)` | Set column sort |
382
+ | `setFilter(colId, value)` | Set column filter |
383
+ | `startEdit(row, col)` | Start editing a cell |
384
+ | `commitEdit()` | Commit current edit |
385
+ | `cancelEdit()` | Cancel current edit |
386
+ | `refresh()` | Refetch data from source |
387
+ | `getRowCount()` | Get total row count |
388
+ | `getRowData(rowIndex)` | Get data for a specific row |
389
+
390
+ ### GridCore Properties
391
+
392
+ | Property | Description |
393
+ | ----------- | ------------------------- |
394
+ | `selection` | SelectionManager instance |
395
+ | `fill` | FillManager instance |
396
+
397
+ ## Donations
398
+
399
+ Keeping this library requires effort and passion, I'm a full time engineer employed on other project and I'm trying my best to keep this work free! For all the features.
400
+
401
+ If you think this project helped you achieve your goals, it's hopefully worth a beer! 🍻
402
+
403
+ <div align="center">
404
+
405
+ ### Paypal
406
+
407
+ [![Paypal QR Code](../../public/images/donazione_paypal.png "Paypal QR Code donation")](https://www.paypal.com/donate/?hosted_button_id=XCNMG6BR4ZMLY)
408
+
409
+ [https://www.paypal.com/donate/?hosted_button_id=XCNMG6BR4ZMLY](https://www.paypal.com/donate/?hosted_button_id=XCNMG6BR4ZMLY)
410
+
411
+ ### Bitcoin
412
+
413
+ [![Bitcoin QR Donation](../../public/images/bc1qcukwmzver59eyqq442xyzscmxavqjt568kkc9m.png "Bitcoin QR Donation")](bitcoin:bc1qcukwmzver59eyqq442xyzscmxavqjt568kkc9m)
414
+
415
+ bitcoin:bc1qcukwmzver59eyqq442xyzscmxavqjt568kkc9m
416
+
417
+ ### Lightning Network
418
+
419
+ [![Lightning Network QR Donation](../../public/images/lightning.png "Lightning Network QR Donation")](lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhhx6rpvanhjetdvfjhyvf4xs0xu5p7)
420
+
421
+ lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhhx6rpvanhjetdvfjhyvf4xs0xu5p7
422
+
423
+ </div>