@danielgindi/dgtable.js 2.0.7 → 2.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +547 -282
  2. package/dist/SelectionHelper.d.ts +24 -0
  3. package/dist/SelectionHelper.d.ts.map +1 -0
  4. package/dist/by_column_filter.d.ts +14 -0
  5. package/dist/by_column_filter.d.ts.map +1 -0
  6. package/dist/cell_preview.d.ts +28 -0
  7. package/dist/cell_preview.d.ts.map +1 -0
  8. package/dist/column_collection.d.ts +41 -0
  9. package/dist/column_collection.d.ts.map +1 -0
  10. package/dist/column_resize.d.ts +25 -0
  11. package/dist/column_resize.d.ts.map +1 -0
  12. package/dist/constants.d.ts +19 -0
  13. package/dist/constants.d.ts.map +1 -0
  14. package/dist/header_events.d.ts +63 -0
  15. package/dist/header_events.d.ts.map +1 -0
  16. package/dist/helpers.d.ts +50 -0
  17. package/dist/helpers.d.ts.map +1 -0
  18. package/dist/index.d.ts +166 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/internal.d.ts +56 -0
  21. package/dist/internal.d.ts.map +1 -0
  22. package/dist/lib.cjs.js +6909 -3929
  23. package/dist/lib.cjs.js.map +1 -1
  24. package/dist/lib.cjs.min.js +2 -2
  25. package/dist/lib.cjs.min.js.map +1 -1
  26. package/dist/lib.es6.js +6912 -3932
  27. package/dist/lib.es6.js.map +1 -1
  28. package/dist/lib.es6.min.js +2 -2
  29. package/dist/lib.es6.min.js.map +1 -1
  30. package/dist/lib.umd.js +9251 -4346
  31. package/dist/lib.umd.js.map +1 -1
  32. package/dist/lib.umd.min.js +2 -2
  33. package/dist/lib.umd.min.js.map +1 -1
  34. package/dist/private_types.d.ts +145 -0
  35. package/dist/private_types.d.ts.map +1 -0
  36. package/dist/rendering.d.ts +57 -0
  37. package/dist/rendering.d.ts.map +1 -0
  38. package/dist/row_collection.d.ts +38 -0
  39. package/dist/row_collection.d.ts.map +1 -0
  40. package/dist/types.d.ts +221 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/util.d.ts +9 -0
  43. package/dist/util.d.ts.map +1 -0
  44. package/eslint.config.mjs +1 -0
  45. package/package.json +26 -12
  46. package/src/SelectionHelper.ts +90 -0
  47. package/src/by_column_filter.ts +36 -0
  48. package/src/cell_preview.ts +325 -0
  49. package/src/column_collection.ts +131 -0
  50. package/src/column_resize.ts +363 -0
  51. package/src/constants.ts +22 -0
  52. package/src/header_events.ts +369 -0
  53. package/src/helpers.ts +291 -0
  54. package/src/index.ts +1628 -0
  55. package/src/internal.ts +263 -0
  56. package/src/private_types.ts +156 -0
  57. package/src/rendering.ts +771 -0
  58. package/src/row_collection.ts +197 -0
  59. package/src/types.ts +265 -0
  60. package/src/util.ts +27 -0
  61. package/tsconfig.json +38 -0
  62. package/src/SelectionHelper.js +0 -65
  63. package/src/by_column_filter.js +0 -25
  64. package/src/column_collection.js +0 -153
  65. package/src/index.js +0 -3991
  66. package/src/row_collection.js +0 -183
  67. package/src/util.js +0 -17
@@ -0,0 +1,263 @@
1
+ /**
2
+ * Internal helper functions for DGTable
3
+ * These are extracted from the class to avoid exposing them on the public API
4
+ */
5
+
6
+ import { ColumnWidthMode } from './constants';
7
+ import {
8
+ HoverInEventSymbol,
9
+ HoverOutEventSymbol,
10
+ PreviewCellSymbol,
11
+ OriginalCellSymbol,
12
+ IsSafeSymbol,
13
+ } from './private_types';
14
+ import { cellMouseOverEvent, cellMouseOutEvent } from './cell_preview';
15
+ import {
16
+ onMouseDownColumnHeader as resizeOnMouseDownColumnHeader,
17
+ } from './column_resize';
18
+ import {
19
+ onTouchStartColumnHeader,
20
+ onMouseMoveColumnHeader,
21
+ onMouseUpColumnHeader,
22
+ onMouseLeaveColumnHeader,
23
+ onSortOnColumnHeaderEvent,
24
+ onStartDragColumnHeader,
25
+ onDragEnterColumnHeader,
26
+ onDragOverColumnHeader,
27
+ onDragLeaveColumnHeader,
28
+ onDropColumnHeader,
29
+ } from './header_events';
30
+ import { syncHorizontalStickies } from './rendering';
31
+ import ByColumnFilter from './by_column_filter';
32
+ import type { ColumnOptions, FilterFunction, RowData } from './types';
33
+ import type { ColumnWidthModeType } from './constants';
34
+ import type { DGTablePrivateState, DGTableInternalOptions, InternalColumn } from './private_types';
35
+
36
+ /**
37
+ * Interface for the table instance passed to internal functions
38
+ */
39
+ export interface DGTableInternal {
40
+ el: HTMLElement;
41
+ _o: DGTableInternalOptions;
42
+ _p: DGTablePrivateState;
43
+ emit(event: string, value?: unknown): void;
44
+ }
45
+
46
+ /**
47
+ * Setup cell hover event handlers
48
+ */
49
+ export function setupHovers(table: DGTableInternal): void {
50
+ const p = table._p;
51
+
52
+ const hoverMouseOverHandler = (event: MouseEvent) => {
53
+ let cell = event.currentTarget as HTMLElement;
54
+ let target = event.relatedTarget as Node;
55
+ if (target === cell || cell.contains(target))
56
+ return;
57
+ if ((cell as any)[PreviewCellSymbol] &&
58
+ (target === (cell as any)[PreviewCellSymbol] || (cell as any)[PreviewCellSymbol].contains(target)))
59
+ return;
60
+ cellMouseOverEvent(table as any, cell);
61
+ };
62
+
63
+ const hoverMouseOutHandler = (event: MouseEvent) => {
64
+ let cell = ((event.currentTarget as any)[OriginalCellSymbol] || event.currentTarget) as HTMLElement;
65
+ let target = event.relatedTarget as Node;
66
+ if (target === table.el || cell.contains(target))
67
+ return;
68
+ if ((cell as any)[PreviewCellSymbol] &&
69
+ (target === (cell as any)[PreviewCellSymbol] || (cell as any)[PreviewCellSymbol].contains(target)))
70
+ return;
71
+ cellMouseOutEvent(table as any, cell);
72
+ };
73
+
74
+ p._bindCellHoverIn = (el: HTMLElement) => {
75
+ if (!(el as any)[HoverInEventSymbol]) {
76
+ el.addEventListener('mouseover', (el as any)[HoverInEventSymbol] = hoverMouseOverHandler);
77
+ }
78
+ };
79
+
80
+ p._unbindCellHoverIn = (el: HTMLElement) => {
81
+ if ((el as any)[HoverInEventSymbol]) {
82
+ el.removeEventListener('mouseover', (el as any)[HoverInEventSymbol]);
83
+ (el as any)[HoverInEventSymbol] = null;
84
+ }
85
+ };
86
+
87
+ p._bindCellHoverOut = (el: HTMLElement) => {
88
+ if (!(el as any)[HoverOutEventSymbol]) {
89
+ el.addEventListener('mouseout', (el as any)[HoverOutEventSymbol] = hoverMouseOutHandler);
90
+ }
91
+ };
92
+
93
+ p._unbindCellHoverOut = (el: HTMLElement) => {
94
+ if ((el as any)[HoverOutEventSymbol]) {
95
+ el.removeEventListener('mouseout', (el as any)[HoverOutEventSymbol]);
96
+ (el as any)[HoverOutEventSymbol] = null;
97
+ }
98
+ };
99
+ }
100
+
101
+ /**
102
+ * Handle horizontal scroll synchronization
103
+ */
104
+ export function onTableScrolledHorizontally(table: DGTableInternal): void {
105
+ const p = table._p;
106
+ p.header!.scrollLeft = p.table!.scrollLeft;
107
+ syncHorizontalStickies(table as any);
108
+ }
109
+
110
+ /**
111
+ * Bind event handlers to a header column element
112
+ */
113
+ export function bindHeaderColumnEvents(table: DGTableInternal, columnEl: HTMLElement): void {
114
+ const inner = columnEl.firstChild as HTMLElement;
115
+
116
+ columnEl.addEventListener('mousedown', (evt: MouseEvent) => resizeOnMouseDownColumnHeader(table as any, evt));
117
+ columnEl.addEventListener('mousemove', (evt: MouseEvent) => onMouseMoveColumnHeader(table as any, evt));
118
+ columnEl.addEventListener('mouseup', (evt: MouseEvent) => onMouseUpColumnHeader(table as any, evt));
119
+ columnEl.addEventListener('mouseleave', (evt: MouseEvent) => onMouseLeaveColumnHeader(table as any, evt));
120
+ columnEl.addEventListener('touchstart', (evt: TouchEvent) => onTouchStartColumnHeader(table as any, evt));
121
+ columnEl.addEventListener('dragstart', (evt: DragEvent) => onStartDragColumnHeader(table as any, evt));
122
+ columnEl.addEventListener('click', (evt: Event) => onSortOnColumnHeaderEvent(table as any, evt));
123
+ columnEl.addEventListener('contextmenu', (evt: Event) => evt.preventDefault());
124
+ inner.addEventListener('dragenter', (evt: DragEvent) => onDragEnterColumnHeader(table as any, evt));
125
+ inner.addEventListener('dragover', (evt: DragEvent) => onDragOverColumnHeader(table as any, evt));
126
+ inner.addEventListener('dragleave', (evt: DragEvent) => onDragLeaveColumnHeader(table as any, evt));
127
+ inner.addEventListener('drop', (evt: DragEvent) => onDropColumnHeader(table as any, evt));
128
+ }
129
+
130
+ /**
131
+ * Unbind cell events for a single row
132
+ */
133
+ export function unbindCellEventsForRow(table: DGTableInternal, rowToClean: HTMLElement): void {
134
+ const p = table._p;
135
+ for (let i = 0, cells = rowToClean.childNodes, cellCount = cells.length; i < cellCount; i++) {
136
+ p._unbindCellHoverIn(cells[i] as HTMLElement);
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Parse column width and determine width mode
142
+ */
143
+ export function parseColumnWidth(
144
+ width: number | string | null | undefined,
145
+ minWidth: number
146
+ ): { width: number; mode: ColumnWidthModeType } {
147
+ let widthSize = Math.max(0, parseFloat(width as string) || 0),
148
+ widthMode: ColumnWidthModeType = ColumnWidthMode.AUTO;
149
+
150
+ if (widthSize > 0) {
151
+ if (width === widthSize + '%') {
152
+ widthMode = ColumnWidthMode.RELATIVE;
153
+ widthSize /= 100;
154
+ } else if (widthSize > 0 && widthSize < 1) {
155
+ widthMode = ColumnWidthMode.RELATIVE;
156
+ } else {
157
+ if (widthSize < minWidth) {
158
+ widthSize = minWidth;
159
+ }
160
+ widthMode = ColumnWidthMode.ABSOLUTE;
161
+ }
162
+ }
163
+
164
+ return { width: widthSize, mode: widthMode };
165
+ }
166
+
167
+ /**
168
+ * Initialize a column from column options data
169
+ */
170
+ export function initColumnFromData(
171
+ options: DGTableInternalOptions,
172
+ columnData: ColumnOptions
173
+ ): InternalColumn {
174
+ let parsedWidth = parseColumnWidth(columnData.width, columnData.ignoreMin ? 0 : options.minColumnWidth);
175
+
176
+ let col: InternalColumn = {
177
+ name: columnData.name,
178
+ label: columnData.label === undefined ? columnData.name : columnData.label,
179
+ width: parsedWidth.width,
180
+ widthMode: parsedWidth.mode,
181
+ resizable: columnData.resizable === undefined ? true : columnData.resizable,
182
+ sortable: columnData.sortable === undefined ? true : columnData.sortable,
183
+ movable: columnData.movable === undefined ? true : columnData.movable,
184
+ visible: columnData.visible === undefined ? true : columnData.visible,
185
+ cellClasses: columnData.cellClasses === undefined ? options.cellClasses : columnData.cellClasses,
186
+ ignoreMin: columnData.ignoreMin === undefined ? false : !!columnData.ignoreMin,
187
+ sticky: columnData.sticky === undefined ? null : (columnData.sticky || null),
188
+ dataPath: [],
189
+ comparePath: [],
190
+ order: 0,
191
+ };
192
+
193
+ const rawDataPath = columnData.dataPath === undefined ? [col.name] : columnData.dataPath;
194
+ col.dataPath = typeof rawDataPath === 'string' ? rawDataPath.split('.') : rawDataPath;
195
+
196
+ const rawComparePath = columnData.comparePath === undefined ? col.dataPath : columnData.comparePath;
197
+ col.comparePath = typeof rawComparePath === 'string' ? rawComparePath.split('.') : rawComparePath;
198
+
199
+ return col;
200
+ }
201
+
202
+ /**
203
+ * Ensure at least one column is visible
204
+ */
205
+ export function ensureVisibleColumns(table: DGTableInternal): void {
206
+ const p = table._p;
207
+
208
+ if (p.visibleColumns.length === 0 && p.columns.length) {
209
+ p.columns[0].visible = true;
210
+ p.visibleColumns.push(p.columns[0]);
211
+ table.emit('showcolumn', p.columns[0].name);
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Refilter the rows using current filter
217
+ */
218
+ export function refilter(table: DGTableInternal): void {
219
+ const p = table._p;
220
+
221
+ if (p.filteredRows && p.filterArgs) {
222
+ let filterFunc = (table._o.filter || ByColumnFilter) as FilterFunction;
223
+ p.filteredRows = p.rows.filteredCollection(filterFunc, p.filterArgs);
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Get HTML content for a cell
229
+ */
230
+ export function getHtmlForCell(
231
+ options: DGTableInternalOptions,
232
+ rowData: RowData,
233
+ column: InternalColumn
234
+ ): string {
235
+ let dataPath = column.dataPath;
236
+ let colValue: unknown = rowData[dataPath[0]];
237
+ for (let dataPathIndex = 1; dataPathIndex < dataPath.length; dataPathIndex++) {
238
+ if (colValue == null) break;
239
+ colValue = colValue && (colValue as Record<string, unknown>)[dataPath[dataPathIndex]];
240
+ }
241
+
242
+ const formatter = options.cellFormatter;
243
+ let content;
244
+
245
+ if (formatter[IsSafeSymbol]) {
246
+ content = formatter(colValue, column.name, rowData);
247
+ } else {
248
+ try {
249
+ content = formatter(colValue, column.name, rowData);
250
+ } catch (err) {
251
+ content = '[ERROR]';
252
+ // eslint-disable-next-line no-console
253
+ console.error('Failed to generate content for cell ' + column.name, err);
254
+ }
255
+ }
256
+
257
+ if (content === undefined || content === null) {
258
+ content = '';
259
+ }
260
+
261
+ return content;
262
+ }
263
+
@@ -0,0 +1,156 @@
1
+ import type { WidthType } from './constants';
2
+ import type RowCollection from './row_collection';
3
+ import type ColumnCollection from './column_collection';
4
+ import type { Emitter } from 'mitt';
5
+ import {
6
+ CellFormatter,
7
+ CustomSortingProvider,
8
+ FilterFunction,
9
+ HeaderCellFormatter,
10
+ OnComparatorRequired,
11
+ } from "@/types";
12
+
13
+ // Symbols for internal use
14
+ export const IsSafeSymbol = Symbol('safe');
15
+ export const HoverInEventSymbol = Symbol('hover_in');
16
+ export const HoverOutEventSymbol = Symbol('hover_out');
17
+ export const RowClickEventSymbol = Symbol('row_click');
18
+ export const PreviewCellSymbol = Symbol('preview_cell');
19
+ export const OriginalCellSymbol = Symbol('cell');
20
+ export const RelatedTouchSymbol = Symbol('related_touch');
21
+ export const OriginalRowIndex = Symbol('original_row_index');
22
+
23
+ // External untyped modules - use any
24
+ type DomEventsSink = any;
25
+ type VirtualListHelper = any;
26
+
27
+ /**
28
+ * Internal column representation
29
+ */
30
+ export interface InternalColumn {
31
+ name: string;
32
+ label: string;
33
+ width: number;
34
+ widthMode: number; // ColumnWidthMode value (0, 1, or 2)
35
+ resizable: boolean;
36
+ sortable: boolean;
37
+ movable: boolean;
38
+ visible: boolean;
39
+ cellClasses: string;
40
+ ignoreMin: boolean;
41
+ sticky: 'start' | 'end' | null;
42
+ dataPath: string[];
43
+ comparePath: string[];
44
+ order: number;
45
+ actualWidth?: number;
46
+ actualWidthConsideringScrollbarWidth?: number | null;
47
+ arrowProposedWidth?: number;
48
+ element?: HTMLElement;
49
+ stickyPos?: { direction: string; offset: number };
50
+ _finalWidth?: number;
51
+ }
52
+
53
+ /**
54
+ * Internal options (normalized)
55
+ */
56
+ export interface DGTableInternalOptions {
57
+ virtualTable: boolean;
58
+ estimatedRowHeight?: number;
59
+ rowsBufferSize: number;
60
+ minColumnWidth: number;
61
+ resizeAreaWidth: number;
62
+ resizableColumns: boolean;
63
+ movableColumns: boolean;
64
+ sortableColumns: number;
65
+ adjustColumnWidthForSortArrow: boolean;
66
+ convertColumnWidthsToRelative: boolean;
67
+ autoFillTableWidth: boolean;
68
+ allowCancelSort: boolean;
69
+ cellClasses: string;
70
+ resizerClassName: string;
71
+ tableClassName: string;
72
+ allowCellPreview: boolean;
73
+ allowHeaderCellPreview: boolean;
74
+ cellPreviewClassName: string;
75
+ cellPreviewAutoBackground: boolean;
76
+ onComparatorRequired: OnComparatorRequired | null;
77
+ customSortingProvider: CustomSortingProvider | null;
78
+ width: WidthType;
79
+ relativeWidthGrowsToFillWidth: boolean;
80
+ relativeWidthShrinksToFillWidth: boolean;
81
+ cellFormatter: CellFormatter;
82
+ headerCellFormatter: HeaderCellFormatter;
83
+ filter: FilterFunction | null;
84
+ height?: number;
85
+ }
86
+
87
+ /**
88
+ * Internal sort column specification
89
+ */
90
+ export interface SortColumn {
91
+ column: string;
92
+ comparePath: string[];
93
+ descending: boolean;
94
+ }
95
+
96
+ /**
97
+ * Worker listener entry
98
+ */
99
+ export interface WorkerListener {
100
+ worker: Worker;
101
+ listener: (evt: MessageEvent) => void;
102
+ }
103
+
104
+ /**
105
+ * Internal private state
106
+ */
107
+ export interface DGTablePrivateState {
108
+ eventsSink: DomEventsSink;
109
+ mitt: Emitter<Record<string, unknown>>;
110
+ tableSkeletonNeedsRendering: boolean;
111
+ columns: ColumnCollection;
112
+ visibleColumns: InternalColumn[];
113
+ rows: RowCollection;
114
+ filteredRows: RowCollection | null;
115
+ filterArgs: unknown;
116
+ scrollbarWidth: number;
117
+ _lastVirtualScrollHeight: number;
118
+ lastDetectedWidth?: number;
119
+ virtualListHelper?: VirtualListHelper | null;
120
+ header?: HTMLElement;
121
+ headerRow?: HTMLElement;
122
+ table?: HTMLElement;
123
+ tbody?: HTMLElement;
124
+ resizer?: HTMLElement | null;
125
+ currentTouchId?: number | null;
126
+ transparentBgColor1?: string;
127
+ transparentBgColor2?: string;
128
+ cellPreviewCell?: HTMLElement | null;
129
+ abortCellPreview?: boolean;
130
+ dragId?: number;
131
+ stickiesLeft?: [HTMLElement, ...HTMLElement[]][];
132
+ stickiesRight?: [HTMLElement, ...HTMLElement[]][];
133
+ stickiesSetLeft?: Set<number>;
134
+ stickiesSetRight?: Set<number>;
135
+ lastStickyScrollLeft?: number;
136
+ isStickyColumns?: Map<number, 'left' | 'right'>;
137
+ virtualRowHeight?: number;
138
+ workerListeners?: WorkerListener[];
139
+ notifyRendererOfColumnsConfig?: () => void;
140
+ _deferredRender?: ReturnType<typeof setTimeout>;
141
+ _bindCellHoverIn: (el: HTMLElement) => void;
142
+ _unbindCellHoverIn: (el: HTMLElement) => void;
143
+ _bindCellHoverOut: (el: HTMLElement) => void;
144
+ _unbindCellHoverOut: (el: HTMLElement) => void;
145
+ }
146
+
147
+ /**
148
+ * DGTable interface for use by helper modules
149
+ */
150
+ export interface DGTableInterface {
151
+ el: HTMLElement;
152
+ _o: DGTableInternalOptions;
153
+ _p: DGTablePrivateState;
154
+ emit(event: string, data?: unknown): void;
155
+ tableWidthChanged(forceUpdate?: boolean, renderColumns?: boolean): void;
156
+ }