gp-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.
@@ -0,0 +1,422 @@
1
+ //#region src/types.d.ts
2
+ type CellDataType = "text" | "number" | "boolean" | "date" | "dateString" | "dateTime" | "dateTimeString" | "object";
3
+ type CellValue = string | number | boolean | Date | object | null;
4
+ type Row = unknown;
5
+ type SortDirection = "asc" | "desc";
6
+ type SortModel = {
7
+ colId: string;
8
+ direction: SortDirection;
9
+ };
10
+ type FilterModel = Record<string, string>;
11
+ interface ColumnDefinition {
12
+ field: string;
13
+ colId?: string;
14
+ cellDataType: CellDataType;
15
+ width: number;
16
+ headerName?: string;
17
+ editable?: boolean;
18
+ /** Renderer key for adapter lookup, or inline renderer function */
19
+ cellRenderer?: string;
20
+ editRenderer?: string;
21
+ headerRenderer?: string;
22
+ }
23
+ interface CellPosition {
24
+ row: number;
25
+ col: number;
26
+ }
27
+ interface CellRange {
28
+ startRow: number;
29
+ startCol: number;
30
+ endRow: number;
31
+ endCol: number;
32
+ }
33
+ interface SelectionState {
34
+ activeCell: CellPosition | null;
35
+ range: CellRange | null;
36
+ /** Anchor cell for shift-extend selection */
37
+ anchor: CellPosition | null;
38
+ /** Whether selection mode is active (ctrl held) */
39
+ selectionMode: boolean;
40
+ }
41
+ interface EditState {
42
+ row: number;
43
+ col: number;
44
+ initialValue: CellValue;
45
+ currentValue: CellValue;
46
+ }
47
+ interface FillHandleState {
48
+ sourceRange: CellRange;
49
+ targetRow: number;
50
+ targetCol: number;
51
+ }
52
+ interface SlotState {
53
+ slotId: string;
54
+ rowIndex: number;
55
+ rowData: Row;
56
+ translateY: number;
57
+ }
58
+ interface DataSourceRequest {
59
+ pagination: {
60
+ pageIndex: number;
61
+ pageSize: number;
62
+ };
63
+ sort?: SortModel[];
64
+ filter?: FilterModel;
65
+ }
66
+ interface DataSourceResponse<TData = Row> {
67
+ rows: TData[];
68
+ totalRows: number;
69
+ }
70
+ interface DataSource<TData = Row> {
71
+ fetch(request: DataSourceRequest): Promise<DataSourceResponse<TData>>;
72
+ }
73
+ interface CreateSlotInstruction {
74
+ type: "CREATE_SLOT";
75
+ slotId: string;
76
+ }
77
+ interface DestroySlotInstruction {
78
+ type: "DESTROY_SLOT";
79
+ slotId: string;
80
+ }
81
+ interface AssignSlotInstruction {
82
+ type: "ASSIGN_SLOT";
83
+ slotId: string;
84
+ rowIndex: number;
85
+ rowData: Row;
86
+ }
87
+ interface MoveSlotInstruction {
88
+ type: "MOVE_SLOT";
89
+ slotId: string;
90
+ translateY: number;
91
+ }
92
+ interface SetActiveCellInstruction {
93
+ type: "SET_ACTIVE_CELL";
94
+ position: CellPosition | null;
95
+ }
96
+ interface SetSelectionRangeInstruction {
97
+ type: "SET_SELECTION_RANGE";
98
+ range: CellRange | null;
99
+ }
100
+ interface StartEditInstruction {
101
+ type: "START_EDIT";
102
+ row: number;
103
+ col: number;
104
+ initialValue: CellValue;
105
+ }
106
+ interface StopEditInstruction {
107
+ type: "STOP_EDIT";
108
+ }
109
+ interface CommitEditInstruction {
110
+ type: "COMMIT_EDIT";
111
+ row: number;
112
+ col: number;
113
+ value: CellValue;
114
+ }
115
+ interface SetContentSizeInstruction {
116
+ type: "SET_CONTENT_SIZE";
117
+ width: number;
118
+ height: number;
119
+ }
120
+ interface UpdateHeaderInstruction {
121
+ type: "UPDATE_HEADER";
122
+ colIndex: number;
123
+ column: ColumnDefinition;
124
+ sortDirection?: SortDirection;
125
+ sortIndex?: number;
126
+ }
127
+ interface StartFillInstruction {
128
+ type: "START_FILL";
129
+ sourceRange: CellRange;
130
+ }
131
+ interface UpdateFillInstruction {
132
+ type: "UPDATE_FILL";
133
+ targetRow: number;
134
+ targetCol: number;
135
+ }
136
+ interface CommitFillInstruction {
137
+ type: "COMMIT_FILL";
138
+ filledCells: Array<{
139
+ row: number;
140
+ col: number;
141
+ value: CellValue;
142
+ }>;
143
+ }
144
+ interface CancelFillInstruction {
145
+ type: "CANCEL_FILL";
146
+ }
147
+ interface DataLoadingInstruction {
148
+ type: "DATA_LOADING";
149
+ }
150
+ interface DataLoadedInstruction {
151
+ type: "DATA_LOADED";
152
+ totalRows: number;
153
+ }
154
+ interface DataErrorInstruction {
155
+ type: "DATA_ERROR";
156
+ error: string;
157
+ }
158
+ type GridInstruction = CreateSlotInstruction | DestroySlotInstruction | AssignSlotInstruction | MoveSlotInstruction | SetActiveCellInstruction | SetSelectionRangeInstruction | StartEditInstruction | StopEditInstruction | CommitEditInstruction | SetContentSizeInstruction | UpdateHeaderInstruction | StartFillInstruction | UpdateFillInstruction | CommitFillInstruction | CancelFillInstruction | DataLoadingInstruction | DataLoadedInstruction | DataErrorInstruction;
159
+ interface GridCoreOptions<TData = Row> {
160
+ columns: ColumnDefinition[];
161
+ dataSource: DataSource<TData>;
162
+ rowHeight: number;
163
+ headerHeight?: number;
164
+ overscan?: number;
165
+ }
166
+ interface CellRendererParams {
167
+ value: CellValue;
168
+ rowData: Row;
169
+ column: ColumnDefinition;
170
+ rowIndex: number;
171
+ colIndex: number;
172
+ isActive: boolean;
173
+ isSelected: boolean;
174
+ isEditing: boolean;
175
+ }
176
+ interface EditRendererParams extends CellRendererParams {
177
+ initialValue: CellValue;
178
+ onValueChange: (newValue: CellValue) => void;
179
+ onCommit: () => void;
180
+ onCancel: () => void;
181
+ }
182
+ interface HeaderRendererParams {
183
+ column: ColumnDefinition;
184
+ colIndex: number;
185
+ sortDirection?: SortDirection;
186
+ sortIndex?: number;
187
+ onSort: (direction: SortDirection | null, addToExisting: boolean) => void;
188
+ }
189
+ type InstructionListener = (instruction: GridInstruction) => void;
190
+ type BatchInstructionListener = (instructions: GridInstruction[]) => void;
191
+ //#endregion
192
+ //#region src/selection.d.ts
193
+ type Direction = "up" | "down" | "left" | "right";
194
+ interface SelectionManagerOptions {
195
+ getRowCount: () => number;
196
+ getColumnCount: () => number;
197
+ getCellValue: (row: number, col: number) => CellValue;
198
+ getRowData: (row: number) => Row | undefined;
199
+ getColumn: (col: number) => ColumnDefinition | undefined;
200
+ }
201
+ /**
202
+ * Manages Excel-style cell selection, keyboard navigation, and clipboard operations.
203
+ */
204
+ declare class SelectionManager {
205
+ private state;
206
+ private options;
207
+ private listeners;
208
+ constructor(options: SelectionManagerOptions);
209
+ onInstruction(listener: InstructionListener): () => void;
210
+ private emit;
211
+ getState(): SelectionState;
212
+ getActiveCell(): CellPosition | null;
213
+ getSelectionRange(): CellRange | null;
214
+ isSelected(row: number, col: number): boolean;
215
+ isActiveCell(row: number, col: number): boolean;
216
+ /**
217
+ * Start a selection at the given cell.
218
+ * @param cell - The cell to select
219
+ * @param opts.shift - Extend selection from anchor (range select)
220
+ * @param opts.ctrl - Toggle selection mode
221
+ */
222
+ startSelection(cell: CellPosition, opts?: {
223
+ shift?: boolean;
224
+ ctrl?: boolean;
225
+ }): void;
226
+ /**
227
+ * Move focus in a direction, optionally extending the selection.
228
+ */
229
+ moveFocus(direction: Direction, extend?: boolean): void;
230
+ /**
231
+ * Select all cells in the grid (Ctrl+A).
232
+ */
233
+ selectAll(): void;
234
+ /**
235
+ * Clear the current selection.
236
+ */
237
+ clearSelection(): void;
238
+ /**
239
+ * Set the active cell directly.
240
+ */
241
+ setActiveCell(row: number, col: number): void;
242
+ /**
243
+ * Set the selection range directly.
244
+ */
245
+ setSelectionRange(range: CellRange): void;
246
+ /**
247
+ * Get the data from the currently selected cells as a 2D array.
248
+ */
249
+ getSelectedData(): CellValue[][];
250
+ /**
251
+ * Copy the selected data to the clipboard (Ctrl+C).
252
+ */
253
+ copySelectionToClipboard(): Promise<void>;
254
+ private clampPosition;
255
+ }
256
+ //#endregion
257
+ //#region src/fill.d.ts
258
+ interface FillManagerOptions {
259
+ getRowCount: () => number;
260
+ getColumnCount: () => number;
261
+ getCellValue: (row: number, col: number) => CellValue;
262
+ getColumn: (col: number) => ColumnDefinition | undefined;
263
+ setCellValue: (row: number, col: number, value: CellValue) => void;
264
+ }
265
+ /**
266
+ * Manages fill handle operations including pattern detection and auto-fill.
267
+ */
268
+ declare class FillManager {
269
+ private state;
270
+ private options;
271
+ private listeners;
272
+ constructor(options: FillManagerOptions);
273
+ onInstruction(listener: InstructionListener): () => void;
274
+ private emit;
275
+ getState(): FillHandleState | null;
276
+ isActive(): boolean;
277
+ /**
278
+ * Start a fill drag operation from a source range.
279
+ */
280
+ startFillDrag(sourceRange: CellRange): void;
281
+ /**
282
+ * Update the fill drag target position.
283
+ */
284
+ updateFillDrag(targetRow: number, targetCol: number): void;
285
+ /**
286
+ * Commit the fill operation - apply pattern to target cells.
287
+ */
288
+ commitFillDrag(): void;
289
+ /**
290
+ * Cancel the fill operation.
291
+ */
292
+ cancelFillDrag(): void;
293
+ /**
294
+ * Calculate the values to fill based on source pattern.
295
+ */
296
+ private calculateFilledCells;
297
+ private getSourceColumnValues;
298
+ private getSourceRowValues;
299
+ private detectPattern;
300
+ private applyPattern;
301
+ }
302
+ //#endregion
303
+ //#region src/grid-core.d.ts
304
+ declare class GridCore<TData extends Row = Row> {
305
+ private columns;
306
+ private dataSource;
307
+ private rowHeight;
308
+ private headerHeight;
309
+ private overscan;
310
+ private scrollTop;
311
+ private scrollLeft;
312
+ private viewportWidth;
313
+ private viewportHeight;
314
+ private cachedRows;
315
+ private totalRows;
316
+ private currentPageIndex;
317
+ private pageSize;
318
+ private sortModel;
319
+ private filterModel;
320
+ private slotPool;
321
+ readonly selection: SelectionManager;
322
+ readonly fill: FillManager;
323
+ private editState;
324
+ private columnPositions;
325
+ private listeners;
326
+ private batchListeners;
327
+ constructor(options: GridCoreOptions<TData>);
328
+ onInstruction(listener: InstructionListener): () => void;
329
+ /**
330
+ * Subscribe to batched instructions for efficient React state updates.
331
+ * Batch listeners receive arrays of instructions instead of individual ones.
332
+ */
333
+ onBatchInstruction(listener: BatchInstructionListener): () => void;
334
+ private emit;
335
+ private emitBatch;
336
+ /**
337
+ * Initialize the grid and load initial data.
338
+ */
339
+ initialize(): Promise<void>;
340
+ /**
341
+ * Update viewport measurements and sync slots.
342
+ */
343
+ setViewport(scrollTop: number, scrollLeft: number, width: number, height: number): void;
344
+ /**
345
+ * Synchronize slots with current viewport position.
346
+ * This implements the slot recycling strategy.
347
+ */
348
+ private syncSlots;
349
+ private destroyAllSlots;
350
+ private getRowTranslateY;
351
+ private fetchData;
352
+ private fetchAllData;
353
+ setSort(colId: string, direction: SortDirection | null, addToExisting?: boolean): Promise<void>;
354
+ setFilter(colId: string, value: string): Promise<void>;
355
+ /**
356
+ * Force refresh all slot data (used after filtering/sorting when data changes)
357
+ */
358
+ private refreshAllSlots;
359
+ getSortModel(): SortModel[];
360
+ getFilterModel(): FilterModel;
361
+ startEdit(row: number, col: number): void;
362
+ updateEditValue(value: CellValue): void;
363
+ commitEdit(): void;
364
+ cancelEdit(): void;
365
+ getEditState(): EditState | null;
366
+ getCellValue(row: number, col: number): CellValue;
367
+ setCellValue(row: number, col: number, value: CellValue): void;
368
+ private getFieldValue;
369
+ private setFieldValue;
370
+ private computeColumnPositions;
371
+ private emitContentSize;
372
+ private emitHeaders;
373
+ getColumns(): ColumnDefinition[];
374
+ getColumnPositions(): number[];
375
+ getRowCount(): number;
376
+ getRowHeight(): number;
377
+ getHeaderHeight(): number;
378
+ getTotalWidth(): number;
379
+ getTotalHeight(): number;
380
+ getRowData(rowIndex: number): TData | undefined;
381
+ /**
382
+ * Refresh data from the data source.
383
+ */
384
+ refresh(): Promise<void>;
385
+ /**
386
+ * Refresh slot display without refetching data.
387
+ * Useful after in-place data modifications like fill operations.
388
+ */
389
+ refreshSlotData(): void;
390
+ /**
391
+ * Update the data source and refresh.
392
+ */
393
+ setDataSource(dataSource: DataSource<TData>): Promise<void>;
394
+ /**
395
+ * Update columns and recompute layout.
396
+ */
397
+ setColumns(columns: ColumnDefinition[]): void;
398
+ }
399
+ //#endregion
400
+ //#region src/data-source.d.ts
401
+ /**
402
+ * Creates a client-side data source that holds all data in memory.
403
+ * Sorting and filtering are performed client-side.
404
+ */
405
+ declare function createClientDataSource<TData extends Row = Row>(data: TData[], options?: {
406
+ /** Custom field accessor for nested properties */
407
+ getFieldValue?: (row: TData, field: string) => CellValue;
408
+ }): DataSource<TData>;
409
+ type ServerFetchFunction<TData> = (request: DataSourceRequest) => Promise<DataSourceResponse<TData>>;
410
+ /**
411
+ * Creates a server-side data source that delegates all operations to the server.
412
+ * The fetch function receives sort/filter/pagination params to pass to the API.
413
+ */
414
+ declare function createServerDataSource<TData extends Row = Row>(fetchFn: ServerFetchFunction<TData>): DataSource<TData>;
415
+ /**
416
+ * Convenience function to create a data source from an array.
417
+ * This provides backwards compatibility with the old `rowData` prop.
418
+ */
419
+ declare function createDataSourceFromArray<TData extends Row = Row>(data: TData[]): DataSource<TData>;
420
+ //#endregion
421
+ export { type AssignSlotInstruction, type BatchInstructionListener, type CancelFillInstruction, type CellDataType, type CellPosition, type CellRange, type CellRendererParams, type CellValue, type ColumnDefinition, type CommitEditInstruction, type CommitFillInstruction, type CreateSlotInstruction, type DataErrorInstruction, type DataLoadedInstruction, type DataLoadingInstruction, type DataSource, type DataSourceRequest, type DataSourceResponse, type DestroySlotInstruction, type Direction, type EditRendererParams, type EditState, type FillHandleState, FillManager, type FilterModel, GridCore, type GridCoreOptions, type GridInstruction, type HeaderRendererParams, type InstructionListener, type MoveSlotInstruction, type Row, SelectionManager, type SelectionState, type SetActiveCellInstruction, type SetContentSizeInstruction, type SetSelectionRangeInstruction, type SlotState, type SortDirection, type SortModel, type StartEditInstruction, type StartFillInstruction, type StopEditInstruction, type UpdateFillInstruction, type UpdateHeaderInstruction, createClientDataSource, createDataSourceFromArray, createServerDataSource };
422
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/selection.ts","../src/fill.ts","../src/grid-core.ts","../src/data-source.ts"],"sourcesContent":[],"mappings":";KAMY,YAAA;AAAA,KAUA,SAAA,GAVY,MAAA,GAAA,MAAA,GAAA,OAAA,GAU4B,IAV5B,GAAA,MAAA,GAAA,IAAA;AAUZ,KACA,GAAA,GADS,OAAA;AACT,KAEA,aAAA,GAFG,KAAA,GAAA,MAAA;AAEH,KACA,SAAA,GADa;EACb,KAAA,EAAA,MAAS;EACT,SAAA,EADwC,aAC7B;AAMvB,CAAA;AAiBiB,KAvBL,WAAA,GAAc,MAuBG,CAAA,MAAA,EAAA,MAAA,CAAA;AAKZ,UAtBA,gBAAA,CAsBS;EAWT,KAAA,EAAA,MAAA;EACH,KAAA,CAAA,EAAA,MAAA;EACL,YAAA,EAhCO,YAgCP;EAEC,KAAA,EAAA,MAAA;EAAY,UAAA,CAAA,EAAA,MAAA;EASL,QAAA,CAAA,EAAA,OAAS;EAWT;EAUA,YAAS,CAAA,EAAA,MAAA;EAWT,YAAA,CAAA,EAAA,MAAiB;EASjB,cAAA,CAAA,EAAA,MAAkB;AAKnC;AAAoC,UA3EnB,YAAA,CA2EmB;EACnB,GAAA,EAAA,MAAA;EAA+C,GAAA,EAAA,MAAA;;AAA3B,UAvEpB,SAAA,CAuEoB;EAAO,QAAA,EAAA,MAAA;EAQ3B,QAAA,EAAA,MAAA;EAKA,MAAA,EAAA,MAAA;EAKA,MAAA,EAAA,MAAA;AAOjB;AAOiB,UA5FA,cAAA,CA4FwB;EAKxB,UAAA,EAhGH,YAgGG,GAAA,IAA4B;EAM5B,KAAA,EArGR,SAqGQ,GAAA,IAAoB;EAOpB;EAIA,MAAA,EA9GP,YA8GO,GAAA,IAAqB;EAQrB;EAMA,aAAA,EAAA,OAAA;AASjB;AAKiB,UAjIA,SAAA,CAiIA;EAMA,GAAA,EAAA,MAAA;EAKA,GAAA,EAAA,MAAA;EAKA,YAAA,EA9ID,SA8IC;EAIA,YAAA,EAjJD,SAiJC;AAKjB;AAMY,UArJK,eAAA,CAqJU;EAEvB,WAAA,EAtJW,SAsJX;EACA,SAAA,EAAA,MAAA;EACA,SAAA,EAAA,MAAA;;AAGA,UAlJa,SAAA,CAkJb;EACA,MAAA,EAAA,MAAA;EAEA,QAAA,EAAA,MAAA;EACA,OAAA,EAnJO,GAmJP;EACA,UAAA,EAAA,MAAA;;AAGA,UA/Ia,iBAAA,CA+Ib;EAEA,UAAA,EAAA;IACA,SAAA,EAAA,MAAA;IACA,QAAA,EAAA,MAAA;EACA,CAAA;EAEA,IAAA,CAAA,EAjJK,SAiJL,EAAA;EACA,MAAA,CAAA,EAjJO,WAiJP;;AACoB,UA/IP,kBA+IO,CAAA,QA/IoB,GA+IpB,CAAA,CAAA;EAMP,IAAA,EApJT,KAoJS,EAAA;EAAwB,SAAA,EAAA,MAAA;;AAEhB,UAlJR,UAkJQ,CAAA,QAlJW,GAkJX,CAAA,CAAA;EAAX,KAAA,CAAA,OAAA,EAjJG,iBAiJH,CAAA,EAjJuB,OAiJvB,CAjJ+B,kBAiJ/B,CAjJkD,KAiJlD,CAAA,CAAA;;AAUG,UAnJA,qBAAA,CAmJkB;EAC1B,IAAA,EAAA,aAAA;EACE,MAAA,EAAA,MAAA;;AACe,UAjJT,sBAAA,CAiJS;EAQT,IAAA,EAAA,cAAA;EACD,MAAA,EAAA,MAAA;;AAD4B,UApJ3B,qBAAA,CAoJ2B;EAAkB,IAAA,EAAA,aAAA;EAO7C,MAAA,EAAA,MAAA;EACP,QAAA,EAAA,MAAA;EAEQ,OAAA,EA1JP,GA0JO;;AAEiB,UAzJlB,mBAAA,CAyJkB;EAOvB,IAAA,EAAA,WAAA;EACA,MAAA,EAAA,MAAA;;;UA1JK,wBAAA;EC3IL,IAAA,EAAA,iBAAS;EAEJ,QAAA,ED2IL,YC3IK,GAAA,IAAuB;;AAIT,UD0Id,4BAAA,CC1Ic;EACD,IAAA,EAAA,qBAAA;EAAgB,KAAA,ED2IrC,SC3IqC,GAAA,IAAA;AAM9C;AAWuB,UD8HN,oBAAA,CC9HM;EAQG,IAAA,EAAA,YAAA;EAiBZ,GAAA,EAAA,MAAA;EAIK,GAAA,EAAA,MAAA;EAII,YAAA,EDiGP,SCjGO;;AAkEA,UDkCN,mBAAA,CClCM;EA2GI,IAAA,EAAA,WAAA;;AA+CS,UDpHnB,qBAAA,CCoHmB;EAAO,IAAA,EAAA,aAAA;;;SDhHlC;AEvKT;AAG8C,UFwK7B,yBAAA,CExK6B;EAChB,IAAA,EAAA,kBAAA;EACoB,KAAA,EAAA,MAAA;EAAS,MAAA,EAAA,MAAA;AAM3D;AAKuB,UFiKN,uBAAA,CEjKM;EAQG,IAAA,EAAA,eAAA;EAiBZ,QAAA,EAAA,MAAA;EAee,MAAA,EF4HnB,gBE5HmB;EAAS,aAAA,CAAA,EF6HpB,aE7HoB;;;UFkIrB,oBAAA;EG/JJ,IAAA,EAAA,YAAQ;EAAe,WAAA,EHiKrB,SGjKqB;;AAiCP,UHmIZ,qBAAA,CGnIY;EACL,IAAA,EAAA,aAAA;EAYe,SAAA,EAAA,MAAA;EAAhB,SAAA,EAAA,MAAA;;AAiDQ,UH2Ed,qBAAA,CG3Ec;EA+CT,IAAA,EAAA,aAAA;EAiPP,WAAA,EHnNA,KGmNA,CAAA;IAEV,GAAA,EAAA,MAAA;IA0B4C,GAAA,EAAA,MAAA;IAgD/B,KAAA,EH/RsC,SG+RtC;EAIE,CAAA,CAAA;;AAsEF,UHtWD,qBAAA,CGsWC;EAQwB,IAAA,EAAA,aAAA;;AA8F1B,UHvcC,sBAAA,CGucD;EA4BgB,IAAA,EAAA,cAAA;;AA4Ba,UH3f5B,qBAAA,CG2f4B;EAAX,IAAA,EAAA,aAAA;EAAoB,SAAA,EAAA,MAAA;;AAQhB,UH9frB,oBAAA,CG8fqB;;;;AC7sBtB,KJqNJ,eAAA,GAER,qBIvNkC,GJwNlC,sBIxNkC,GJyNlC,qBIzNkC,GJ0NlC,mBI1NkC,GJ4NlC,wBI5NkC,GJ6NlC,4BI7NkC,GJ+NlC,oBI/NkC,GJgOlC,mBIhOkC,GJiOlC,qBIjOkC,GJmOlC,yBInOkC,GJoOlC,uBIpOkC,GJsOlC,oBItOkC,GJuOlC,qBIvOkC,GJwOlC,qBIxOkC,GJyOlC,qBIzOkC,GJ2OlC,sBI3OkC,GJ4OlC,qBI5OkC,GJ6OlC,oBI7OkC;AAAe,UJmPpC,eInPoC,CAAA,QJmPZ,GInPY,CAAA,CAAA;EAAM,OAAA,EJoPhD,gBIpPgD,EAAA;EACnD,UAAA,EJoPM,UIpPN,CJoPiB,KIpPjB,CAAA;EAGkB,SAAA,EAAA,MAAA;EAAyB,YAAA,CAAA,EAAA,MAAA;EAErC,QAAA,CAAA,EAAA,MAAA;;AAAD,UJyPI,kBAAA,CIzPJ;EAiCD,KAAA,EJyNH,SIzNG;EACD,OAAA,EJyNA,GIzNA;EACqB,MAAA,EJyNtB,gBIzNsB;EAAnB,QAAA,EAAA,MAAA;EAAR,QAAA,EAAA,MAAA;EAAO,QAAA,EAAA,OAAA;EAMI,UAAA,EAAA,OAAA;EAAqC,SAAA,EAAA,OAAA;;AACtB,UJ0Nd,kBAAA,SAA2B,kBI1Nb,CAAA;EAApB,YAAA,EJ2NK,SI3NL;EACG,aAAA,EAAA,CAAA,QAAA,EJ2Nc,SI3Nd,EAAA,GAAA,IAAA;EAAX,QAAA,EAAA,GAAA,GAAA,IAAA;EAAU,QAAA,EAAA,GAAA,GAAA,IAAA;AAoGb;AAAwD,UJ4HvC,oBAAA,CI5HuC;EAAM,MAAA,EJ6HpD,gBI7HoD;EACtD,QAAA,EAAA,MAAA;EACM,aAAA,CAAA,EJ6HI,aI7HJ;EAAX,SAAA,CAAA,EAAA,MAAA;EAAU,MAAA,EAAA,CAAA,SAAA,EJ+HS,aI/HT,GAAA,IAAA,EAAA,aAAA,EAAA,OAAA,EAAA,GAAA,IAAA;;KJsID,mBAAA,iBAAoC;KACpC,wBAAA,kBAA0C;;;AA5S1C,KCOA,SAAA,GDPY,IAAA,GAAA,MAAA,GAAA,MAAA,GAAA,OAAA;AAUZ,UCDK,uBAAA,CDCuC;EAC5C,WAAG,EAAA,GAAA,GAAA,MAAA;EAEH,cAAA,EAAa,GAAA,GAAA,MAAA;EACb,YAAS,EAAA,CAAA,GAAA,EAAA,MAA+B,EAAA,GAAA,EAAA,MAAa,EAAA,GCFnB,SDEmB;EACrD,UAAA,EAAA,CAAA,GAAW,EAAA,MAAA,EAAG,GCFK,GDEC,GAAA,SAAA;EAMf,SAAA,EAAA,CAAA,GAAA,EAAA,MAAgB,EAAA,GCPH,gBDUF,GAAA,SAAA;AAc5B;AAKA;AAWA;;AAES,cCpCI,gBAAA,CDoCJ;EAEC,QAAA,KAAA;EAAY,QAAA,OAAA;EASL,QAAA,SAAS;EAWT,WAAA,CAAA,OAAe,EC/CT,uBDgDC;EASP,aAAS,CAAA,QAAA,ECjDA,mBDoDZ,CAAA,EAAA,GAAA,GAAA,IAAA;EAQG,QAAA,IAAA;EASA,QAAA,CAAA,CAAA,ECpDH,cDoDqB;EAKlB,aAAU,CAAA,CAAA,ECrDR,YDqDQ,GAAA,IAAA;EAAS,iBAAA,CAAA,CAAA,ECjDb,SDiDa,GAAA,IAAA;EACnB,UAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAA+C,YAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAAnB;;;AAQ7C;AAKA;AAKA;EAOiB,cAAA,CAAA,IAAA,EC3CP,YD2C0B,EAAA,IAkBnB,CAlBmB,EAAA;IAOnB,KAAA,CAAA,EAAA,OAAA;IAKA,IAAA,CAAA,EAAA,OAAA;EAMA,CAAA,CAAA,EAAA,IAAA;EAOA;AAIjB;AAQA;EAMiB,SAAA,CAAA,SAAA,ECpDM,SDoDiB,EAAA,MAG9B,CAAA,EAAA,OAAA,CAAA,EAAA,IAAA;EAMO;AAKjB;AAMA;EAKiB,SAAA,CAAA,CAAA,EAAA,IAAA;EAKA;AAIjB;AAKA;EAMY,cAAA,CAAA,CAAA,EAAe,IAAA;EAEvB;;;EAGA,aAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAEA;;;EAIA,iBAAA,CAAA,KAAA,ECDuB,SDCvB,CAAA,EAAA,IAAA;EACA;;;EAKA,eAAA,CAAA,CAAA,ECKiB,SDLjB,EAAA,EAAA;EACA;;;EAIA,wBAAA,CAAA,CAAA,ECmCgC,ODnChC,CAAA,IAAA,CAAA;EACA,QAAA,aAAA;;;;AA1PQ,UEKK,kBAAA,CFLO;EAUZ,WAAA,EAAS,GAAA,GAAA,MAA+B;EACxC,cAAG,EAAA,GAAA,GAAA,MAAA;EAEH,YAAA,EAAA,CAAA,GAAa,EAAA,MAAA,EAAA,GAAA,EAAA,MAAA,EAAA,GELqB,SFKrB;EACb,SAAA,EAAA,CAAS,GAAA,EAAA,MAA+B,EAAA,GELtB,gBFKmC,GAAA,SAAA;EACrD,YAAA,EAAW,CAAA,GAAA,EAAA,MAAG,EAAA,GAAA,EAAM,MAAA,EAAA,KAAA,EELkB,SFKlB,EAAA,GAAA,IAAA;AAMhC;AAiBA;AAKA;AAWA;AACc,cEvCD,WAAA,CFuCC;EACL,QAAA,KAAA;EAEC,QAAA,OAAA;EAAY,QAAA,SAAA;EASL,WAAA,CAAS,OAAA,EE9CH,kBFkDP;EAOC,aAAA,CAAA,QAAe,EEjDN,mBFkDF,CAAA,EAAA,GAAA,GAAA,IAAA;EASP,QAAA,IAAS;EAWT,QAAA,CAAA,CAAA,EErDH,eFqDoB,GAAA,IAKzB;EAIQ,QAAA,CAAA,CAAA,EAAA,OAAA;EAKA;;;EAC+C,aAAA,CAAA,WAAA,EErDnC,SFqDmC,CAAA,EAAA,IAAA;EAAnB;;;EAQ5B,cAAA,CAAA,SAAqB,EAAA,MAAA,EAAA,SAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAKrB;AAKjB;AAOA;EAOiB,cAAA,CAAA,CAAA,EAAA,IAAA;EAKA;AAMjB;AAOA;EAIiB,cAAA,CAAA,CAAA,EAAA,IAAA;EAQA;AAMjB;AASA;EAKiB,QAAA,oBAAqB;EAMrB,QAAA,qBAAqB;EAKrB,QAAA,kBAAqB;EAKrB,QAAA,aAAA;EAIA,QAAA,YAAA;AAKjB;;;AAlNY,cGqBC,QHrBE,CAAA,cGqBqB,GHrBrB,GGqB2B,GHrB3B,CAAA,CAAA;EAEH,QAAA,OAAA;EACA,QAAA,UAAS;EACT,QAAA,SAAW;EAMN,QAAA,YAAgB;EAiBhB,QAAA,QAAY;EAKZ,QAAA,SAAS;EAWT,QAAA,UAAc;EACjB,QAAA,aAAA;EACL,QAAA,cAAA;EAEC,QAAA,UAAA;EAAY,QAAA,SAAA;EASL,QAAA,gBAGD;EAQC,QAAA,QAAA;EAUA,QAAA,SAAS;EAWT,QAAA,WAAA;EASA,QAAA,QAAA;EAKA,SAAA,SAAU,EGhDE,gBHgDF;EAAS,SAAA,IAAA,EG/CZ,WH+CY;EACnB,QAAA,SAAA;EAA+C,QAAA,eAAA;EAAnB,QAAA,SAAA;EAAR,QAAA,cAAA;EAAO,WAAA,CAAA,OAAA,EGpCrB,eHoCqB,CGpCL,KHoCK,CAAA;EAQ3B,aAAA,CAAA,QAAA,EGNS,mBHMY,CAAA,EAAA,GAAA,GAAA,IAAA;EAKrB;AAKjB;AAOA;AAOA;EAKiB,kBAAA,CAAA,QAAA,EGxBc,wBH0Bb,CAAA,EAAA,GAAA,GAAA,IAAA;EAID,QAAA,IAAA;EAOA,QAAA,SAAA;EAIA;AAQjB;AAMA;EASiB,UAAA,CAAA,CAAA,EGjBK,OHiBL,CAAA,IAAoB,CAAA;EAKpB;AAMjB;AAKA;EAKiB,WAAA,CAAA,SAAA,EAAA,MAAsB,EAAA,UAAA,EAAA,MAAA,EAAA,KAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAItB;AAKjB;AAMA;;EAGI,QAAA,SAAA;EACA,QAAA,eAAA;EACA,QAAA,gBAAA;EAEA,QAAA,SAAA;EACA,QAAA,YAAA;EAEA,OAAA,CAAA,KAAA,EAAA,MAAA,EAAA,SAAA,EGkLW,aHlLX,GAAA,IAAA,EAAA,aAAA,CAAA,EAAA,OAAA,CAAA,EGoLC,OHpLD,CAAA,IAAA,CAAA;EACA,SAAA,CAAA,KAAA,EAAA,MAAA,EAAA,KAAA,EAAA,MAAA,CAAA,EG6M6C,OH7M7C,CAAA,IAAA,CAAA;EACA;;;EAKA,QAAA,eAAA;EACA,YAAA,CAAA,CAAA,EGsPc,SHtPd,EAAA;EACA,cAAA,CAAA,CAAA,EGyPgB,WHzPhB;EACA,SAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAEA,eAAA,CAAA,KAAA,EGkRqB,SHlRrB,CAAA,EAAA,IAAA;EACA,UAAA,CAAA,CAAA,EAAA,IAAA;EACA,UAAA,CAAA,CAAA,EAAA,IAAA;EAAoB,YAAA,CAAA,CAAA,EG0TN,SH1TM,GAAA,IAAA;EAMP,YAAA,CAAA,GAAA,EAAe,MAAA,EAAA,GAAA,EAAA,MAAA,CAAA,EG4TU,SH5TV;EAAS,YAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EGsUO,SHtUP,CAAA,EAAA,IAAA;EAC9B,QAAA,aAAA;EACc,QAAA,aAAA;EAAX,QAAA,sBAAA;EAAU,QAAA,eAAA;EAUP,QAAA,WAAA;EACR,UAAA,CAAA,CAAA,EG6YO,gBH7YP,EAAA;EACE,kBAAA,CAAA,CAAA,EAAA,MAAA,EAAA;EACD,WAAA,CAAA,CAAA,EAAA,MAAA;EAAgB,YAAA,CAAA,CAAA,EAAA,MAAA;EAQT,eAAA,CAAA,CAAA,EAAA,MAAmB;EACpB,aAAA,CAAA,CAAA,EAAA,MAAA;EACY,cAAA,CAAA,CAAA,EAAA,MAAA;EAFgB,UAAA,CAAA,QAAA,EAAA,MAAA,CAAA,EG+ZZ,KH/ZY,GAAA,SAAA;EAAkB;AAO9D;;EAGkB,OAAA,CAAA,CAAA,EGgaC,OHhaD,CAAA,IAAA,CAAA;EAEI;;AAOtB;AACA;;;;ACrSA;EAEiB,aAAA,CAAA,UAAA,EE0sBiB,UF1sBM,CE0sBK,KF1sBL,CAAA,CAAA,EE0sBc,OF1sBd,CAAA,IAAA,CAAA;EAGM;;;EAEA,UAAA,CAAA,OAAA,EE6sBxB,gBF7sBwB,EAAA,CAAA,EAAA,IAAA;AAM9C;;;ADpBA;AAUA;AACA;AAEA;AACY,iBIAI,sBJAiD,CAAA,cIAZ,GJAY,GIAN,GJAM,CAAA,CAAA,IAAA,EICzD,KJDyD,EAAA,EAAA,OAwBjE,CAxBiE,EAAA;EACrD;EAMK,aAAA,CAAA,EAAA,CAAA,GAAgB,EIHP,KJGO,EAAA,KAGjB,EAAA,MAAA,EAAY,GINuB,SJMvB;AAc5B,CAAA,CAAA,EIlBG,UJkBc,CIlBH,KJkBe,CAAA;AAKZ,KIUL,mBJVc,CAAA,KAAA,CAAA,GAAA,CAAA,OAAA,EIWf,iBJXe,EAAA,GIYrB,OJZqB,CIYb,kBJZa,CIYM,KJZN,CAAA,CAAA;AAW1B;;;;AAIsB,iBIGN,sBJHM,CAAA,cIG+B,GJH/B,GIGqC,GJHrC,CAAA,CAAA,OAAA,EIIX,mBJJW,CIIS,KJJT,CAAA,CAAA,EIKnB,UJLmB,CIKR,KJLQ,CAAA;AAStB;AAWA;AAUA;AAWA;AASiB,iBIuDD,yBJtDR,CAAA,cIsDgD,GJtD3C,GIsDiD,GJtDjD,CAAA,CAAA,IAAA,EIuDL,KJvDK,EAAA,CAAA,EIwDV,UJxDU,CIwDC,KJxDD,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ var e=class{state={activeCell:null,range:null,anchor:null,selectionMode:!1};options;listeners=[];constructor(e){this.options=e}onInstruction(e){return this.listeners.push(e),()=>{this.listeners=this.listeners.filter(t=>t!==e)}}emit(e){for(let t of this.listeners)t(e)}getState(){return{...this.state}}getActiveCell(){return this.state.activeCell}getSelectionRange(){return this.state.range}isSelected(e,t){let{range:n}=this.state;if(!n)return!1;let r=Math.min(n.startRow,n.endRow),i=Math.max(n.startRow,n.endRow),a=Math.min(n.startCol,n.endCol),o=Math.max(n.startCol,n.endCol);return e>=r&&e<=i&&t>=a&&t<=o}isActiveCell(e,t){let{activeCell:n}=this.state;return n?.row===e&&n?.col===t}startSelection(e,t={}){let{shift:n=!1,ctrl:r=!1}=t,{row:i,col:a}=this.clampPosition(e);n&&this.state.anchor?(this.state.range={startRow:this.state.anchor.row,startCol:this.state.anchor.col,endRow:i,endCol:a},this.state.activeCell={row:i,col:a}):(this.state.activeCell={row:i,col:a},this.state.anchor={row:i,col:a},this.state.range=null),this.state.selectionMode=r,this.emit({type:`SET_ACTIVE_CELL`,position:this.state.activeCell}),this.emit({type:`SET_SELECTION_RANGE`,range:this.state.range})}moveFocus(e,t=!1){if(!this.state.activeCell){this.startSelection({row:0,col:0});return}let{row:n,col:r}=this.state.activeCell,i=n,a=r;switch(e){case`up`:i=Math.max(0,n-1);break;case`down`:i=Math.min(this.options.getRowCount()-1,n+1);break;case`left`:a=Math.max(0,r-1);break;case`right`:a=Math.min(this.options.getColumnCount()-1,r+1);break}t?(this.state.anchor||(this.state.anchor={row:n,col:r}),this.state.range={startRow:this.state.anchor.row,startCol:this.state.anchor.col,endRow:i,endCol:a},this.state.activeCell={row:i,col:a},this.emit({type:`SET_ACTIVE_CELL`,position:this.state.activeCell}),this.emit({type:`SET_SELECTION_RANGE`,range:this.state.range})):(this.state.activeCell={row:i,col:a},this.state.anchor={row:i,col:a},this.state.range=null,this.emit({type:`SET_ACTIVE_CELL`,position:this.state.activeCell}),this.emit({type:`SET_SELECTION_RANGE`,range:null}))}selectAll(){let e=this.options.getRowCount(),t=this.options.getColumnCount();e===0||t===0||(this.state.range={startRow:0,startCol:0,endRow:e-1,endCol:t-1},this.state.activeCell||(this.state.activeCell={row:0,col:0},this.emit({type:`SET_ACTIVE_CELL`,position:this.state.activeCell})),this.emit({type:`SET_SELECTION_RANGE`,range:this.state.range}))}clearSelection(){this.state.activeCell=null,this.state.range=null,this.state.anchor=null,this.state.selectionMode=!1,this.emit({type:`SET_ACTIVE_CELL`,position:null}),this.emit({type:`SET_SELECTION_RANGE`,range:null})}setActiveCell(e,t){let n=this.clampPosition({row:e,col:t});this.state.activeCell=n,this.state.anchor=n,this.state.range=null,this.emit({type:`SET_ACTIVE_CELL`,position:this.state.activeCell}),this.emit({type:`SET_SELECTION_RANGE`,range:null})}setSelectionRange(e){this.state.range=e,this.emit({type:`SET_SELECTION_RANGE`,range:this.state.range})}getSelectedData(){let{range:e,activeCell:t}=this.state;if(!e&&!t)return[];let n=e||{startRow:t.row,startCol:t.col,endRow:t.row,endCol:t.col},r=Math.min(n.startRow,n.endRow),i=Math.max(n.startRow,n.endRow),a=Math.min(n.startCol,n.endCol),o=Math.max(n.startCol,n.endCol),s=[];for(let e=r;e<=i;e++){let t=[];for(let n=a;n<=o;n++)t.push(this.options.getCellValue(e,n));s.push(t)}return s}async copySelectionToClipboard(){let e=this.getSelectedData();if(e.length===0)return;let t=e.map(e=>e.map(e=>e==null?``:String(e)).join(` `)).join(`
2
+ `);try{await navigator.clipboard.writeText(t)}catch{let e=document.createElement(`textarea`);e.value=t,e.style.position=`fixed`,e.style.left=`-9999px`,document.body.appendChild(e),e.select(),document.execCommand(`copy`),document.body.removeChild(e)}}clampPosition(e){let t=this.options.getRowCount(),n=this.options.getColumnCount();return{row:Math.max(0,Math.min(e.row,t-1)),col:Math.max(0,Math.min(e.col,n-1))}}},t=class{state=null;options;listeners=[];constructor(e){this.options=e}onInstruction(e){return this.listeners.push(e),()=>{this.listeners=this.listeners.filter(t=>t!==e)}}emit(e){for(let t of this.listeners)t(e)}getState(){return this.state?{...this.state}:null}isActive(){return this.state!==null}startFillDrag(e){this.state={sourceRange:e,targetRow:e.endRow,targetCol:e.endCol},this.emit({type:`START_FILL`,sourceRange:e})}updateFillDrag(e,t){if(!this.state)return;let n=this.options.getRowCount(),r=this.options.getColumnCount();e=Math.max(0,Math.min(e,n-1)),t=Math.max(0,Math.min(t,r-1)),this.state.targetRow=e,this.state.targetCol=t,this.emit({type:`UPDATE_FILL`,targetRow:e,targetCol:t})}commitFillDrag(){if(!this.state)return;let{sourceRange:e,targetRow:t,targetCol:n}=this.state,r=this.calculateFilledCells(e,t,n);for(let{row:e,col:t,value:n}of r)this.options.setCellValue(e,t,n);this.emit({type:`COMMIT_FILL`,filledCells:r}),this.state=null}cancelFillDrag(){this.state&&(this.state=null,this.emit({type:`CANCEL_FILL`}))}calculateFilledCells(e,t,n){let r=[],i=Math.min(e.startRow,e.endRow),a=Math.max(e.startRow,e.endRow),o=Math.min(e.startCol,e.endCol),s=Math.max(e.startCol,e.endCol),c=t>a,l=t<i,u=n>s,d=n<o;if(c||l)for(let e=o;e<=s;e++){let n=this.getSourceColumnValues(i,a,e),o=this.detectPattern(n);if(c)for(let i=a+1;i<=t;i++){let t=i-a-1,s=this.applyPattern(o,n,t);r.push({row:i,col:e,value:s})}else if(l)for(let a=i-1;a>=t;a--){let t=i-a-1,s=this.applyPattern(o,n,t,!0);r.push({row:a,col:e,value:s})}}if(u||d)for(let e=i;e<=a;e++){let t=this.getSourceRowValues(o,s,e),i=this.detectPattern(t);if(u)for(let a=s+1;a<=n;a++){let n=a-s-1,o=this.applyPattern(i,t,n);r.push({row:e,col:a,value:o})}else if(d)for(let a=o-1;a>=n;a--){let n=o-a-1,s=this.applyPattern(i,t,n,!0);r.push({row:e,col:a,value:s})}}return r}getSourceColumnValues(e,t,n){let r=[];for(let i=e;i<=t;i++)r.push(this.options.getCellValue(i,n));return r}getSourceRowValues(e,t,n){let r=[];for(let i=e;i<=t;i++)r.push(this.options.getCellValue(n,i));return r}detectPattern(e){if(e.length===0)return{type:`constant`,value:null};if(e.length===1)return{type:`constant`,value:e[0]??null};let t=e.map(e=>typeof e==`number`?e:Number(e));if(t.every(e=>!isNaN(e))){let e=[];for(let n=1;n<t.length;n++)e.push(t[n]-t[n-1]);if(e.every(t=>t===e[0])&&e[0]!==void 0)return{type:`arithmetic`,start:t[0],step:e[0]}}return{type:`repeat`,values:e}}applyPattern(e,t,n,r=!1){switch(e.type){case`constant`:return e.value;case`arithmetic`:{let i=r?-(n+1):n+1;return(r?e.start:e.start+e.step*(t.length-1))+e.step*i}case`repeat`:{let t=e.values.length;if(t===0)return null;if(r){let r=(t-1-n%t+t)%t;return e.values[r]??null}return e.values[n%t]??null}}}},n=class{columns;dataSource;rowHeight;headerHeight;overscan;scrollTop=0;scrollLeft=0;viewportWidth=800;viewportHeight=600;cachedRows=new Map;totalRows=0;currentPageIndex=0;pageSize=1e6;sortModel=[];filterModel={};slotPool={slots:new Map,rowToSlot:new Map,nextSlotId:0};selection;fill;editState=null;columnPositions=[];listeners=[];batchListeners=[];constructor(n){this.columns=n.columns,this.dataSource=n.dataSource,this.rowHeight=n.rowHeight,this.headerHeight=n.headerHeight??n.rowHeight,this.overscan=n.overscan??3,this.computeColumnPositions(),this.selection=new e({getRowCount:()=>this.totalRows,getColumnCount:()=>this.columns.length,getCellValue:(e,t)=>this.getCellValue(e,t),getRowData:e=>this.cachedRows.get(e),getColumn:e=>this.columns[e]}),this.selection.onInstruction(e=>this.emit(e)),this.fill=new t({getRowCount:()=>this.totalRows,getColumnCount:()=>this.columns.length,getCellValue:(e,t)=>this.getCellValue(e,t),getColumn:e=>this.columns[e],setCellValue:(e,t,n)=>this.setCellValue(e,t,n)}),this.fill.onInstruction(e=>this.emit(e))}onInstruction(e){return this.listeners.push(e),()=>{this.listeners=this.listeners.filter(t=>t!==e)}}onBatchInstruction(e){return this.batchListeners.push(e),()=>{this.batchListeners=this.batchListeners.filter(t=>t!==e)}}emit(e){for(let t of this.listeners)t(e);for(let t of this.batchListeners)t([e])}emitBatch(e){if(e.length!==0){for(let t of this.batchListeners)t(e);for(let t of e)for(let e of this.listeners)e(t)}}async initialize(){await this.fetchData(),this.syncSlots(),this.emitContentSize(),this.emitHeaders()}setViewport(e,t,n,r){(this.scrollTop!==e||this.scrollLeft!==t||this.viewportWidth!==n||this.viewportHeight!==r)&&(this.scrollTop=e,this.scrollLeft=t,this.viewportWidth=n,this.viewportHeight=r,this.syncSlots())}syncSlots(){let e=Math.max(0,Math.floor(this.scrollTop/this.rowHeight)-this.overscan),t=Math.min(this.totalRows-1,Math.ceil((this.scrollTop+this.viewportHeight)/this.rowHeight)+this.overscan);if(this.totalRows===0||t<e){this.destroyAllSlots();return}let n=new Set;for(let r=e;r<=t;r++)n.add(r);let r=[],i=[];for(let[e,t]of this.slotPool.slots)n.has(t.rowIndex)?n.delete(t.rowIndex):(i.push(e),this.slotPool.rowToSlot.delete(t.rowIndex));let a=Array.from(n);for(let e=0;e<a.length;e++){let t=a[e],n=this.cachedRows.get(t);if(e<i.length){let a=i[e],o=this.slotPool.slots.get(a),s=this.getRowTranslateY(t);o.rowIndex=t,o.rowData=n??{},o.translateY=s,this.slotPool.rowToSlot.set(t,a),r.push({type:`ASSIGN_SLOT`,slotId:a,rowIndex:t,rowData:n??{}}),r.push({type:`MOVE_SLOT`,slotId:a,translateY:s})}else{let e=`slot-${this.slotPool.nextSlotId++}`,i=this.getRowTranslateY(t),a={slotId:e,rowIndex:t,rowData:n??{},translateY:i};this.slotPool.slots.set(e,a),this.slotPool.rowToSlot.set(t,e),r.push({type:`CREATE_SLOT`,slotId:e}),r.push({type:`ASSIGN_SLOT`,slotId:e,rowIndex:t,rowData:n??{}}),r.push({type:`MOVE_SLOT`,slotId:e,translateY:i})}}for(let e=a.length;e<i.length;e++){let t=i[e];this.slotPool.slots.delete(t),r.push({type:`DESTROY_SLOT`,slotId:t})}for(let[e,t]of this.slotPool.slots){let n=this.getRowTranslateY(t.rowIndex);t.translateY!==n&&(t.translateY=n,r.push({type:`MOVE_SLOT`,slotId:e,translateY:n}))}this.emitBatch(r)}destroyAllSlots(){let e=[];for(let t of this.slotPool.slots.keys())e.push({type:`DESTROY_SLOT`,slotId:t});this.slotPool.slots.clear(),this.slotPool.rowToSlot.clear(),this.emitBatch(e)}getRowTranslateY(e){return e*this.rowHeight+this.headerHeight}async fetchData(){this.emit({type:`DATA_LOADING`});try{let e={pagination:{pageIndex:this.currentPageIndex,pageSize:this.pageSize},sort:this.sortModel.length>0?this.sortModel:void 0,filter:Object.keys(this.filterModel).length>0?this.filterModel:void 0},t=await this.dataSource.fetch(e);this.cachedRows.clear(),t.rows.forEach((e,t)=>{this.cachedRows.set(this.currentPageIndex*this.pageSize+t,e)}),this.totalRows=t.totalRows,t.totalRows>t.rows.length&&this.currentPageIndex===0&&await this.fetchAllData(),this.emit({type:`DATA_LOADED`,totalRows:this.totalRows})}catch(e){this.emit({type:`DATA_ERROR`,error:e instanceof Error?e.message:String(e)})}}async fetchAllData(){let e=Math.ceil(this.totalRows/this.pageSize);for(let t=1;t<e;t++){let e={pagination:{pageIndex:t,pageSize:this.pageSize},sort:this.sortModel.length>0?this.sortModel:void 0,filter:Object.keys(this.filterModel).length>0?this.filterModel:void 0};(await this.dataSource.fetch(e)).rows.forEach((e,n)=>{this.cachedRows.set(t*this.pageSize+n,e)})}}async setSort(e,t,n=!1){let r=this.sortModel.findIndex(t=>t.colId===e);n?t===null?r>=0&&this.sortModel.splice(r,1):r>=0?this.sortModel[r].direction=t:this.sortModel.push({colId:e,direction:t}):this.sortModel=t===null?[]:[{colId:e,direction:t}],await this.fetchData(),this.refreshAllSlots(),this.emitHeaders()}async setFilter(e,t){t===``?delete this.filterModel[e]:this.filterModel[e]=t,await this.fetchData(),this.refreshAllSlots(),this.emitContentSize()}refreshAllSlots(){let e=[];for(let[t,n]of this.slotPool.slots)if(n.rowIndex>=0&&n.rowIndex<this.totalRows){let r=this.cachedRows.get(n.rowIndex),i=this.getRowTranslateY(n.rowIndex);n.rowData=r??{},n.translateY=i,e.push({type:`ASSIGN_SLOT`,slotId:t,rowIndex:n.rowIndex,rowData:r??{}}),e.push({type:`MOVE_SLOT`,slotId:t,translateY:i})}this.emitBatch(e),this.syncSlots()}getSortModel(){return[...this.sortModel]}getFilterModel(){return{...this.filterModel}}startEdit(e,t){let n=this.columns[t];if(!n||n.editable!==!0)return;let r=this.getCellValue(e,t);this.editState={row:e,col:t,initialValue:r,currentValue:r},this.emit({type:`START_EDIT`,row:e,col:t,initialValue:r})}updateEditValue(e){this.editState&&(this.editState.currentValue=e)}commitEdit(){if(!this.editState)return;let{row:e,col:t,currentValue:n}=this.editState;this.setCellValue(e,t,n),this.emit({type:`COMMIT_EDIT`,row:e,col:t,value:n}),this.editState=null,this.emit({type:`STOP_EDIT`});let r=this.slotPool.rowToSlot.get(e);if(r){let t=this.cachedRows.get(e);t&&this.emit({type:`ASSIGN_SLOT`,slotId:r,rowIndex:e,rowData:t})}}cancelEdit(){this.editState=null,this.emit({type:`STOP_EDIT`})}getEditState(){return this.editState?{...this.editState}:null}getCellValue(e,t){let n=this.cachedRows.get(e);if(!n)return null;let r=this.columns[t];return r?this.getFieldValue(n,r.field):null}setCellValue(e,t,n){let r=this.cachedRows.get(e);if(!r||typeof r!=`object`)return;let i=this.columns[t];i&&this.setFieldValue(r,i.field,n)}getFieldValue(e,t){let n=t.split(`.`),r=e;for(let e of n){if(typeof r!=`object`||!r)return null;r=r[e]}return r??null}setFieldValue(e,t,n){let r=t.split(`.`),i=e;for(let e=0;e<r.length-1;e++){let t=r[e];t in i||(i[t]={}),i=i[t]}let a=r[r.length-1];i[a]=n}computeColumnPositions(){this.columnPositions=[0];let e=0;for(let t of this.columns)e+=t.width,this.columnPositions.push(e)}emitContentSize(){let e=this.columnPositions[this.columnPositions.length-1]??0,t=this.totalRows*this.rowHeight+this.headerHeight;this.emit({type:`SET_CONTENT_SIZE`,width:e,height:t})}emitHeaders(){let e=new Map;this.sortModel.forEach((t,n)=>{e.set(t.colId,{direction:t.direction,index:n+1})});for(let t=0;t<this.columns.length;t++){let n=this.columns[t],r=n.colId??n.field,i=e.get(r);this.emit({type:`UPDATE_HEADER`,colIndex:t,column:n,sortDirection:i?.direction,sortIndex:i?.index})}}getColumns(){return this.columns}getColumnPositions(){return[...this.columnPositions]}getRowCount(){return this.totalRows}getRowHeight(){return this.rowHeight}getHeaderHeight(){return this.headerHeight}getTotalWidth(){return this.columnPositions[this.columnPositions.length-1]??0}getTotalHeight(){return this.totalRows*this.rowHeight+this.headerHeight}getRowData(e){return this.cachedRows.get(e)}async refresh(){await this.fetchData(),this.syncSlots(),this.emitContentSize()}refreshSlotData(){this.refreshAllSlots()}async setDataSource(e){this.dataSource=e,await this.refresh()}setColumns(e){this.columns=e,this.computeColumnPositions(),this.emitContentSize(),this.emitHeaders(),this.syncSlots()}};function r(e,t={}){let{getFieldValue:n=a}=t;return{async fetch(t){let r=[...e];t.filter&&Object.keys(t.filter).length>0&&(r=o(r,t.filter,n)),t.sort&&t.sort.length>0&&(r=s(r,t.sort,n));let i=r.length,{pageIndex:a,pageSize:c}=t.pagination,l=a*c;return{rows:r.slice(l,l+c),totalRows:i}}}}function i(e){return{async fetch(t){return e(t)}}}function a(e,t){let n=t.split(`.`),r=e;for(let e of n){if(typeof r!=`object`||!r)return null;r=r[e]}return r??null}function o(e,t,n){let r=Object.entries(t).filter(([,e])=>e!==``);return r.length===0?e:e.filter(e=>{for(let[t,i]of r){let r=n(e,t),a=String(r??``).toLowerCase(),o=i.toLowerCase();if(!a.includes(o))return!1}return!0})}function s(e,t,n){return[...e].sort((e,r)=>{for(let{colId:i,direction:a}of t){let t=c(n(e,i),n(r,i));if(t!==0)return a===`asc`?t:-t}return 0})}function c(e,t){if(e==null&&t==null)return 0;if(e==null)return 1;if(t==null)return-1;let n=Number(e),r=Number(t);return!isNaN(n)&&!isNaN(r)?n-r:e instanceof Date&&t instanceof Date?e.getTime()-t.getTime():String(e).localeCompare(String(t))}function l(e){return r(e)}export{t as FillManager,n as GridCore,e as SelectionManager,r as createClientDataSource,l as createDataSourceFromArray,i as createServerDataSource};
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["data: CellValue[][]","row: CellValue[]","result: Array<{ row: number; col: number; value: CellValue }>","values: CellValue[]","diffs: number[]","instructions: GridInstruction[]","slotsToRecycle: string[]","newSlot: SlotState","request: DataSourceRequest","value: unknown","value: unknown"],"sources":["../src/selection.ts","../src/fill.ts","../src/grid-core.ts","../src/data-source.ts"],"sourcesContent":["// gp-grid-core/src/selection.ts\r\n\r\nimport type {\r\n CellPosition,\r\n CellRange,\r\n SelectionState,\r\n GridInstruction,\r\n InstructionListener,\r\n CellValue,\r\n ColumnDefinition,\r\n Row,\r\n} from \"./types\";\r\n\r\nexport type Direction = \"up\" | \"down\" | \"left\" | \"right\";\r\n\r\nexport interface SelectionManagerOptions {\r\n getRowCount: () => number;\r\n getColumnCount: () => number;\r\n getCellValue: (row: number, col: number) => CellValue;\r\n getRowData: (row: number) => Row | undefined;\r\n getColumn: (col: number) => ColumnDefinition | undefined;\r\n}\r\n\r\n/**\r\n * Manages Excel-style cell selection, keyboard navigation, and clipboard operations.\r\n */\r\nexport class SelectionManager {\r\n private state: SelectionState = {\r\n activeCell: null,\r\n range: null,\r\n anchor: null,\r\n selectionMode: false,\r\n };\r\n\r\n private options: SelectionManagerOptions;\r\n private listeners: InstructionListener[] = [];\r\n\r\n constructor(options: SelectionManagerOptions) {\r\n this.options = options;\r\n }\r\n\r\n // ===========================================================================\r\n // Instruction Emission\r\n // ===========================================================================\r\n\r\n onInstruction(listener: InstructionListener): () => void {\r\n this.listeners.push(listener);\r\n return () => {\r\n this.listeners = this.listeners.filter((l) => l !== listener);\r\n };\r\n }\r\n\r\n private emit(instruction: GridInstruction): void {\r\n for (const listener of this.listeners) {\r\n listener(instruction);\r\n }\r\n }\r\n\r\n // ===========================================================================\r\n // State Accessors\r\n // ===========================================================================\r\n\r\n getState(): SelectionState {\r\n return { ...this.state };\r\n }\r\n\r\n getActiveCell(): CellPosition | null {\r\n return this.state.activeCell;\r\n }\r\n\r\n getSelectionRange(): CellRange | null {\r\n return this.state.range;\r\n }\r\n\r\n isSelected(row: number, col: number): boolean {\r\n const { range } = this.state;\r\n if (!range) return false;\r\n\r\n const minRow = Math.min(range.startRow, range.endRow);\r\n const maxRow = Math.max(range.startRow, range.endRow);\r\n const minCol = Math.min(range.startCol, range.endCol);\r\n const maxCol = Math.max(range.startCol, range.endCol);\r\n\r\n return row >= minRow && row <= maxRow && col >= minCol && col <= maxCol;\r\n }\r\n\r\n isActiveCell(row: number, col: number): boolean {\r\n const { activeCell } = this.state;\r\n return activeCell?.row === row && activeCell?.col === col;\r\n }\r\n\r\n // ===========================================================================\r\n // Selection Operations\r\n // ===========================================================================\r\n\r\n /**\r\n * Start a selection at the given cell.\r\n * @param cell - The cell to select\r\n * @param opts.shift - Extend selection from anchor (range select)\r\n * @param opts.ctrl - Toggle selection mode\r\n */\r\n startSelection(\r\n cell: CellPosition,\r\n opts: { shift?: boolean; ctrl?: boolean } = {}\r\n ): void {\r\n // console.log(\"[GP-Grid Selection] startSelection:\", { cell, opts, listenerCount: this.listeners.length });\r\n const { shift = false, ctrl = false } = opts;\r\n const { row, col } = this.clampPosition(cell);\r\n\r\n if (shift && this.state.anchor) {\r\n // Extend selection from anchor to current cell\r\n this.state.range = {\r\n startRow: this.state.anchor.row,\r\n startCol: this.state.anchor.col,\r\n endRow: row,\r\n endCol: col,\r\n };\r\n this.state.activeCell = { row, col };\r\n } else {\r\n // Start new selection\r\n this.state.activeCell = { row, col };\r\n this.state.anchor = { row, col };\r\n this.state.range = null;\r\n }\r\n\r\n this.state.selectionMode = ctrl;\r\n\r\n // console.log(\"[GP-Grid Selection] Emitting SET_ACTIVE_CELL:\", this.state.activeCell);\r\n this.emit({ type: \"SET_ACTIVE_CELL\", position: this.state.activeCell });\r\n // console.log(\"[GP-Grid Selection] Emitting SET_SELECTION_RANGE:\", this.state.range);\r\n this.emit({ type: \"SET_SELECTION_RANGE\", range: this.state.range });\r\n }\r\n\r\n /**\r\n * Move focus in a direction, optionally extending the selection.\r\n */\r\n moveFocus(direction: Direction, extend: boolean = false): void {\r\n if (!this.state.activeCell) {\r\n // No active cell, select first cell\r\n this.startSelection({ row: 0, col: 0 });\r\n return;\r\n }\r\n\r\n const { row, col } = this.state.activeCell;\r\n let newRow = row;\r\n let newCol = col;\r\n\r\n switch (direction) {\r\n case \"up\":\r\n newRow = Math.max(0, row - 1);\r\n break;\r\n case \"down\":\r\n newRow = Math.min(this.options.getRowCount() - 1, row + 1);\r\n break;\r\n case \"left\":\r\n newCol = Math.max(0, col - 1);\r\n break;\r\n case \"right\":\r\n newCol = Math.min(this.options.getColumnCount() - 1, col + 1);\r\n break;\r\n }\r\n\r\n if (extend) {\r\n // Extend selection (Shift+Arrow)\r\n if (!this.state.anchor) {\r\n this.state.anchor = { row, col };\r\n }\r\n\r\n this.state.range = {\r\n startRow: this.state.anchor.row,\r\n startCol: this.state.anchor.col,\r\n endRow: newRow,\r\n endCol: newCol,\r\n };\r\n this.state.activeCell = { row: newRow, col: newCol };\r\n\r\n this.emit({ type: \"SET_ACTIVE_CELL\", position: this.state.activeCell });\r\n this.emit({ type: \"SET_SELECTION_RANGE\", range: this.state.range });\r\n } else {\r\n // Move without extending\r\n this.state.activeCell = { row: newRow, col: newCol };\r\n this.state.anchor = { row: newRow, col: newCol };\r\n this.state.range = null;\r\n\r\n this.emit({ type: \"SET_ACTIVE_CELL\", position: this.state.activeCell });\r\n this.emit({ type: \"SET_SELECTION_RANGE\", range: null });\r\n }\r\n }\r\n\r\n /**\r\n * Select all cells in the grid (Ctrl+A).\r\n */\r\n selectAll(): void {\r\n const rowCount = this.options.getRowCount();\r\n const colCount = this.options.getColumnCount();\r\n\r\n if (rowCount === 0 || colCount === 0) return;\r\n\r\n this.state.range = {\r\n startRow: 0,\r\n startCol: 0,\r\n endRow: rowCount - 1,\r\n endCol: colCount - 1,\r\n };\r\n\r\n // Keep active cell if exists, otherwise set to first cell\r\n if (!this.state.activeCell) {\r\n this.state.activeCell = { row: 0, col: 0 };\r\n this.emit({ type: \"SET_ACTIVE_CELL\", position: this.state.activeCell });\r\n }\r\n\r\n this.emit({ type: \"SET_SELECTION_RANGE\", range: this.state.range });\r\n }\r\n\r\n /**\r\n * Clear the current selection.\r\n */\r\n clearSelection(): void {\r\n this.state.activeCell = null;\r\n this.state.range = null;\r\n this.state.anchor = null;\r\n this.state.selectionMode = false;\r\n\r\n this.emit({ type: \"SET_ACTIVE_CELL\", position: null });\r\n this.emit({ type: \"SET_SELECTION_RANGE\", range: null });\r\n }\r\n\r\n /**\r\n * Set the active cell directly.\r\n */\r\n setActiveCell(row: number, col: number): void {\r\n const clamped = this.clampPosition({ row, col });\r\n this.state.activeCell = clamped;\r\n this.state.anchor = clamped;\r\n this.state.range = null;\r\n\r\n this.emit({ type: \"SET_ACTIVE_CELL\", position: this.state.activeCell });\r\n this.emit({ type: \"SET_SELECTION_RANGE\", range: null });\r\n }\r\n\r\n /**\r\n * Set the selection range directly.\r\n */\r\n setSelectionRange(range: CellRange): void {\r\n this.state.range = range;\r\n this.emit({ type: \"SET_SELECTION_RANGE\", range: this.state.range });\r\n }\r\n\r\n // ===========================================================================\r\n // Data Extraction\r\n // ===========================================================================\r\n\r\n /**\r\n * Get the data from the currently selected cells as a 2D array.\r\n */\r\n getSelectedData(): CellValue[][] {\r\n const { range, activeCell } = this.state;\r\n\r\n if (!range && !activeCell) {\r\n return [];\r\n }\r\n\r\n const effectiveRange = range || {\r\n startRow: activeCell!.row,\r\n startCol: activeCell!.col,\r\n endRow: activeCell!.row,\r\n endCol: activeCell!.col,\r\n };\r\n\r\n const minRow = Math.min(effectiveRange.startRow, effectiveRange.endRow);\r\n const maxRow = Math.max(effectiveRange.startRow, effectiveRange.endRow);\r\n const minCol = Math.min(effectiveRange.startCol, effectiveRange.endCol);\r\n const maxCol = Math.max(effectiveRange.startCol, effectiveRange.endCol);\r\n\r\n const data: CellValue[][] = [];\r\n\r\n for (let r = minRow; r <= maxRow; r++) {\r\n const row: CellValue[] = [];\r\n for (let c = minCol; c <= maxCol; c++) {\r\n row.push(this.options.getCellValue(r, c));\r\n }\r\n data.push(row);\r\n }\r\n\r\n return data;\r\n }\r\n\r\n /**\r\n * Copy the selected data to the clipboard (Ctrl+C).\r\n */\r\n async copySelectionToClipboard(): Promise<void> {\r\n const data = this.getSelectedData();\r\n if (data.length === 0) return;\r\n\r\n // Convert to tab-separated values (Excel-compatible)\r\n const tsv = data\r\n .map((row) =>\r\n row.map((cell) => (cell == null ? \"\" : String(cell))).join(\"\\t\")\r\n )\r\n .join(\"\\n\");\r\n\r\n try {\r\n await navigator.clipboard.writeText(tsv);\r\n } catch (err) {\r\n // Fallback for older browsers\r\n const textarea = document.createElement(\"textarea\");\r\n textarea.value = tsv;\r\n textarea.style.position = \"fixed\";\r\n textarea.style.left = \"-9999px\";\r\n document.body.appendChild(textarea);\r\n textarea.select();\r\n document.execCommand(\"copy\");\r\n document.body.removeChild(textarea);\r\n }\r\n }\r\n\r\n // ===========================================================================\r\n // Helpers\r\n // ===========================================================================\r\n\r\n private clampPosition(pos: CellPosition): CellPosition {\r\n const rowCount = this.options.getRowCount();\r\n const colCount = this.options.getColumnCount();\r\n\r\n return {\r\n row: Math.max(0, Math.min(pos.row, rowCount - 1)),\r\n col: Math.max(0, Math.min(pos.col, colCount - 1)),\r\n };\r\n }\r\n}\r\n\r\n","// gp-grid-core/src/fill.ts\r\n\r\nimport type {\r\n CellRange,\r\n CellValue,\r\n FillHandleState,\r\n GridInstruction,\r\n InstructionListener,\r\n ColumnDefinition,\r\n} from \"./types\";\r\n\r\nexport interface FillManagerOptions {\r\n getRowCount: () => number;\r\n getColumnCount: () => number;\r\n getCellValue: (row: number, col: number) => CellValue;\r\n getColumn: (col: number) => ColumnDefinition | undefined;\r\n setCellValue: (row: number, col: number, value: CellValue) => void;\r\n}\r\n\r\n/**\r\n * Manages fill handle operations including pattern detection and auto-fill.\r\n */\r\nexport class FillManager {\r\n private state: FillHandleState | null = null;\r\n private options: FillManagerOptions;\r\n private listeners: InstructionListener[] = [];\r\n\r\n constructor(options: FillManagerOptions) {\r\n this.options = options;\r\n }\r\n\r\n // ===========================================================================\r\n // Instruction Emission\r\n // ===========================================================================\r\n\r\n onInstruction(listener: InstructionListener): () => void {\r\n this.listeners.push(listener);\r\n return () => {\r\n this.listeners = this.listeners.filter((l) => l !== listener);\r\n };\r\n }\r\n\r\n private emit(instruction: GridInstruction): void {\r\n for (const listener of this.listeners) {\r\n listener(instruction);\r\n }\r\n }\r\n\r\n // ===========================================================================\r\n // State Accessors\r\n // ===========================================================================\r\n\r\n getState(): FillHandleState | null {\r\n return this.state ? { ...this.state } : null;\r\n }\r\n\r\n isActive(): boolean {\r\n return this.state !== null;\r\n }\r\n\r\n // ===========================================================================\r\n // Fill Handle Operations\r\n // ===========================================================================\r\n\r\n /**\r\n * Start a fill drag operation from a source range.\r\n */\r\n startFillDrag(sourceRange: CellRange): void {\r\n this.state = {\r\n sourceRange,\r\n targetRow: sourceRange.endRow,\r\n targetCol: sourceRange.endCol,\r\n };\r\n\r\n this.emit({ type: \"START_FILL\", sourceRange });\r\n }\r\n\r\n /**\r\n * Update the fill drag target position.\r\n */\r\n updateFillDrag(targetRow: number, targetCol: number): void {\r\n if (!this.state) return;\r\n\r\n // Clamp to valid bounds\r\n const rowCount = this.options.getRowCount();\r\n const colCount = this.options.getColumnCount();\r\n\r\n targetRow = Math.max(0, Math.min(targetRow, rowCount - 1));\r\n targetCol = Math.max(0, Math.min(targetCol, colCount - 1));\r\n\r\n this.state.targetRow = targetRow;\r\n this.state.targetCol = targetCol;\r\n\r\n this.emit({ type: \"UPDATE_FILL\", targetRow, targetCol });\r\n }\r\n\r\n /**\r\n * Commit the fill operation - apply pattern to target cells.\r\n */\r\n commitFillDrag(): void {\r\n if (!this.state) return;\r\n\r\n const { sourceRange, targetRow, targetCol } = this.state;\r\n const filledCells = this.calculateFilledCells(sourceRange, targetRow, targetCol);\r\n\r\n // Apply values\r\n for (const { row, col, value } of filledCells) {\r\n this.options.setCellValue(row, col, value);\r\n }\r\n\r\n this.emit({ type: \"COMMIT_FILL\", filledCells });\r\n\r\n this.state = null;\r\n }\r\n\r\n /**\r\n * Cancel the fill operation.\r\n */\r\n cancelFillDrag(): void {\r\n if (!this.state) return;\r\n\r\n this.state = null;\r\n this.emit({ type: \"CANCEL_FILL\" });\r\n }\r\n\r\n // ===========================================================================\r\n // Pattern Detection & Fill Logic\r\n // ===========================================================================\r\n\r\n /**\r\n * Calculate the values to fill based on source pattern.\r\n */\r\n private calculateFilledCells(\r\n sourceRange: CellRange,\r\n targetRow: number,\r\n targetCol: number\r\n ): Array<{ row: number; col: number; value: CellValue }> {\r\n const result: Array<{ row: number; col: number; value: CellValue }> = [];\r\n\r\n const srcMinRow = Math.min(sourceRange.startRow, sourceRange.endRow);\r\n const srcMaxRow = Math.max(sourceRange.startRow, sourceRange.endRow);\r\n const srcMinCol = Math.min(sourceRange.startCol, sourceRange.endCol);\r\n const srcMaxCol = Math.max(sourceRange.startCol, sourceRange.endCol);\r\n\r\n // Determine fill direction\r\n const fillDown = targetRow > srcMaxRow;\r\n const fillUp = targetRow < srcMinRow;\r\n const fillRight = targetCol > srcMaxCol;\r\n const fillLeft = targetCol < srcMinCol;\r\n\r\n // For now, we only support vertical fills (most common use case)\r\n if (fillDown || fillUp) {\r\n for (let col = srcMinCol; col <= srcMaxCol; col++) {\r\n const sourceValues = this.getSourceColumnValues(srcMinRow, srcMaxRow, col);\r\n const pattern = this.detectPattern(sourceValues);\r\n\r\n if (fillDown) {\r\n for (let row = srcMaxRow + 1; row <= targetRow; row++) {\r\n const fillIndex = row - srcMaxRow - 1;\r\n const value = this.applyPattern(pattern, sourceValues, fillIndex);\r\n result.push({ row, col, value });\r\n }\r\n } else if (fillUp) {\r\n for (let row = srcMinRow - 1; row >= targetRow; row--) {\r\n const fillIndex = srcMinRow - row - 1;\r\n const value = this.applyPattern(pattern, sourceValues, fillIndex, true);\r\n result.push({ row, col, value });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Horizontal fill\r\n if (fillRight || fillLeft) {\r\n for (let row = srcMinRow; row <= srcMaxRow; row++) {\r\n const sourceValues = this.getSourceRowValues(srcMinCol, srcMaxCol, row);\r\n const pattern = this.detectPattern(sourceValues);\r\n\r\n if (fillRight) {\r\n for (let col = srcMaxCol + 1; col <= targetCol; col++) {\r\n const fillIndex = col - srcMaxCol - 1;\r\n const value = this.applyPattern(pattern, sourceValues, fillIndex);\r\n result.push({ row, col, value });\r\n }\r\n } else if (fillLeft) {\r\n for (let col = srcMinCol - 1; col >= targetCol; col--) {\r\n const fillIndex = srcMinCol - col - 1;\r\n const value = this.applyPattern(pattern, sourceValues, fillIndex, true);\r\n result.push({ row, col, value });\r\n }\r\n }\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n private getSourceColumnValues(minRow: number, maxRow: number, col: number): CellValue[] {\r\n const values: CellValue[] = [];\r\n for (let row = minRow; row <= maxRow; row++) {\r\n values.push(this.options.getCellValue(row, col));\r\n }\r\n return values;\r\n }\r\n\r\n private getSourceRowValues(minCol: number, maxCol: number, row: number): CellValue[] {\r\n const values: CellValue[] = [];\r\n for (let col = minCol; col <= maxCol; col++) {\r\n values.push(this.options.getCellValue(row, col));\r\n }\r\n return values;\r\n }\r\n\r\n // ===========================================================================\r\n // Pattern Types\r\n // ===========================================================================\r\n\r\n private detectPattern(values: CellValue[]): FillPattern {\r\n if (values.length === 0) {\r\n return { type: \"constant\", value: null };\r\n }\r\n\r\n if (values.length === 1) {\r\n return { type: \"constant\", value: values[0] ?? null };\r\n }\r\n\r\n // Check for numeric sequence\r\n const numbers = values.map((v) => (typeof v === \"number\" ? v : Number(v)));\r\n if (numbers.every((n) => !isNaN(n))) {\r\n // Check for arithmetic sequence\r\n const diffs: number[] = [];\r\n for (let i = 1; i < numbers.length; i++) {\r\n diffs.push(numbers[i]! - numbers[i - 1]!);\r\n }\r\n\r\n const allSameDiff = diffs.every((d) => d === diffs[0]);\r\n if (allSameDiff && diffs[0] !== undefined) {\r\n return { type: \"arithmetic\", start: numbers[0]!, step: diffs[0] };\r\n }\r\n }\r\n\r\n // Check for repeating pattern\r\n return { type: \"repeat\", values };\r\n }\r\n\r\n private applyPattern(\r\n pattern: FillPattern,\r\n sourceValues: CellValue[],\r\n fillIndex: number,\r\n reverse: boolean = false\r\n ): CellValue {\r\n switch (pattern.type) {\r\n case \"constant\":\r\n return pattern.value;\r\n\r\n case \"arithmetic\": {\r\n const multiplier = reverse ? -(fillIndex + 1) : fillIndex + 1;\r\n const lastValue = reverse ? pattern.start : pattern.start + pattern.step * (sourceValues.length - 1);\r\n return lastValue + pattern.step * multiplier;\r\n }\r\n\r\n case \"repeat\": {\r\n const len = pattern.values.length;\r\n if (len === 0) return null;\r\n if (reverse) {\r\n // For reverse, cycle backwards\r\n const idx = (len - 1 - (fillIndex % len) + len) % len;\r\n return pattern.values[idx] ?? null;\r\n }\r\n return pattern.values[fillIndex % len] ?? null;\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ===========================================================================\r\n// Pattern Types\r\n// ===========================================================================\r\n\r\ntype FillPattern =\r\n | { type: \"constant\"; value: CellValue }\r\n | { type: \"arithmetic\"; start: number; step: number }\r\n | { type: \"repeat\"; values: CellValue[] };\r\n\r\n","// gp-grid-core/src/grid-core.ts\r\n\r\nimport type {\r\n GridCoreOptions,\r\n GridInstruction,\r\n InstructionListener,\r\n BatchInstructionListener,\r\n ColumnDefinition,\r\n CellValue,\r\n CellPosition,\r\n CellRange,\r\n DataSource,\r\n DataSourceRequest,\r\n Row,\r\n SortModel,\r\n SortDirection,\r\n FilterModel,\r\n SlotState,\r\n EditState,\r\n} from \"./types\";\r\nimport { SelectionManager } from \"./selection\";\r\nimport { FillManager } from \"./fill\";\r\n\r\n// =============================================================================\r\n// Slot Pool Manager\r\n// =============================================================================\r\n\r\ninterface SlotPoolState {\r\n slots: Map<string, SlotState>;\r\n /** Maps rowIndex to slotId for quick lookup */\r\n rowToSlot: Map<number, string>;\r\n nextSlotId: number;\r\n}\r\n\r\n// =============================================================================\r\n// GridCore\r\n// =============================================================================\r\n\r\nexport class GridCore<TData extends Row = Row> {\r\n // Configuration\r\n private columns: ColumnDefinition[];\r\n private dataSource: DataSource<TData>;\r\n private rowHeight: number;\r\n private headerHeight: number;\r\n private overscan: number;\r\n\r\n // Viewport state\r\n private scrollTop: number = 0;\r\n private scrollLeft: number = 0;\r\n private viewportWidth: number = 800;\r\n private viewportHeight: number = 600;\r\n\r\n // Data state\r\n private cachedRows: Map<number, TData> = new Map();\r\n private totalRows: number = 0;\r\n private currentPageIndex: number = 0;\r\n // Use large page size to avoid excessive pagination for client-side data sources\r\n private pageSize: number = 1000000;\r\n\r\n // Sort & Filter\r\n private sortModel: SortModel[] = [];\r\n private filterModel: FilterModel = {};\r\n\r\n // Slot pool\r\n private slotPool: SlotPoolState = {\r\n slots: new Map(),\r\n rowToSlot: new Map(),\r\n nextSlotId: 0,\r\n };\r\n\r\n // Managers\r\n public readonly selection: SelectionManager;\r\n public readonly fill: FillManager;\r\n\r\n // Edit state\r\n private editState: EditState | null = null;\r\n\r\n // Column positions (computed)\r\n private columnPositions: number[] = [];\r\n\r\n // Instruction listeners\r\n private listeners: InstructionListener[] = [];\r\n private batchListeners: BatchInstructionListener[] = [];\r\n\r\n constructor(options: GridCoreOptions<TData>) {\r\n this.columns = options.columns;\r\n this.dataSource = options.dataSource;\r\n this.rowHeight = options.rowHeight;\r\n this.headerHeight = options.headerHeight ?? options.rowHeight;\r\n this.overscan = options.overscan ?? 3;\r\n\r\n this.computeColumnPositions();\r\n\r\n // Initialize selection manager\r\n this.selection = new SelectionManager({\r\n getRowCount: () => this.totalRows,\r\n getColumnCount: () => this.columns.length,\r\n getCellValue: (row, col) => this.getCellValue(row, col),\r\n getRowData: (row) => this.cachedRows.get(row),\r\n getColumn: (col) => this.columns[col],\r\n });\r\n\r\n // Forward selection instructions\r\n this.selection.onInstruction((instruction) => this.emit(instruction));\r\n\r\n // Initialize fill manager\r\n this.fill = new FillManager({\r\n getRowCount: () => this.totalRows,\r\n getColumnCount: () => this.columns.length,\r\n getCellValue: (row, col) => this.getCellValue(row, col),\r\n getColumn: (col) => this.columns[col],\r\n setCellValue: (row, col, value) => this.setCellValue(row, col, value),\r\n });\r\n\r\n // Forward fill instructions\r\n this.fill.onInstruction((instruction) => this.emit(instruction));\r\n }\r\n\r\n // ===========================================================================\r\n // Instruction System\r\n // ===========================================================================\r\n\r\n onInstruction(listener: InstructionListener): () => void {\r\n this.listeners.push(listener);\r\n return () => {\r\n this.listeners = this.listeners.filter((l) => l !== listener);\r\n };\r\n }\r\n\r\n /**\r\n * Subscribe to batched instructions for efficient React state updates.\r\n * Batch listeners receive arrays of instructions instead of individual ones.\r\n */\r\n onBatchInstruction(listener: BatchInstructionListener): () => void {\r\n this.batchListeners.push(listener);\r\n return () => {\r\n this.batchListeners = this.batchListeners.filter((l) => l !== listener);\r\n };\r\n }\r\n\r\n private emit(instruction: GridInstruction): void {\r\n // console.log(\"[GP-Grid Core] emit:\", instruction.type, { \r\n // listenerCount: this.listeners.length, \r\n // batchListenerCount: this.batchListeners.length \r\n // });\r\n // Emit to individual listeners\r\n for (const listener of this.listeners) {\r\n listener(instruction);\r\n }\r\n // Also emit as a single-item batch\r\n for (const listener of this.batchListeners) {\r\n listener([instruction]);\r\n }\r\n }\r\n\r\n private emitBatch(instructions: GridInstruction[]): void {\r\n if (instructions.length === 0) return;\r\n \r\n // console.log(\"[GP-Grid Core] emitBatch:\", instructions.map(i => i.type), {\r\n // batchListenerCount: this.batchListeners.length\r\n // });\r\n // Emit to batch listeners as a single batch\r\n for (const listener of this.batchListeners) {\r\n listener(instructions);\r\n }\r\n // Also emit to individual listeners for backwards compatibility\r\n for (const instruction of instructions) {\r\n for (const listener of this.listeners) {\r\n listener(instruction);\r\n }\r\n }\r\n }\r\n\r\n // ===========================================================================\r\n // Initialization\r\n // ===========================================================================\r\n\r\n /**\r\n * Initialize the grid and load initial data.\r\n */\r\n async initialize(): Promise<void> {\r\n await this.fetchData();\r\n this.syncSlots();\r\n this.emitContentSize();\r\n this.emitHeaders();\r\n }\r\n\r\n // ===========================================================================\r\n // Viewport Management\r\n // ===========================================================================\r\n\r\n /**\r\n * Update viewport measurements and sync slots.\r\n */\r\n setViewport(\r\n scrollTop: number,\r\n scrollLeft: number,\r\n width: number,\r\n height: number\r\n ): void {\r\n const changed =\r\n this.scrollTop !== scrollTop ||\r\n this.scrollLeft !== scrollLeft ||\r\n this.viewportWidth !== width ||\r\n this.viewportHeight !== height;\r\n\r\n if (!changed) return;\r\n\r\n this.scrollTop = scrollTop;\r\n this.scrollLeft = scrollLeft;\r\n this.viewportWidth = width;\r\n this.viewportHeight = height;\r\n\r\n this.syncSlots();\r\n }\r\n\r\n // ===========================================================================\r\n // Slot Pool Management (Virtual Scroll)\r\n // ===========================================================================\r\n\r\n /**\r\n * Synchronize slots with current viewport position.\r\n * This implements the slot recycling strategy.\r\n */\r\n private syncSlots(): void {\r\n const visibleStartRow = Math.max(0, Math.floor(this.scrollTop / this.rowHeight) - this.overscan);\r\n const visibleEndRow = Math.min(\r\n this.totalRows - 1,\r\n Math.ceil((this.scrollTop + this.viewportHeight) / this.rowHeight) + this.overscan\r\n );\r\n\r\n if (this.totalRows === 0 || visibleEndRow < visibleStartRow) {\r\n // No rows to display - destroy all slots\r\n this.destroyAllSlots();\r\n return;\r\n }\r\n\r\n const requiredRows = new Set<number>();\r\n for (let row = visibleStartRow; row <= visibleEndRow; row++) {\r\n requiredRows.add(row);\r\n }\r\n\r\n const instructions: GridInstruction[] = [];\r\n\r\n // Find slots that are no longer needed\r\n const slotsToRecycle: string[] = [];\r\n for (const [slotId, slot] of this.slotPool.slots) {\r\n if (!requiredRows.has(slot.rowIndex)) {\r\n slotsToRecycle.push(slotId);\r\n this.slotPool.rowToSlot.delete(slot.rowIndex);\r\n } else {\r\n requiredRows.delete(slot.rowIndex);\r\n }\r\n }\r\n\r\n // Assign recycled slots to new rows\r\n const rowsNeedingSlots = Array.from(requiredRows);\r\n for (let i = 0; i < rowsNeedingSlots.length; i++) {\r\n const rowIndex = rowsNeedingSlots[i]!;\r\n const rowData = this.cachedRows.get(rowIndex);\r\n\r\n if (i < slotsToRecycle.length) {\r\n // Recycle existing slot\r\n const slotId = slotsToRecycle[i]!;\r\n const slot = this.slotPool.slots.get(slotId)!;\r\n const translateY = this.getRowTranslateY(rowIndex);\r\n\r\n slot.rowIndex = rowIndex;\r\n slot.rowData = rowData ?? {};\r\n slot.translateY = translateY;\r\n\r\n this.slotPool.rowToSlot.set(rowIndex, slotId);\r\n\r\n instructions.push({\r\n type: \"ASSIGN_SLOT\",\r\n slotId,\r\n rowIndex,\r\n rowData: rowData ?? {},\r\n });\r\n instructions.push({\r\n type: \"MOVE_SLOT\",\r\n slotId,\r\n translateY,\r\n });\r\n } else {\r\n // Create new slot\r\n const slotId = `slot-${this.slotPool.nextSlotId++}`;\r\n const translateY = this.getRowTranslateY(rowIndex);\r\n\r\n const newSlot: SlotState = {\r\n slotId,\r\n rowIndex,\r\n rowData: rowData ?? {},\r\n translateY,\r\n };\r\n\r\n this.slotPool.slots.set(slotId, newSlot);\r\n this.slotPool.rowToSlot.set(rowIndex, slotId);\r\n\r\n instructions.push({ type: \"CREATE_SLOT\", slotId });\r\n instructions.push({\r\n type: \"ASSIGN_SLOT\",\r\n slotId,\r\n rowIndex,\r\n rowData: rowData ?? {},\r\n });\r\n instructions.push({\r\n type: \"MOVE_SLOT\",\r\n slotId,\r\n translateY,\r\n });\r\n }\r\n }\r\n\r\n // Destroy excess slots\r\n for (let i = rowsNeedingSlots.length; i < slotsToRecycle.length; i++) {\r\n const slotId = slotsToRecycle[i]!;\r\n this.slotPool.slots.delete(slotId);\r\n instructions.push({ type: \"DESTROY_SLOT\", slotId });\r\n }\r\n\r\n // Update positions of existing slots that haven't moved\r\n for (const [slotId, slot] of this.slotPool.slots) {\r\n const expectedY = this.getRowTranslateY(slot.rowIndex);\r\n if (slot.translateY !== expectedY) {\r\n slot.translateY = expectedY;\r\n instructions.push({\r\n type: \"MOVE_SLOT\",\r\n slotId,\r\n translateY: expectedY,\r\n });\r\n }\r\n }\r\n\r\n this.emitBatch(instructions);\r\n }\r\n\r\n private destroyAllSlots(): void {\r\n const instructions: GridInstruction[] = [];\r\n for (const slotId of this.slotPool.slots.keys()) {\r\n instructions.push({ type: \"DESTROY_SLOT\", slotId });\r\n }\r\n this.slotPool.slots.clear();\r\n this.slotPool.rowToSlot.clear();\r\n this.emitBatch(instructions);\r\n }\r\n\r\n private getRowTranslateY(rowIndex: number): number {\r\n return rowIndex * this.rowHeight + this.headerHeight;\r\n }\r\n\r\n // ===========================================================================\r\n // Data Fetching\r\n // ===========================================================================\r\n\r\n private async fetchData(): Promise<void> {\r\n this.emit({ type: \"DATA_LOADING\" });\r\n\r\n try {\r\n const request: DataSourceRequest = {\r\n pagination: {\r\n pageIndex: this.currentPageIndex,\r\n pageSize: this.pageSize,\r\n },\r\n sort: this.sortModel.length > 0 ? this.sortModel : undefined,\r\n filter: Object.keys(this.filterModel).length > 0 ? this.filterModel : undefined,\r\n };\r\n\r\n const response = await this.dataSource.fetch(request);\r\n\r\n // Cache the fetched rows\r\n this.cachedRows.clear();\r\n response.rows.forEach((row, index) => {\r\n this.cachedRows.set(this.currentPageIndex * this.pageSize + index, row);\r\n });\r\n\r\n this.totalRows = response.totalRows;\r\n\r\n // For client-side data source, fetch all data for simplicity\r\n // (the client data source handles filtering/sorting internally)\r\n if (response.totalRows > response.rows.length && this.currentPageIndex === 0) {\r\n // Fetch all remaining pages for client-side mode\r\n await this.fetchAllData();\r\n }\r\n\r\n this.emit({ type: \"DATA_LOADED\", totalRows: this.totalRows });\r\n } catch (error) {\r\n this.emit({\r\n type: \"DATA_ERROR\",\r\n error: error instanceof Error ? error.message : String(error),\r\n });\r\n }\r\n }\r\n\r\n private async fetchAllData(): Promise<void> {\r\n // Fetch all data in chunks for client-side data source\r\n const totalPages = Math.ceil(this.totalRows / this.pageSize);\r\n\r\n for (let page = 1; page < totalPages; page++) {\r\n const request: DataSourceRequest = {\r\n pagination: {\r\n pageIndex: page,\r\n pageSize: this.pageSize,\r\n },\r\n sort: this.sortModel.length > 0 ? this.sortModel : undefined,\r\n filter: Object.keys(this.filterModel).length > 0 ? this.filterModel : undefined,\r\n };\r\n\r\n const response = await this.dataSource.fetch(request);\r\n response.rows.forEach((row, index) => {\r\n this.cachedRows.set(page * this.pageSize + index, row);\r\n });\r\n }\r\n }\r\n\r\n // ===========================================================================\r\n // Sort & Filter\r\n // ===========================================================================\r\n\r\n async setSort(\r\n colId: string,\r\n direction: SortDirection | null,\r\n addToExisting: boolean = false\r\n ): Promise<void> {\r\n // console.log(\"[GP-Grid Core] setSort:\", { colId, direction, addToExisting });\r\n const existingIndex = this.sortModel.findIndex((s) => s.colId === colId);\r\n\r\n if (!addToExisting) {\r\n this.sortModel = direction === null ? [] : [{ colId, direction }];\r\n } else {\r\n if (direction === null) {\r\n if (existingIndex >= 0) {\r\n this.sortModel.splice(existingIndex, 1);\r\n }\r\n } else if (existingIndex >= 0) {\r\n this.sortModel[existingIndex]!.direction = direction;\r\n } else {\r\n this.sortModel.push({ colId, direction });\r\n }\r\n }\r\n\r\n // console.log(\"[GP-Grid Core] setSort - fetching sorted data...\");\r\n await this.fetchData();\r\n // Refresh all slots with newly sorted data\r\n this.refreshAllSlots();\r\n this.emitHeaders();\r\n // console.log(\"[GP-Grid Core] setSort - complete\");\r\n }\r\n\r\n async setFilter(colId: string, value: string): Promise<void> {\r\n if (value === \"\") {\r\n delete this.filterModel[colId];\r\n } else {\r\n this.filterModel[colId] = value;\r\n }\r\n\r\n await this.fetchData();\r\n // Force refresh all slots since filtered data changed\r\n this.refreshAllSlots();\r\n this.emitContentSize();\r\n }\r\n\r\n /**\r\n * Force refresh all slot data (used after filtering/sorting when data changes)\r\n */\r\n private refreshAllSlots(): void {\r\n const instructions: GridInstruction[] = [];\r\n\r\n for (const [slotId, slot] of this.slotPool.slots) {\r\n // Check if row index is still valid\r\n if (slot.rowIndex >= 0 && slot.rowIndex < this.totalRows) {\r\n const rowData = this.cachedRows.get(slot.rowIndex);\r\n const translateY = this.getRowTranslateY(slot.rowIndex);\r\n\r\n slot.rowData = rowData ?? {};\r\n slot.translateY = translateY;\r\n\r\n instructions.push({\r\n type: \"ASSIGN_SLOT\",\r\n slotId,\r\n rowIndex: slot.rowIndex,\r\n rowData: rowData ?? {},\r\n });\r\n instructions.push({\r\n type: \"MOVE_SLOT\",\r\n slotId,\r\n translateY,\r\n });\r\n }\r\n }\r\n\r\n this.emitBatch(instructions);\r\n\r\n // Also sync slots to handle any rows that went out of bounds\r\n this.syncSlots();\r\n }\r\n\r\n getSortModel(): SortModel[] {\r\n return [...this.sortModel];\r\n }\r\n\r\n getFilterModel(): FilterModel {\r\n return { ...this.filterModel };\r\n }\r\n\r\n // ===========================================================================\r\n // Editing\r\n // ===========================================================================\r\n\r\n startEdit(row: number, col: number): void {\r\n const column = this.columns[col];\r\n if (!column || column.editable !== true) return;\r\n\r\n const initialValue = this.getCellValue(row, col);\r\n this.editState = {\r\n row,\r\n col,\r\n initialValue,\r\n currentValue: initialValue,\r\n };\r\n\r\n this.emit({\r\n type: \"START_EDIT\",\r\n row,\r\n col,\r\n initialValue,\r\n });\r\n }\r\n\r\n updateEditValue(value: CellValue): void {\r\n if (this.editState) {\r\n this.editState.currentValue = value;\r\n }\r\n }\r\n\r\n commitEdit(): void {\r\n if (!this.editState) return;\r\n\r\n const { row, col, currentValue } = this.editState;\r\n this.setCellValue(row, col, currentValue);\r\n\r\n this.emit({\r\n type: \"COMMIT_EDIT\",\r\n row,\r\n col,\r\n value: currentValue,\r\n });\r\n\r\n this.editState = null;\r\n this.emit({ type: \"STOP_EDIT\" });\r\n\r\n // Update the slot displaying this row\r\n const slotId = this.slotPool.rowToSlot.get(row);\r\n if (slotId) {\r\n const rowData = this.cachedRows.get(row);\r\n if (rowData) {\r\n this.emit({\r\n type: \"ASSIGN_SLOT\",\r\n slotId,\r\n rowIndex: row,\r\n rowData,\r\n });\r\n }\r\n }\r\n }\r\n\r\n cancelEdit(): void {\r\n this.editState = null;\r\n this.emit({ type: \"STOP_EDIT\" });\r\n }\r\n\r\n getEditState(): EditState | null {\r\n return this.editState ? { ...this.editState } : null;\r\n }\r\n\r\n // ===========================================================================\r\n // Cell Value Access\r\n // ===========================================================================\r\n\r\n getCellValue(row: number, col: number): CellValue {\r\n const rowData = this.cachedRows.get(row);\r\n if (!rowData) return null;\r\n\r\n const column = this.columns[col];\r\n if (!column) return null;\r\n\r\n return this.getFieldValue(rowData, column.field);\r\n }\r\n\r\n setCellValue(row: number, col: number, value: CellValue): void {\r\n const rowData = this.cachedRows.get(row);\r\n if (!rowData || typeof rowData !== \"object\") return;\r\n\r\n const column = this.columns[col];\r\n if (!column) return;\r\n\r\n this.setFieldValue(rowData as Record<string, unknown>, column.field, value);\r\n }\r\n\r\n private getFieldValue(data: TData, field: string): CellValue {\r\n const parts = field.split(\".\");\r\n let value: unknown = data;\r\n\r\n for (const part of parts) {\r\n if (value == null || typeof value !== \"object\") {\r\n return null;\r\n }\r\n value = (value as Record<string, unknown>)[part];\r\n }\r\n\r\n return (value ?? null) as CellValue;\r\n }\r\n\r\n private setFieldValue(data: Record<string, unknown>, field: string, value: CellValue): void {\r\n const parts = field.split(\".\");\r\n let obj = data;\r\n\r\n for (let i = 0; i < parts.length - 1; i++) {\r\n const part = parts[i]!;\r\n if (!(part in obj)) {\r\n obj[part] = {};\r\n }\r\n obj = obj[part] as Record<string, unknown>;\r\n }\r\n\r\n const lastPart = parts[parts.length - 1]!;\r\n obj[lastPart] = value;\r\n }\r\n\r\n // ===========================================================================\r\n // Layout Helpers\r\n // ===========================================================================\r\n\r\n private computeColumnPositions(): void {\r\n this.columnPositions = [0];\r\n let pos = 0;\r\n for (const col of this.columns) {\r\n pos += col.width;\r\n this.columnPositions.push(pos);\r\n }\r\n }\r\n\r\n private emitContentSize(): void {\r\n const width = this.columnPositions[this.columnPositions.length - 1] ?? 0;\r\n const height = this.totalRows * this.rowHeight + this.headerHeight;\r\n this.emit({ type: \"SET_CONTENT_SIZE\", width, height });\r\n }\r\n\r\n private emitHeaders(): void {\r\n const sortInfoMap = new Map<string, { direction: SortDirection; index: number }>();\r\n this.sortModel.forEach((sort, index) => {\r\n sortInfoMap.set(sort.colId, { direction: sort.direction, index: index + 1 });\r\n });\r\n\r\n for (let i = 0; i < this.columns.length; i++) {\r\n const column = this.columns[i]!;\r\n const colId = column.colId ?? column.field;\r\n const sortInfo = sortInfoMap.get(colId);\r\n\r\n this.emit({\r\n type: \"UPDATE_HEADER\",\r\n colIndex: i,\r\n column,\r\n sortDirection: sortInfo?.direction,\r\n sortIndex: sortInfo?.index,\r\n });\r\n }\r\n }\r\n\r\n // ===========================================================================\r\n // Public Accessors\r\n // ===========================================================================\r\n\r\n getColumns(): ColumnDefinition[] {\r\n return this.columns;\r\n }\r\n\r\n getColumnPositions(): number[] {\r\n return [...this.columnPositions];\r\n }\r\n\r\n getRowCount(): number {\r\n return this.totalRows;\r\n }\r\n\r\n getRowHeight(): number {\r\n return this.rowHeight;\r\n }\r\n\r\n getHeaderHeight(): number {\r\n return this.headerHeight;\r\n }\r\n\r\n getTotalWidth(): number {\r\n return this.columnPositions[this.columnPositions.length - 1] ?? 0;\r\n }\r\n\r\n getTotalHeight(): number {\r\n return this.totalRows * this.rowHeight + this.headerHeight;\r\n }\r\n\r\n getRowData(rowIndex: number): TData | undefined {\r\n return this.cachedRows.get(rowIndex);\r\n }\r\n\r\n // ===========================================================================\r\n // Data Updates\r\n // ===========================================================================\r\n\r\n /**\r\n * Refresh data from the data source.\r\n */\r\n async refresh(): Promise<void> {\r\n await this.fetchData();\r\n this.syncSlots();\r\n this.emitContentSize();\r\n }\r\n\r\n /**\r\n * Refresh slot display without refetching data.\r\n * Useful after in-place data modifications like fill operations.\r\n */\r\n refreshSlotData(): void {\r\n this.refreshAllSlots();\r\n }\r\n\r\n /**\r\n * Update the data source and refresh.\r\n */\r\n async setDataSource(dataSource: DataSource<TData>): Promise<void> {\r\n this.dataSource = dataSource;\r\n await this.refresh();\r\n }\r\n\r\n /**\r\n * Update columns and recompute layout.\r\n */\r\n setColumns(columns: ColumnDefinition[]): void {\r\n this.columns = columns;\r\n this.computeColumnPositions();\r\n this.emitContentSize();\r\n this.emitHeaders();\r\n this.syncSlots();\r\n }\r\n}\r\n\r\n","// gp-grid-core/src/data-source.ts\r\n\r\nimport type {\r\n DataSource,\r\n DataSourceRequest,\r\n DataSourceResponse,\r\n Row,\r\n SortModel,\r\n FilterModel,\r\n CellValue,\r\n} from \"./types\";\r\n\r\n// =============================================================================\r\n// Client Data Source (In-Memory)\r\n// =============================================================================\r\n\r\n/**\r\n * Creates a client-side data source that holds all data in memory.\r\n * Sorting and filtering are performed client-side.\r\n */\r\nexport function createClientDataSource<TData extends Row = Row>(\r\n data: TData[],\r\n options: {\r\n /** Custom field accessor for nested properties */\r\n getFieldValue?: (row: TData, field: string) => CellValue;\r\n } = {}\r\n): DataSource<TData> {\r\n const { getFieldValue = defaultGetFieldValue } = options;\r\n\r\n return {\r\n async fetch(request: DataSourceRequest): Promise<DataSourceResponse<TData>> {\r\n let processedData = [...data];\r\n\r\n // Apply filters\r\n if (request.filter && Object.keys(request.filter).length > 0) {\r\n processedData = applyFilters(processedData, request.filter, getFieldValue);\r\n }\r\n\r\n // Apply sorting\r\n if (request.sort && request.sort.length > 0) {\r\n processedData = applySort(processedData, request.sort, getFieldValue);\r\n }\r\n\r\n const totalRows = processedData.length;\r\n\r\n // Apply pagination\r\n const { pageIndex, pageSize } = request.pagination;\r\n const startIndex = pageIndex * pageSize;\r\n const rows = processedData.slice(startIndex, startIndex + pageSize);\r\n\r\n return { rows, totalRows };\r\n },\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// Server Data Source\r\n// =============================================================================\r\n\r\nexport type ServerFetchFunction<TData> = (\r\n request: DataSourceRequest\r\n) => Promise<DataSourceResponse<TData>>;\r\n\r\n/**\r\n * Creates a server-side data source that delegates all operations to the server.\r\n * The fetch function receives sort/filter/pagination params to pass to the API.\r\n */\r\nexport function createServerDataSource<TData extends Row = Row>(\r\n fetchFn: ServerFetchFunction<TData>\r\n): DataSource<TData> {\r\n return {\r\n async fetch(request: DataSourceRequest): Promise<DataSourceResponse<TData>> {\r\n return fetchFn(request);\r\n },\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// Helper Functions\r\n// =============================================================================\r\n\r\nfunction defaultGetFieldValue<TData>(row: TData, field: string): CellValue {\r\n const parts = field.split(\".\");\r\n let value: unknown = row;\r\n\r\n for (const part of parts) {\r\n if (value == null || typeof value !== \"object\") {\r\n return null;\r\n }\r\n value = (value as Record<string, unknown>)[part];\r\n }\r\n\r\n return (value ?? null) as CellValue;\r\n}\r\n\r\nfunction applyFilters<TData>(\r\n data: TData[],\r\n filterModel: FilterModel,\r\n getFieldValue: (row: TData, field: string) => CellValue\r\n): TData[] {\r\n const filterEntries = Object.entries(filterModel).filter(([, value]) => value !== \"\");\r\n\r\n if (filterEntries.length === 0) {\r\n return data;\r\n }\r\n\r\n return data.filter((row) => {\r\n for (const [field, filterValue] of filterEntries) {\r\n const cellValue = getFieldValue(row, field);\r\n const cellStr = String(cellValue ?? \"\").toLowerCase();\r\n const filterStr = filterValue.toLowerCase();\r\n\r\n if (!cellStr.includes(filterStr)) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n });\r\n}\r\n\r\nfunction applySort<TData>(\r\n data: TData[],\r\n sortModel: SortModel[],\r\n getFieldValue: (row: TData, field: string) => CellValue\r\n): TData[] {\r\n return [...data].sort((a, b) => {\r\n for (const { colId, direction } of sortModel) {\r\n const aVal = getFieldValue(a, colId);\r\n const bVal = getFieldValue(b, colId);\r\n const comparison = compareValues(aVal, bVal);\r\n\r\n if (comparison !== 0) {\r\n return direction === \"asc\" ? comparison : -comparison;\r\n }\r\n }\r\n return 0;\r\n });\r\n}\r\n\r\nfunction compareValues(a: CellValue, b: CellValue): number {\r\n // Null handling\r\n if (a == null && b == null) return 0;\r\n if (a == null) return 1;\r\n if (b == null) return -1;\r\n\r\n // Numeric comparison\r\n const aNum = Number(a);\r\n const bNum = Number(b);\r\n if (!isNaN(aNum) && !isNaN(bNum)) {\r\n return aNum - bNum;\r\n }\r\n\r\n // Date comparison\r\n if (a instanceof Date && b instanceof Date) {\r\n return a.getTime() - b.getTime();\r\n }\r\n\r\n // String comparison\r\n return String(a).localeCompare(String(b));\r\n}\r\n\r\n// =============================================================================\r\n// Utility: Create Data Source from Array (Legacy Support)\r\n// =============================================================================\r\n\r\n/**\r\n * Convenience function to create a data source from an array.\r\n * This provides backwards compatibility with the old `rowData` prop.\r\n */\r\nexport function createDataSourceFromArray<TData extends Row = Row>(\r\n data: TData[]\r\n): DataSource<TData> {\r\n return createClientDataSource(data);\r\n}\r\n\r\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "gp-grid-core",
3
+ "description": "A typescript library that enables grid creation",
4
+ "private": false,
5
+ "version": "0.1.0",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "author": "Giovanni Patruno (giovanni.patruno@outlook.com)",
9
+ "type": "module",
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "devDependencies": {
14
+ "@types/node": "^24.9.1",
15
+ "tsdown": "^0.15.9",
16
+ "typescript": "~5.8.3"
17
+ },
18
+ "scripts": {
19
+ "dev": "tsdown --watch",
20
+ "build": "tsdown",
21
+ "test": "vitest",
22
+ "test:ui": "vitest --ui",
23
+ "bench": "vitest bench"
24
+ }
25
+ }