@gridkitjs/core 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1252 -22
- package/dist/index.js +2282 -704
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -63,13 +63,23 @@ function getColumnId(column) {
|
|
|
63
63
|
function resolveRowId(row, index, getRowId) {
|
|
64
64
|
return getRowId?.(row, index) ?? String(index);
|
|
65
65
|
}
|
|
66
|
+
function labelFromField(field) {
|
|
67
|
+
return field.split(".").join(" ");
|
|
68
|
+
}
|
|
66
69
|
function resolveColumnLabel(column) {
|
|
67
70
|
const { headerTemplate } = column;
|
|
68
71
|
if (headerTemplate === void 0) {
|
|
69
|
-
return column.
|
|
72
|
+
return column.header ?? labelFromField(column.field);
|
|
70
73
|
}
|
|
71
74
|
return typeof headerTemplate === "function" ? headerTemplate() : headerTemplate;
|
|
72
75
|
}
|
|
76
|
+
function resolveColumnHeaderText(column) {
|
|
77
|
+
if (column.header !== void 0) {
|
|
78
|
+
return column.header;
|
|
79
|
+
}
|
|
80
|
+
const label = resolveColumnLabel(column);
|
|
81
|
+
return typeof label === "string" ? label : labelFromField(column.field);
|
|
82
|
+
}
|
|
73
83
|
function buildKeyShortcuts(capabilities) {
|
|
74
84
|
return [
|
|
75
85
|
capabilities.reorderable ? "Control+ArrowLeft Control+ArrowRight" : "",
|
|
@@ -87,341 +97,675 @@ function accessDotted(obj, path) {
|
|
|
87
97
|
return path.split(".").reduce((value, key) => isNested(value) ? value[key] : void 0, obj);
|
|
88
98
|
}
|
|
89
99
|
|
|
90
|
-
// src/util/
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return {
|
|
94
|
-
rowIndex: Math.min(Math.max(focus.rowIndex, HEADER_ROW), rowCount - 1),
|
|
95
|
-
columnIndex: Math.min(
|
|
96
|
-
Math.max(focus.columnIndex, 0),
|
|
97
|
-
Math.max(columnCount - 1, 0)
|
|
98
|
-
)
|
|
99
|
-
};
|
|
100
|
+
// src/util/sorting.ts
|
|
101
|
+
function isEmpty(value) {
|
|
102
|
+
return value === null || value === void 0;
|
|
100
103
|
}
|
|
101
|
-
function
|
|
102
|
-
return
|
|
104
|
+
function toTime(value) {
|
|
105
|
+
return value instanceof Date ? value.getTime() : new Date(String(value)).getTime();
|
|
103
106
|
}
|
|
104
|
-
function
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const stepped = next + direction;
|
|
108
|
-
if (stepped < HEADER_ROW || stepped >= rowCount) {
|
|
109
|
-
return fallback;
|
|
110
|
-
}
|
|
111
|
-
next = stepped;
|
|
107
|
+
function compareValues(a, b, type) {
|
|
108
|
+
if (isEmpty(a)) {
|
|
109
|
+
return isEmpty(b) ? 0 : 1;
|
|
112
110
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
function nextFocusForKey(key, modifiers, focus, rowCount, columnCount, pageSize, isSkippableRow = noRowsSkippable) {
|
|
116
|
-
if (modifiers.altKey) {
|
|
117
|
-
return null;
|
|
111
|
+
if (isEmpty(b)) {
|
|
112
|
+
return -1;
|
|
118
113
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
case "
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
return
|
|
127
|
-
case "
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
-1,
|
|
132
|
-
rowCount,
|
|
133
|
-
isSkippableRow,
|
|
134
|
-
rowIndex
|
|
135
|
-
),
|
|
136
|
-
columnIndex
|
|
137
|
-
};
|
|
138
|
-
case "ArrowDown":
|
|
139
|
-
return {
|
|
140
|
-
rowIndex: skipSkippableRows(
|
|
141
|
-
rowIndex + 1,
|
|
142
|
-
1,
|
|
143
|
-
rowCount,
|
|
144
|
-
isSkippableRow,
|
|
145
|
-
rowIndex
|
|
146
|
-
),
|
|
147
|
-
columnIndex
|
|
148
|
-
};
|
|
149
|
-
// Ctrl takes Home and End to the grid's ends rather than the row's, which
|
|
150
|
-
// is the one place Ctrl is navigation rather than reorder.
|
|
151
|
-
case "Home":
|
|
152
|
-
return modifiers.ctrlKey ? { rowIndex: HEADER_ROW, columnIndex: 0 } : { rowIndex, columnIndex: 0 };
|
|
153
|
-
case "End":
|
|
154
|
-
return modifiers.ctrlKey ? {
|
|
155
|
-
rowIndex: skipSkippableRows(
|
|
156
|
-
rowCount - 1,
|
|
157
|
-
-1,
|
|
158
|
-
rowCount,
|
|
159
|
-
isSkippableRow,
|
|
160
|
-
rowIndex
|
|
161
|
-
),
|
|
162
|
-
columnIndex: columnCount - 1
|
|
163
|
-
} : { rowIndex, columnIndex: columnCount - 1 };
|
|
164
|
-
case "PageUp":
|
|
165
|
-
return {
|
|
166
|
-
rowIndex: skipSkippableRows(
|
|
167
|
-
rowIndex - pageSize,
|
|
168
|
-
-1,
|
|
169
|
-
rowCount,
|
|
170
|
-
isSkippableRow,
|
|
171
|
-
rowIndex
|
|
172
|
-
),
|
|
173
|
-
columnIndex
|
|
174
|
-
};
|
|
175
|
-
case "PageDown":
|
|
176
|
-
return {
|
|
177
|
-
rowIndex: skipSkippableRows(
|
|
178
|
-
rowIndex + pageSize,
|
|
179
|
-
1,
|
|
180
|
-
rowCount,
|
|
181
|
-
isSkippableRow,
|
|
182
|
-
rowIndex
|
|
183
|
-
),
|
|
184
|
-
columnIndex
|
|
185
|
-
};
|
|
114
|
+
switch (type) {
|
|
115
|
+
case "number":
|
|
116
|
+
case "decimal":
|
|
117
|
+
case "currency":
|
|
118
|
+
case "percent":
|
|
119
|
+
return Number(a) - Number(b);
|
|
120
|
+
case "boolean":
|
|
121
|
+
return Number(Boolean(a)) - Number(Boolean(b));
|
|
122
|
+
case "date":
|
|
123
|
+
case "dateTime":
|
|
124
|
+
case "time":
|
|
125
|
+
return toTime(a) - toTime(b);
|
|
186
126
|
default:
|
|
187
|
-
return
|
|
127
|
+
return String(a).localeCompare(String(b));
|
|
188
128
|
}
|
|
189
129
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
function applyColumnOrder(columns, order) {
|
|
193
|
-
if (order.length === 0) {
|
|
194
|
-
return columns;
|
|
195
|
-
}
|
|
196
|
-
const byId = new Map(columns.map((column) => [getColumnId(column), column]));
|
|
197
|
-
const listed = order.map((id) => byId.get(id)).filter((column) => column !== void 0);
|
|
198
|
-
const taken = new Set(listed.map((column) => getColumnId(column)));
|
|
199
|
-
return [
|
|
200
|
-
...listed,
|
|
201
|
-
...columns.filter((column) => !taken.has(getColumnId(column)))
|
|
202
|
-
];
|
|
130
|
+
function sortDirectionFor(sort, columnId) {
|
|
131
|
+
return sort.find((entry) => entry.columnId === columnId)?.direction ?? null;
|
|
203
132
|
}
|
|
204
|
-
function
|
|
205
|
-
|
|
206
|
-
|
|
133
|
+
function sortPriorityFor(sort, columnId) {
|
|
134
|
+
const index = sort.findIndex((entry) => entry.columnId === columnId);
|
|
135
|
+
return index === -1 ? null : index + 1;
|
|
136
|
+
}
|
|
137
|
+
function toggleColumnSort(sort, columnId, options) {
|
|
138
|
+
const index = sort.findIndex((entry) => entry.columnId === columnId);
|
|
139
|
+
const isSoleEntry = sort.length === 1 && index === 0;
|
|
140
|
+
if (!options.stack && !isSoleEntry) {
|
|
141
|
+
return [{ columnId, direction: "asc" }];
|
|
207
142
|
}
|
|
208
|
-
const
|
|
209
|
-
const
|
|
210
|
-
if (
|
|
211
|
-
return
|
|
143
|
+
const current = index === -1 ? void 0 : sort[index]?.direction;
|
|
144
|
+
const next = current === void 0 ? "asc" : current === "asc" ? "desc" : null;
|
|
145
|
+
if (next === null) {
|
|
146
|
+
return sort.filter((entry) => entry.columnId !== columnId);
|
|
212
147
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
return next.every((id, index) => id === orderedIds[index]) ? orderedIds : next;
|
|
216
|
-
}
|
|
217
|
-
function movesColumn(orderedIds, movedId, beforeId) {
|
|
218
|
-
return moveColumnBefore(orderedIds, movedId, beforeId) !== orderedIds;
|
|
219
|
-
}
|
|
220
|
-
function resolveDropBefore(orderedIds, targetId, side) {
|
|
221
|
-
if (side === "before") {
|
|
222
|
-
return targetId;
|
|
148
|
+
if (index === -1) {
|
|
149
|
+
return [...sort, { columnId, direction: next }];
|
|
223
150
|
}
|
|
224
|
-
|
|
225
|
-
|
|
151
|
+
return sort.map(
|
|
152
|
+
(entry, i) => i === index ? { columnId, direction: next } : entry
|
|
153
|
+
);
|
|
226
154
|
}
|
|
227
|
-
function
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
return void 0;
|
|
155
|
+
function sortRows(rows, sort, columns) {
|
|
156
|
+
if (sort.length === 0) {
|
|
157
|
+
return rows;
|
|
231
158
|
}
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
159
|
+
const byId = new Map(columns.map((entry) => [entry.id, entry.column]));
|
|
160
|
+
const active = sort.filter((entry) => byId.has(entry.columnId));
|
|
161
|
+
if (active.length === 0) {
|
|
162
|
+
return rows;
|
|
235
163
|
}
|
|
236
|
-
|
|
164
|
+
const sorted = [...rows].sort((a, b) => {
|
|
165
|
+
for (const { columnId, direction } of active) {
|
|
166
|
+
const column = byId.get(columnId);
|
|
167
|
+
if (column === void 0) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const left = accessDotted(a.row, column.field);
|
|
171
|
+
const right = accessDotted(b.row, column.field);
|
|
172
|
+
const leftEmpty = isEmpty(left);
|
|
173
|
+
const rightEmpty = isEmpty(right);
|
|
174
|
+
if (leftEmpty || rightEmpty) {
|
|
175
|
+
if (leftEmpty && rightEmpty) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
return leftEmpty ? 1 : -1;
|
|
179
|
+
}
|
|
180
|
+
const result = compareValues(left, right, column.type);
|
|
181
|
+
if (result !== 0) {
|
|
182
|
+
return direction === "asc" ? result : -result;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return 0;
|
|
186
|
+
});
|
|
187
|
+
return sorted.map(
|
|
188
|
+
(row, index) => row.rowIndex === index ? row : { ...row, rowIndex: index }
|
|
189
|
+
);
|
|
237
190
|
}
|
|
238
191
|
|
|
239
|
-
// src/util/
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
return a.length === b.length && a.every((id, index) => id === b[index]);
|
|
192
|
+
// src/util/grouping.ts
|
|
193
|
+
function groupRowId(path) {
|
|
194
|
+
return JSON.stringify(path);
|
|
243
195
|
}
|
|
244
|
-
function
|
|
245
|
-
if (
|
|
246
|
-
return
|
|
196
|
+
function bucketKey(value) {
|
|
197
|
+
if (value === null || value === void 0) {
|
|
198
|
+
return "\0empty";
|
|
247
199
|
}
|
|
248
|
-
if (
|
|
249
|
-
return
|
|
200
|
+
if (value instanceof Date) {
|
|
201
|
+
return `\0date:${String(value.getTime())}`;
|
|
250
202
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
203
|
+
switch (typeof value) {
|
|
204
|
+
case "string":
|
|
205
|
+
case "number":
|
|
206
|
+
case "boolean":
|
|
207
|
+
case "bigint":
|
|
208
|
+
case "symbol":
|
|
209
|
+
return `\0${typeof value}:${String(value)}`;
|
|
210
|
+
case "function":
|
|
211
|
+
return "\0function";
|
|
212
|
+
default:
|
|
213
|
+
return `\0object:${JSON.stringify(value)}`;
|
|
256
214
|
}
|
|
257
|
-
return selection.length === 1 && selection[0] === id ? selection : [id];
|
|
258
215
|
}
|
|
259
|
-
function
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
Math.max(anchor, focus) + 1
|
|
271
|
-
);
|
|
272
|
-
return sameSelection(selection, next) ? selection : next;
|
|
273
|
-
}
|
|
274
|
-
function selectAll(selection, orderedIds, mode) {
|
|
275
|
-
if (mode !== "multiple") {
|
|
276
|
-
return selection;
|
|
277
|
-
}
|
|
278
|
-
return sameSelection(selection, orderedIds) ? selection : orderedIds;
|
|
279
|
-
}
|
|
280
|
-
function clearSelection(selection) {
|
|
281
|
-
return selection.length === 0 ? selection : [];
|
|
282
|
-
}
|
|
283
|
-
function diffSelection(previous, next) {
|
|
284
|
-
if (previous === next) {
|
|
285
|
-
return NO_CHANGE;
|
|
216
|
+
function partitionByValue(rows, column, direction) {
|
|
217
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
218
|
+
for (const row of rows) {
|
|
219
|
+
const value = accessDotted(row.row, column.field);
|
|
220
|
+
const key = bucketKey(value);
|
|
221
|
+
const bucket = buckets.get(key);
|
|
222
|
+
if (bucket === void 0) {
|
|
223
|
+
buckets.set(key, { value, rows: [row] });
|
|
224
|
+
} else {
|
|
225
|
+
bucket.rows.push(row);
|
|
226
|
+
}
|
|
286
227
|
}
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
228
|
+
const groups = [...buckets.values()];
|
|
229
|
+
groups.sort((a, b) => {
|
|
230
|
+
const result = compareValues(a.value, b.value, column.type);
|
|
231
|
+
return direction === "asc" ? result : -result;
|
|
232
|
+
});
|
|
233
|
+
return groups;
|
|
293
234
|
}
|
|
294
|
-
function
|
|
295
|
-
|
|
296
|
-
|
|
235
|
+
function buildLevel(rows, levels, parentPath, expansion, byId, out) {
|
|
236
|
+
const level = levels[0];
|
|
237
|
+
if (level === void 0) {
|
|
238
|
+
out.push(...rows);
|
|
239
|
+
return;
|
|
297
240
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
return selection;
|
|
241
|
+
const column = byId.get(level.columnId);
|
|
242
|
+
if (column === void 0) {
|
|
243
|
+
out.push(...rows);
|
|
244
|
+
return;
|
|
303
245
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
246
|
+
const rest = levels.slice(1);
|
|
247
|
+
const groups = partitionByValue(rows, column, level.direction ?? "asc");
|
|
248
|
+
for (const group of groups) {
|
|
249
|
+
const path = [...parentPath, group.value];
|
|
250
|
+
const groupId = groupRowId(path);
|
|
251
|
+
const expanded = !expansion.includes(groupId);
|
|
252
|
+
const header = {
|
|
253
|
+
kind: "group",
|
|
254
|
+
groupId,
|
|
255
|
+
level: parentPath.length,
|
|
256
|
+
columnId: level.columnId,
|
|
257
|
+
value: group.value,
|
|
258
|
+
path,
|
|
259
|
+
expanded,
|
|
260
|
+
count: group.rows.length,
|
|
261
|
+
// Renumbered globally once `groupRows` has the whole flattened array —
|
|
262
|
+
// a header has no row of its own to carry a dataset position, so
|
|
263
|
+
// `datasetIndex` takes the same renumbered value `rowIndex` does.
|
|
264
|
+
rowIndex: -1,
|
|
265
|
+
datasetIndex: -1,
|
|
266
|
+
// Set by `withGroupAggregates`, downstream of grouping — empty here
|
|
267
|
+
// since `groupRows` itself never knows about `AggregateState`.
|
|
268
|
+
aggregates: /* @__PURE__ */ new Map()
|
|
269
|
+
};
|
|
270
|
+
out.push(header);
|
|
271
|
+
if (expanded) {
|
|
272
|
+
buildLevel(group.rows, rest, path, expansion, byId, out);
|
|
273
|
+
}
|
|
309
274
|
}
|
|
310
|
-
return isSameCell(selection, cell) ? null : cell;
|
|
311
275
|
}
|
|
312
|
-
function
|
|
313
|
-
if (
|
|
314
|
-
return
|
|
276
|
+
function groupRows(rows, groupBy, expansion, columns) {
|
|
277
|
+
if (groupBy.length === 0) {
|
|
278
|
+
return rows;
|
|
315
279
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
case "toggle":
|
|
321
|
-
return toggleSelection(selection, id, mode);
|
|
322
|
-
// A range with no anchor yet spans from the id to itself, which is the
|
|
323
|
-
// plain click a first Shift-click may as well be.
|
|
324
|
-
case "range":
|
|
325
|
-
return selectRange(selection, orderedIds, anchorId ?? id, id, mode);
|
|
326
|
-
default:
|
|
327
|
-
return selectOnly(selection, id, mode);
|
|
280
|
+
const byId = new Map(columns.map((entry) => [entry.id, entry.column]));
|
|
281
|
+
const active = groupBy.filter((entry) => byId.has(entry.columnId));
|
|
282
|
+
if (active.length === 0) {
|
|
283
|
+
return rows;
|
|
328
284
|
}
|
|
285
|
+
const out = [];
|
|
286
|
+
buildLevel(rows, active, [], expansion, byId, out);
|
|
287
|
+
return out.map((entry, index) => {
|
|
288
|
+
if ("kind" in entry) {
|
|
289
|
+
return entry.rowIndex === index && entry.datasetIndex === index ? entry : { ...entry, rowIndex: index, datasetIndex: index };
|
|
290
|
+
}
|
|
291
|
+
return entry.rowIndex === index ? entry : { ...entry, rowIndex: index };
|
|
292
|
+
});
|
|
329
293
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
var DEFAULT_COLUMN_SIZES = {
|
|
333
|
-
width: 150,
|
|
334
|
-
minWidth: 40,
|
|
335
|
-
maxWidth: Number.POSITIVE_INFINITY
|
|
336
|
-
};
|
|
337
|
-
var KEYBOARD_STEP = 10;
|
|
338
|
-
function withDefaults(defaults) {
|
|
339
|
-
return { ...DEFAULT_COLUMN_SIZES, ...defaults };
|
|
294
|
+
function toggleGroupExpansion(expansion, groupId) {
|
|
295
|
+
return expansion.includes(groupId) ? expansion.filter((id) => id !== groupId) : [...expansion, groupId];
|
|
340
296
|
}
|
|
341
|
-
function
|
|
342
|
-
|
|
343
|
-
return {
|
|
344
|
-
minWidth: column.minWidth ?? resolved.minWidth,
|
|
345
|
-
maxWidth: column.maxWidth ?? resolved.maxWidth
|
|
346
|
-
};
|
|
297
|
+
function expandAllGroups(expansion) {
|
|
298
|
+
return expansion.length === 0 ? expansion : [];
|
|
347
299
|
}
|
|
348
|
-
function
|
|
349
|
-
return
|
|
300
|
+
function collapseAllGroups(rows) {
|
|
301
|
+
return rows.filter(
|
|
302
|
+
(entry) => "kind" in entry && entry.kind === "group"
|
|
303
|
+
).map((entry) => entry.groupId);
|
|
350
304
|
}
|
|
351
|
-
function
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
reorderable: column.reorderable ?? options?.reorderable ?? false,
|
|
367
|
-
groupByDraggable: column.groupByDraggable ?? options?.groupByDraggable ?? false,
|
|
368
|
-
alignment: column.alignment ?? alignmentForType(column.type ?? "string")
|
|
369
|
-
};
|
|
370
|
-
});
|
|
305
|
+
function moveGroupByBefore(groupBy, columnId, beforeColumnId) {
|
|
306
|
+
if (columnId === beforeColumnId) {
|
|
307
|
+
return groupBy;
|
|
308
|
+
}
|
|
309
|
+
const without = groupBy.filter((entry) => entry.columnId !== columnId);
|
|
310
|
+
const moved = groupBy.find((entry) => entry.columnId === columnId) ?? {
|
|
311
|
+
columnId
|
|
312
|
+
};
|
|
313
|
+
const target = beforeColumnId === null ? without.length : without.findIndex((entry) => entry.columnId === beforeColumnId);
|
|
314
|
+
if (target === -1) {
|
|
315
|
+
return groupBy;
|
|
316
|
+
}
|
|
317
|
+
const next = [...without];
|
|
318
|
+
next.splice(target, 0, moved);
|
|
319
|
+
return next.length === groupBy.length && next.every((entry, index) => entry === groupBy[index]) ? groupBy : next;
|
|
371
320
|
}
|
|
372
|
-
function
|
|
373
|
-
return
|
|
321
|
+
function movesGroupBy(groupBy, columnId, beforeColumnId) {
|
|
322
|
+
return moveGroupByBefore(groupBy, columnId, beforeColumnId) !== groupBy;
|
|
374
323
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
324
|
+
|
|
325
|
+
// src/util/memoize.ts
|
|
326
|
+
function memoizeLast(compute) {
|
|
327
|
+
let last;
|
|
328
|
+
return (...args) => {
|
|
329
|
+
const previous = last;
|
|
330
|
+
if (previous !== void 0 && args.every((arg, index) => Object.is(arg, previous.args[index]))) {
|
|
331
|
+
return previous.result;
|
|
332
|
+
}
|
|
333
|
+
const result = compute(...args);
|
|
334
|
+
last = { args, result };
|
|
335
|
+
return result;
|
|
381
336
|
};
|
|
382
337
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
338
|
+
|
|
339
|
+
// src/util/ordering.ts
|
|
340
|
+
function applyColumnOrder(columns, order) {
|
|
341
|
+
if (order.length === 0) {
|
|
342
|
+
return columns;
|
|
343
|
+
}
|
|
344
|
+
const byId = new Map(columns.map((column) => [getColumnId(column), column]));
|
|
345
|
+
const listed = order.map((id) => byId.get(id)).filter((column) => column !== void 0);
|
|
346
|
+
const taken = new Set(listed.map((column) => getColumnId(column)));
|
|
347
|
+
return [
|
|
348
|
+
...listed,
|
|
349
|
+
...columns.filter((column) => !taken.has(getColumnId(column)))
|
|
350
|
+
];
|
|
388
351
|
}
|
|
389
|
-
function
|
|
390
|
-
return
|
|
352
|
+
function resolveDataColumns(columns, order) {
|
|
353
|
+
return applyColumnOrder(columns, order).map((column) => ({
|
|
354
|
+
id: getColumnId(column),
|
|
355
|
+
column
|
|
356
|
+
}));
|
|
391
357
|
}
|
|
392
|
-
function
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
}
|
|
401
|
-
const base = movable.reduce((total, item) => total + item.width, 0);
|
|
402
|
-
let clamped = false;
|
|
403
|
-
for (const item of movable) {
|
|
404
|
-
const share = base === 0 ? left / movable.length : left * item.width / base;
|
|
405
|
-
const next = item.width + (item.bound > item.width ? share : -share);
|
|
406
|
-
if (reachedBound(next, item)) {
|
|
407
|
-
item.width = item.bound;
|
|
408
|
-
clamped = true;
|
|
409
|
-
} else {
|
|
410
|
-
item.width = next;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
if (!clamped) {
|
|
414
|
-
break;
|
|
415
|
-
}
|
|
358
|
+
function moveColumnBefore(orderedIds, movedId, beforeId) {
|
|
359
|
+
if (movedId === beforeId || !orderedIds.includes(movedId)) {
|
|
360
|
+
return orderedIds;
|
|
361
|
+
}
|
|
362
|
+
const without = orderedIds.filter((id) => id !== movedId);
|
|
363
|
+
const target = beforeId === null ? without.length : without.indexOf(beforeId);
|
|
364
|
+
if (target === -1) {
|
|
365
|
+
return orderedIds;
|
|
416
366
|
}
|
|
367
|
+
const next = [...without];
|
|
368
|
+
next.splice(target, 0, movedId);
|
|
369
|
+
return next.every((id, index) => id === orderedIds[index]) ? orderedIds : next;
|
|
417
370
|
}
|
|
418
|
-
function
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
371
|
+
function movesColumn(orderedIds, movedId, beforeId) {
|
|
372
|
+
return moveColumnBefore(orderedIds, movedId, beforeId) !== orderedIds;
|
|
373
|
+
}
|
|
374
|
+
function resolveDropBefore(orderedIds, targetId, side) {
|
|
375
|
+
if (side === "before") {
|
|
376
|
+
return targetId;
|
|
423
377
|
}
|
|
424
|
-
const
|
|
378
|
+
const index = orderedIds.indexOf(targetId);
|
|
379
|
+
return index === -1 ? null : orderedIds[index + 1] ?? null;
|
|
380
|
+
}
|
|
381
|
+
function resolveKeyboardDropTarget(orderedIds, columnId, direction) {
|
|
382
|
+
const index = orderedIds.indexOf(columnId);
|
|
383
|
+
if (index === -1) {
|
|
384
|
+
return void 0;
|
|
385
|
+
}
|
|
386
|
+
const targetIndex = direction === -1 ? index - 1 : index + 2;
|
|
387
|
+
if (targetIndex < 0) {
|
|
388
|
+
return void 0;
|
|
389
|
+
}
|
|
390
|
+
return orderedIds[targetIndex] ?? null;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// src/util/paging.ts
|
|
394
|
+
function unitsOf(rows) {
|
|
395
|
+
const units = [];
|
|
396
|
+
let start = 0;
|
|
397
|
+
let openedByGroup = false;
|
|
398
|
+
for (let index = 0; index < rows.length; index++) {
|
|
399
|
+
const entry = rows[index];
|
|
400
|
+
if (entry === void 0) {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
const isTopLevelHeader = "kind" in entry && entry.kind === "group" && entry.level === 0;
|
|
404
|
+
const isBoundary = index !== start && (isTopLevelHeader || !openedByGroup);
|
|
405
|
+
if (isBoundary) {
|
|
406
|
+
units.push({ start, end: index });
|
|
407
|
+
start = index;
|
|
408
|
+
openedByGroup = isTopLevelHeader;
|
|
409
|
+
} else if (index === start) {
|
|
410
|
+
openedByGroup = isTopLevelHeader;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if (start < rows.length) {
|
|
414
|
+
units.push({ start, end: rows.length });
|
|
415
|
+
}
|
|
416
|
+
return units;
|
|
417
|
+
}
|
|
418
|
+
function paginateRows(rows, pagination) {
|
|
419
|
+
const pageSize = Math.max(1, pagination.pageSize);
|
|
420
|
+
const units = unitsOf(rows);
|
|
421
|
+
const pageCount = Math.ceil(units.length / pageSize);
|
|
422
|
+
if (pageCount === 0) {
|
|
423
|
+
return { rows: [], pageCount: 0, pageIndex: 0 };
|
|
424
|
+
}
|
|
425
|
+
const pageIndex = Math.min(Math.max(pagination.pageIndex, 0), pageCount - 1);
|
|
426
|
+
const firstUnit = units[pageIndex * pageSize];
|
|
427
|
+
const lastUnit = units[Math.min(pageIndex * pageSize + pageSize, units.length) - 1];
|
|
428
|
+
if (firstUnit === void 0 || lastUnit === void 0) {
|
|
429
|
+
return { rows: [], pageCount, pageIndex };
|
|
430
|
+
}
|
|
431
|
+
const page = rows.slice(firstUnit.start, lastUnit.end);
|
|
432
|
+
const renumbered = page.map(
|
|
433
|
+
(entry, index) => entry.rowIndex === index ? entry : { ...entry, rowIndex: index }
|
|
434
|
+
);
|
|
435
|
+
return { rows: renumbered, pageCount, pageIndex };
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// src/util/report.ts
|
|
439
|
+
function reportError(message) {
|
|
440
|
+
console.error(`GridKit: ${message}`);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// src/util/filterOperators.ts
|
|
444
|
+
var matchNothing = () => false;
|
|
445
|
+
function kindOf(type) {
|
|
446
|
+
switch (type) {
|
|
447
|
+
case "number":
|
|
448
|
+
case "decimal":
|
|
449
|
+
case "currency":
|
|
450
|
+
case "percent":
|
|
451
|
+
return "number";
|
|
452
|
+
case "boolean":
|
|
453
|
+
return "boolean";
|
|
454
|
+
case "date":
|
|
455
|
+
case "dateTime":
|
|
456
|
+
case "time":
|
|
457
|
+
return "date";
|
|
458
|
+
default:
|
|
459
|
+
return "text";
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function isDateType(type) {
|
|
463
|
+
return kindOf(type) === "date";
|
|
464
|
+
}
|
|
465
|
+
function isEmptyCell(value) {
|
|
466
|
+
return value === null || value === void 0 || value === "";
|
|
467
|
+
}
|
|
468
|
+
function toDate(value) {
|
|
469
|
+
const date = value instanceof Date ? value : typeof value === "string" ? new Date(value) : void 0;
|
|
470
|
+
return date === void 0 || Number.isNaN(date.getTime()) ? void 0 : date;
|
|
471
|
+
}
|
|
472
|
+
function comparable(value, kind) {
|
|
473
|
+
switch (kind) {
|
|
474
|
+
case "number":
|
|
475
|
+
return typeof value === "number" && !Number.isNaN(value) ? value : void 0;
|
|
476
|
+
case "boolean":
|
|
477
|
+
return typeof value === "boolean" ? value : void 0;
|
|
478
|
+
case "date":
|
|
479
|
+
return toDate(value);
|
|
480
|
+
case "text":
|
|
481
|
+
return String(value).toLowerCase();
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
function isOperandOfKind(operand, kind) {
|
|
485
|
+
if (kind !== "text") {
|
|
486
|
+
return comparable(operand, kind) !== void 0;
|
|
487
|
+
}
|
|
488
|
+
return typeof operand === "string" || typeof operand === "number" || typeof operand === "boolean";
|
|
489
|
+
}
|
|
490
|
+
function compileComparison(operand, type) {
|
|
491
|
+
const kind = kindOf(type);
|
|
492
|
+
if (!isOperandOfKind(operand, kind)) {
|
|
493
|
+
return void 0;
|
|
494
|
+
}
|
|
495
|
+
const target = comparable(operand, kind);
|
|
496
|
+
return (value) => {
|
|
497
|
+
if (isEmptyCell(value)) {
|
|
498
|
+
return void 0;
|
|
499
|
+
}
|
|
500
|
+
const cell = comparable(value, kind);
|
|
501
|
+
return cell === void 0 ? void 0 : compareValues(cell, target, type);
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
function isScalarList(operand) {
|
|
505
|
+
return Array.isArray(operand);
|
|
506
|
+
}
|
|
507
|
+
function compileOrdering(operator, operand, type) {
|
|
508
|
+
const compare = compileComparison(operand, type);
|
|
509
|
+
if (compare === void 0) {
|
|
510
|
+
return matchNothing;
|
|
511
|
+
}
|
|
512
|
+
const where = (holds) => (value) => {
|
|
513
|
+
const result = compare(value);
|
|
514
|
+
return result !== void 0 && holds(result);
|
|
515
|
+
};
|
|
516
|
+
switch (operator) {
|
|
517
|
+
case "eq":
|
|
518
|
+
return where((result) => result === 0);
|
|
519
|
+
case "ne": {
|
|
520
|
+
const equals = where((result) => result === 0);
|
|
521
|
+
return (value) => !equals(value);
|
|
522
|
+
}
|
|
523
|
+
case "gt":
|
|
524
|
+
return where((result) => result > 0);
|
|
525
|
+
case "gte":
|
|
526
|
+
return where((result) => result >= 0);
|
|
527
|
+
case "lt":
|
|
528
|
+
return where((result) => result < 0);
|
|
529
|
+
case "lte":
|
|
530
|
+
return where((result) => result <= 0);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
function compileBetween(operand, type) {
|
|
534
|
+
if (!isScalarList(operand) || operand.length !== 2) {
|
|
535
|
+
return matchNothing;
|
|
536
|
+
}
|
|
537
|
+
const [low, high] = operand;
|
|
538
|
+
const fromLow = compileComparison(low, type);
|
|
539
|
+
const fromHigh = compileComparison(high, type);
|
|
540
|
+
if (fromLow === void 0 || fromHigh === void 0) {
|
|
541
|
+
return matchNothing;
|
|
542
|
+
}
|
|
543
|
+
return (value) => {
|
|
544
|
+
const aboveLow = fromLow(value);
|
|
545
|
+
const belowHigh = fromHigh(value);
|
|
546
|
+
return aboveLow !== void 0 && belowHigh !== void 0 && aboveLow >= 0 && belowHigh <= 0;
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
function filterValueKey(value, type) {
|
|
550
|
+
return bucketKey(isDateType(type) ? toDate(value) ?? value : value);
|
|
551
|
+
}
|
|
552
|
+
function compileIn(operand, type) {
|
|
553
|
+
if (!isScalarList(operand)) {
|
|
554
|
+
return matchNothing;
|
|
555
|
+
}
|
|
556
|
+
const keys = new Set(
|
|
557
|
+
operand.filter((scalar) => !isEmptyCell(scalar)).map((scalar) => filterValueKey(scalar, type))
|
|
558
|
+
);
|
|
559
|
+
return (value) => !isEmptyCell(value) && keys.has(filterValueKey(value, type));
|
|
560
|
+
}
|
|
561
|
+
function compileText(operator, operand) {
|
|
562
|
+
if (!isOperandOfKind(operand, "text")) {
|
|
563
|
+
return matchNothing;
|
|
564
|
+
}
|
|
565
|
+
const text = String(operand).toLowerCase();
|
|
566
|
+
const read = (value) => String(value).toLowerCase();
|
|
567
|
+
switch (operator) {
|
|
568
|
+
case "contains":
|
|
569
|
+
return (value) => !isEmptyCell(value) && read(value).includes(text);
|
|
570
|
+
case "notContains":
|
|
571
|
+
return (value) => isEmptyCell(value) || !read(value).includes(text);
|
|
572
|
+
case "startsWith":
|
|
573
|
+
return (value) => !isEmptyCell(value) && read(value).startsWith(text);
|
|
574
|
+
case "endsWith":
|
|
575
|
+
return (value) => !isEmptyCell(value) && read(value).endsWith(text);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
function compileOperatorEntry(entry, type) {
|
|
579
|
+
const { operator, value } = entry;
|
|
580
|
+
switch (operator) {
|
|
581
|
+
case "isEmpty":
|
|
582
|
+
return isEmptyCell;
|
|
583
|
+
case "isNotEmpty":
|
|
584
|
+
return (cell) => !isEmptyCell(cell);
|
|
585
|
+
case "contains":
|
|
586
|
+
case "notContains":
|
|
587
|
+
case "startsWith":
|
|
588
|
+
case "endsWith":
|
|
589
|
+
return compileText(operator, value);
|
|
590
|
+
case "between":
|
|
591
|
+
return compileBetween(value, type);
|
|
592
|
+
case "in":
|
|
593
|
+
return compileIn(value, type);
|
|
594
|
+
case "eq":
|
|
595
|
+
case "ne":
|
|
596
|
+
case "gt":
|
|
597
|
+
case "gte":
|
|
598
|
+
case "lt":
|
|
599
|
+
case "lte":
|
|
600
|
+
return compileOrdering(operator, value, type);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/util/serialize.ts
|
|
605
|
+
function serializeScalar(scalar) {
|
|
606
|
+
return scalar instanceof Date ? scalar.toISOString() : scalar;
|
|
607
|
+
}
|
|
608
|
+
function serializeOperand(operand) {
|
|
609
|
+
return isScalarList(operand) ? operand.map(serializeScalar) : serializeScalar(operand);
|
|
610
|
+
}
|
|
611
|
+
function serializeEntry(entry) {
|
|
612
|
+
if ("combinator" in entry) {
|
|
613
|
+
const entries = serializeFilter(entry.entries);
|
|
614
|
+
return entries.length === 0 && entry.entries.length > 0 ? void 0 : { combinator: entry.combinator, entries };
|
|
615
|
+
}
|
|
616
|
+
if ("predicate" in entry) {
|
|
617
|
+
reportError(
|
|
618
|
+
entry.columnId === void 0 ? "a predicate filter entry across every column cannot be serialised, so it is left out of the saved state." : `a predicate filter entry on \`${entry.columnId}\` cannot be serialised, so it is left out of the saved state.`
|
|
619
|
+
);
|
|
620
|
+
return void 0;
|
|
621
|
+
}
|
|
622
|
+
if ("operator" in entry) {
|
|
623
|
+
const { value, ...rest } = entry;
|
|
624
|
+
return value === void 0 ? rest : { ...rest, value: serializeOperand(value) };
|
|
625
|
+
}
|
|
626
|
+
if ("value" in entry) {
|
|
627
|
+
const { value, ...rest } = entry;
|
|
628
|
+
return {
|
|
629
|
+
...rest,
|
|
630
|
+
value: value instanceof Date ? value.toISOString() : value
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
return entry;
|
|
634
|
+
}
|
|
635
|
+
function serializeFilter(filter) {
|
|
636
|
+
return filter.map((entry) => serializeEntry(entry)).filter((entry) => entry !== void 0);
|
|
637
|
+
}
|
|
638
|
+
function serializeGridState(state) {
|
|
639
|
+
return { ...state, filter: serializeFilter(state.filter) };
|
|
640
|
+
}
|
|
641
|
+
function reviveScalar(scalar, type) {
|
|
642
|
+
return isDateType(type) && typeof scalar === "string" ? toDate(scalar) ?? scalar : scalar;
|
|
643
|
+
}
|
|
644
|
+
function reviveOperand(operand, type) {
|
|
645
|
+
return isScalarList(operand) ? operand.map((scalar) => reviveScalar(scalar, type)) : reviveScalar(operand, type);
|
|
646
|
+
}
|
|
647
|
+
function reviveEntry(entry, typeOf) {
|
|
648
|
+
if ("combinator" in entry) {
|
|
649
|
+
return {
|
|
650
|
+
combinator: entry.combinator,
|
|
651
|
+
entries: reviveEntries(entry.entries, typeOf)
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
if ("operator" in entry) {
|
|
655
|
+
const { value, ...rest } = entry;
|
|
656
|
+
return value === void 0 ? rest : { ...rest, value: reviveOperand(value, typeOf(entry.columnId)) };
|
|
657
|
+
}
|
|
658
|
+
if ("value" in entry) {
|
|
659
|
+
const { value, ...rest } = entry;
|
|
660
|
+
return {
|
|
661
|
+
...rest,
|
|
662
|
+
value: typeof value === "string" ? new Date(value) : value
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
return entry;
|
|
666
|
+
}
|
|
667
|
+
function reviveEntries(filter, typeOf) {
|
|
668
|
+
return filter.map((entry) => reviveEntry(entry, typeOf));
|
|
669
|
+
}
|
|
670
|
+
function reviveFilter(filter, columns) {
|
|
671
|
+
const types = new Map(columns.map((entry) => [entry.id, entry.column.type]));
|
|
672
|
+
return reviveEntries(filter, (columnId) => types.get(columnId));
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// src/util/sizing.ts
|
|
676
|
+
var DEFAULT_COLUMN_SIZES = {
|
|
677
|
+
width: 150,
|
|
678
|
+
minWidth: 40,
|
|
679
|
+
maxWidth: Number.POSITIVE_INFINITY
|
|
680
|
+
};
|
|
681
|
+
var KEYBOARD_STEP = 10;
|
|
682
|
+
function withDefaults(defaults) {
|
|
683
|
+
return { ...DEFAULT_COLUMN_SIZES, ...defaults };
|
|
684
|
+
}
|
|
685
|
+
function resolveColumnConstraints(column, defaults) {
|
|
686
|
+
const resolved = withDefaults(defaults);
|
|
687
|
+
return {
|
|
688
|
+
minWidth: column.minWidth ?? resolved.minWidth,
|
|
689
|
+
maxWidth: column.maxWidth ?? resolved.maxWidth
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
function clampColumnWidth(width, constraints) {
|
|
693
|
+
return Math.min(Math.max(width, constraints.minWidth), constraints.maxWidth);
|
|
694
|
+
}
|
|
695
|
+
function resolveColumnWidths(columns, sizing, options) {
|
|
696
|
+
const resolved = withDefaults(options?.sizes);
|
|
697
|
+
return columns.map((column) => {
|
|
698
|
+
const id = getColumnId(column);
|
|
699
|
+
const stored = sizing[id];
|
|
700
|
+
return {
|
|
701
|
+
column,
|
|
702
|
+
id,
|
|
703
|
+
sized: stored !== void 0,
|
|
704
|
+
width: clampColumnWidth(
|
|
705
|
+
stored ?? column.width ?? resolved.width,
|
|
706
|
+
resolveColumnConstraints(column, resolved)
|
|
707
|
+
),
|
|
708
|
+
label: resolveColumnLabel(column),
|
|
709
|
+
resizable: column.resizable ?? options?.resizable ?? false,
|
|
710
|
+
reorderable: column.reorderable ?? options?.reorderable ?? false,
|
|
711
|
+
groupByDraggable: column.groupByDraggable ?? options?.groupByDraggable ?? false,
|
|
712
|
+
alignment: column.alignment ?? alignmentForType(column.type ?? "string")
|
|
713
|
+
};
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
function totalColumnWidth(resolved) {
|
|
717
|
+
return resolved.reduce((total, entry) => total + entry.width, 0);
|
|
718
|
+
}
|
|
719
|
+
function beginColumnResize(column, startWidth, startPosition, defaults) {
|
|
720
|
+
return {
|
|
721
|
+
columnId: getColumnId(column),
|
|
722
|
+
startWidth,
|
|
723
|
+
startPosition,
|
|
724
|
+
constraints: resolveColumnConstraints(column, defaults)
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
function applyColumnResize(session, position) {
|
|
728
|
+
return clampColumnWidth(
|
|
729
|
+
session.startWidth + (position - session.startPosition),
|
|
730
|
+
session.constraints
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
function reachedBound(width, item) {
|
|
734
|
+
return item.bound > item.width ? width >= item.bound : width <= item.bound;
|
|
735
|
+
}
|
|
736
|
+
function redistribute(entries, remaining) {
|
|
737
|
+
for (; ; ) {
|
|
738
|
+
const movable = entries.filter(
|
|
739
|
+
(item) => item.adjustable && !reachedBound(item.width, item)
|
|
740
|
+
);
|
|
741
|
+
const left = remaining(entries.reduce((t, i) => t + i.width, 0));
|
|
742
|
+
if (left <= 0 || movable.length === 0) {
|
|
743
|
+
break;
|
|
744
|
+
}
|
|
745
|
+
const base = movable.reduce((total, item) => total + item.width, 0);
|
|
746
|
+
let clamped = false;
|
|
747
|
+
for (const item of movable) {
|
|
748
|
+
const share = base === 0 ? left / movable.length : left * item.width / base;
|
|
749
|
+
const next = item.width + (item.bound > item.width ? share : -share);
|
|
750
|
+
if (reachedBound(next, item)) {
|
|
751
|
+
item.width = item.bound;
|
|
752
|
+
clamped = true;
|
|
753
|
+
} else {
|
|
754
|
+
item.width = next;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
if (!clamped) {
|
|
758
|
+
break;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
function fitColumnsToWidth(resolved, availableWidth, defaults) {
|
|
763
|
+
const target = Math.floor(availableWidth);
|
|
764
|
+
const total = totalColumnWidth(resolved);
|
|
765
|
+
if (resolved.length === 0 || total === target) {
|
|
766
|
+
return resolved;
|
|
767
|
+
}
|
|
768
|
+
const growing = total < target;
|
|
425
769
|
const entries = resolved.map((entry) => {
|
|
426
770
|
const constraints = resolveColumnConstraints(entry.column, defaults);
|
|
427
771
|
return {
|
|
@@ -468,96 +812,180 @@ function revertColumnSize(current, base, columnId) {
|
|
|
468
812
|
return next;
|
|
469
813
|
}
|
|
470
814
|
|
|
471
|
-
// src/util/
|
|
472
|
-
function
|
|
815
|
+
// src/util/aggregation.ts
|
|
816
|
+
function isEmpty2(value) {
|
|
473
817
|
return value === null || value === void 0;
|
|
474
818
|
}
|
|
475
|
-
function
|
|
476
|
-
return
|
|
819
|
+
function toNumber(value) {
|
|
820
|
+
return Number(value);
|
|
477
821
|
}
|
|
478
|
-
function
|
|
479
|
-
if (
|
|
480
|
-
return
|
|
822
|
+
function distinctKey(value) {
|
|
823
|
+
if (isEmpty2(value)) {
|
|
824
|
+
return "\0empty";
|
|
481
825
|
}
|
|
482
|
-
if (
|
|
483
|
-
return
|
|
826
|
+
if (value instanceof Date) {
|
|
827
|
+
return `\0date:${String(value.getTime())}`;
|
|
484
828
|
}
|
|
485
|
-
switch (
|
|
829
|
+
switch (typeof value) {
|
|
830
|
+
case "string":
|
|
486
831
|
case "number":
|
|
487
|
-
case "decimal":
|
|
488
|
-
case "currency":
|
|
489
|
-
case "percent":
|
|
490
|
-
return Number(a) - Number(b);
|
|
491
832
|
case "boolean":
|
|
492
|
-
|
|
493
|
-
case "
|
|
494
|
-
|
|
495
|
-
case "
|
|
496
|
-
return
|
|
833
|
+
case "bigint":
|
|
834
|
+
case "symbol":
|
|
835
|
+
return `\0${typeof value}:${String(value)}`;
|
|
836
|
+
case "function":
|
|
837
|
+
return "\0function";
|
|
497
838
|
default:
|
|
498
|
-
return
|
|
839
|
+
return `\0object:${JSON.stringify(value)}`;
|
|
499
840
|
}
|
|
500
841
|
}
|
|
501
|
-
function
|
|
502
|
-
|
|
842
|
+
function reduceBuiltIn(rows, fn, column) {
|
|
843
|
+
if (fn === "count") {
|
|
844
|
+
return rows.length;
|
|
845
|
+
}
|
|
846
|
+
const field = column?.column.field;
|
|
847
|
+
const values = field === void 0 ? [] : rows.map((row) => accessDotted(row, field));
|
|
848
|
+
switch (fn) {
|
|
849
|
+
case "sum": {
|
|
850
|
+
let total = 0;
|
|
851
|
+
for (const value of values) {
|
|
852
|
+
if (isEmpty2(value)) continue;
|
|
853
|
+
total += toNumber(value);
|
|
854
|
+
}
|
|
855
|
+
return total;
|
|
856
|
+
}
|
|
857
|
+
case "avg": {
|
|
858
|
+
const present = values.filter((value) => !isEmpty2(value));
|
|
859
|
+
if (present.length === 0) return void 0;
|
|
860
|
+
const total = present.reduce(
|
|
861
|
+
(acc, value) => acc + toNumber(value),
|
|
862
|
+
0
|
|
863
|
+
);
|
|
864
|
+
return total / present.length;
|
|
865
|
+
}
|
|
866
|
+
case "min":
|
|
867
|
+
case "max": {
|
|
868
|
+
const type = column?.column.type;
|
|
869
|
+
let result;
|
|
870
|
+
for (const value of values) {
|
|
871
|
+
if (isEmpty2(value)) continue;
|
|
872
|
+
if (result === void 0) {
|
|
873
|
+
result = value;
|
|
874
|
+
continue;
|
|
875
|
+
}
|
|
876
|
+
const comparison = compareValues(value, result, type);
|
|
877
|
+
if (fn === "min" ? comparison < 0 : comparison > 0) {
|
|
878
|
+
result = value;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
return result;
|
|
882
|
+
}
|
|
883
|
+
case "countDistinct": {
|
|
884
|
+
const seen = /* @__PURE__ */ new Set();
|
|
885
|
+
for (const value of values) {
|
|
886
|
+
if (isEmpty2(value)) continue;
|
|
887
|
+
seen.add(distinctKey(value));
|
|
888
|
+
}
|
|
889
|
+
return seen.size;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
503
892
|
}
|
|
504
|
-
function
|
|
505
|
-
|
|
506
|
-
return index === -1 ? null : index + 1;
|
|
893
|
+
function keyOf(spec) {
|
|
894
|
+
return spec.id ?? spec.columnId;
|
|
507
895
|
}
|
|
508
|
-
function
|
|
509
|
-
const
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
return [{ columnId, direction: "asc" }];
|
|
896
|
+
function computeAggregates(rows, specs, columns) {
|
|
897
|
+
const results = /* @__PURE__ */ new Map();
|
|
898
|
+
if (specs.length === 0) {
|
|
899
|
+
return results;
|
|
513
900
|
}
|
|
514
|
-
const
|
|
515
|
-
const
|
|
516
|
-
|
|
517
|
-
|
|
901
|
+
const byId = new Map(columns.map((entry) => [entry.id, entry]));
|
|
902
|
+
for (const spec of specs) {
|
|
903
|
+
const value = typeof spec.fn === "function" ? spec.fn(rows) : reduceBuiltIn(rows, spec.fn, byId.get(spec.columnId));
|
|
904
|
+
results.set(keyOf(spec), value);
|
|
518
905
|
}
|
|
519
|
-
|
|
520
|
-
|
|
906
|
+
return results;
|
|
907
|
+
}
|
|
908
|
+
function leafDescendantsOf(flatRows, path, groupBy, byId) {
|
|
909
|
+
const keys = path.map((value) => bucketKey(value));
|
|
910
|
+
return flatRows.filter(
|
|
911
|
+
(row) => keys.every((key, level) => {
|
|
912
|
+
const columnId = groupBy[level]?.columnId;
|
|
913
|
+
const column = columnId === void 0 ? void 0 : byId.get(columnId);
|
|
914
|
+
if (column === void 0) return false;
|
|
915
|
+
return bucketKey(accessDotted(row.row, column.field)) === key;
|
|
916
|
+
})
|
|
917
|
+
).map((row) => row.row);
|
|
918
|
+
}
|
|
919
|
+
function appendAggregatedSpan(displayRows, start, levelFloor, flatRows, groupBy, byId, specs, columns, display, out) {
|
|
920
|
+
let index = start;
|
|
921
|
+
while (index < displayRows.length) {
|
|
922
|
+
const entry = displayRows[index];
|
|
923
|
+
if (entry === void 0) {
|
|
924
|
+
index++;
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
927
|
+
if (levelFloor !== null && "kind" in entry && entry.kind === "group" && entry.level <= levelFloor) {
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
930
|
+
index++;
|
|
931
|
+
if (!("kind" in entry) || entry.kind !== "group") {
|
|
932
|
+
out.push(entry);
|
|
933
|
+
continue;
|
|
934
|
+
}
|
|
935
|
+
const leaves = leafDescendantsOf(flatRows, entry.path, groupBy, byId);
|
|
936
|
+
const aggregates = computeAggregates(leaves, specs, columns);
|
|
937
|
+
const withAggregates = { ...entry, aggregates };
|
|
938
|
+
out.push(withAggregates);
|
|
939
|
+
index = appendAggregatedSpan(
|
|
940
|
+
displayRows,
|
|
941
|
+
index,
|
|
942
|
+
entry.level,
|
|
943
|
+
flatRows,
|
|
944
|
+
groupBy,
|
|
945
|
+
byId,
|
|
946
|
+
specs,
|
|
947
|
+
columns,
|
|
948
|
+
display,
|
|
949
|
+
out
|
|
950
|
+
);
|
|
951
|
+
if (display === "row") {
|
|
952
|
+
const summary = {
|
|
953
|
+
kind: "group-summary",
|
|
954
|
+
groupId: entry.groupId,
|
|
955
|
+
level: entry.level,
|
|
956
|
+
rowIndex: -1,
|
|
957
|
+
datasetIndex: -1,
|
|
958
|
+
aggregates
|
|
959
|
+
};
|
|
960
|
+
out.push(summary);
|
|
961
|
+
}
|
|
521
962
|
}
|
|
522
|
-
return
|
|
523
|
-
(entry, i) => i === index ? { columnId, direction: next } : entry
|
|
524
|
-
);
|
|
963
|
+
return index;
|
|
525
964
|
}
|
|
526
|
-
function
|
|
527
|
-
if (
|
|
528
|
-
return
|
|
965
|
+
function withGroupAggregates(displayRows, flatRows, groupBy, specs, columns, display = "inline") {
|
|
966
|
+
if (specs.length === 0) {
|
|
967
|
+
return displayRows;
|
|
529
968
|
}
|
|
530
969
|
const byId = new Map(columns.map((entry) => [entry.id, entry.column]));
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
continue;
|
|
548
|
-
}
|
|
549
|
-
return leftEmpty ? 1 : -1;
|
|
550
|
-
}
|
|
551
|
-
const result = compareValues(left, right, column.type);
|
|
552
|
-
if (result !== 0) {
|
|
553
|
-
return direction === "asc" ? result : -result;
|
|
554
|
-
}
|
|
970
|
+
const out = [];
|
|
971
|
+
appendAggregatedSpan(
|
|
972
|
+
displayRows,
|
|
973
|
+
0,
|
|
974
|
+
null,
|
|
975
|
+
flatRows,
|
|
976
|
+
groupBy,
|
|
977
|
+
byId,
|
|
978
|
+
specs,
|
|
979
|
+
columns,
|
|
980
|
+
display,
|
|
981
|
+
out
|
|
982
|
+
);
|
|
983
|
+
return out.map((entry, position) => {
|
|
984
|
+
if ("kind" in entry) {
|
|
985
|
+
return entry.rowIndex === position && entry.datasetIndex === position ? entry : { ...entry, rowIndex: position, datasetIndex: position };
|
|
555
986
|
}
|
|
556
|
-
return
|
|
987
|
+
return entry.rowIndex === position ? entry : { ...entry, rowIndex: position };
|
|
557
988
|
});
|
|
558
|
-
return sorted.map(
|
|
559
|
-
(row, index) => row.rowIndex === index ? row : { ...row, rowIndex: index }
|
|
560
|
-
);
|
|
561
989
|
}
|
|
562
990
|
|
|
563
991
|
// src/util/filtering.ts
|
|
@@ -635,10 +1063,18 @@ function compileFilterEntry(entry, byId, columns) {
|
|
|
635
1063
|
const { columnId: columnId2, predicate } = entry;
|
|
636
1064
|
const column = columnId2 === void 0 ? void 0 : byId.get(columnId2);
|
|
637
1065
|
return (row) => predicate(
|
|
638
|
-
column === void 0 ? void 0 : accessDotted(row
|
|
639
|
-
row
|
|
1066
|
+
column === void 0 ? void 0 : accessDotted(row, column.field),
|
|
1067
|
+
row
|
|
640
1068
|
);
|
|
641
1069
|
}
|
|
1070
|
+
if ("operator" in entry) {
|
|
1071
|
+
const column = byId.get(entry.columnId);
|
|
1072
|
+
if (column === void 0) {
|
|
1073
|
+
return () => false;
|
|
1074
|
+
}
|
|
1075
|
+
const test2 = compileOperatorEntry(entry, column.type);
|
|
1076
|
+
return (row) => test2(accessDotted(row, column.field));
|
|
1077
|
+
}
|
|
642
1078
|
if ("value" in entry) {
|
|
643
1079
|
const { columnId: columnId2, value } = entry;
|
|
644
1080
|
if (columnId2 !== void 0) {
|
|
@@ -646,15 +1082,11 @@ function compileFilterEntry(entry, byId, columns) {
|
|
|
646
1082
|
if (column === void 0) {
|
|
647
1083
|
return () => false;
|
|
648
1084
|
}
|
|
649
|
-
return (row) => matchesTypedValue(
|
|
650
|
-
accessDotted(row.row, column.field),
|
|
651
|
-
value,
|
|
652
|
-
column.type
|
|
653
|
-
);
|
|
1085
|
+
return (row) => matchesTypedValue(accessDotted(row, column.field), value, column.type);
|
|
654
1086
|
}
|
|
655
1087
|
return (row) => columns.some(
|
|
656
1088
|
(entry2) => matchesTypedValue(
|
|
657
|
-
accessDotted(row
|
|
1089
|
+
accessDotted(row, entry2.column.field),
|
|
658
1090
|
value,
|
|
659
1091
|
entry2.column.type
|
|
660
1092
|
)
|
|
@@ -667,9 +1099,14 @@ function compileFilterEntry(entry, byId, columns) {
|
|
|
667
1099
|
if (column === void 0) {
|
|
668
1100
|
return () => false;
|
|
669
1101
|
}
|
|
670
|
-
return (row) => test(accessDotted(row
|
|
1102
|
+
return (row) => test(accessDotted(row, column.field));
|
|
671
1103
|
}
|
|
672
|
-
return (row) => columns.some((entry2) => test(accessDotted(row
|
|
1104
|
+
return (row) => columns.some((entry2) => test(accessDotted(row, entry2.column.field)));
|
|
1105
|
+
}
|
|
1106
|
+
function compileFilter(filter, columns) {
|
|
1107
|
+
const byId = new Map(columns.map((entry) => [entry.id, entry.column]));
|
|
1108
|
+
const compiled = filter.filter((entry) => isEntryUsable(entry, byId)).map((entry) => compileFilterEntry(entry, byId, columns));
|
|
1109
|
+
return compiled.length === 0 ? void 0 : (row) => compiled.every((test) => test(row));
|
|
673
1110
|
}
|
|
674
1111
|
function matchesQuery(value, query) {
|
|
675
1112
|
return compileFilterQuery(query)(value);
|
|
@@ -704,231 +1141,1106 @@ function filterRows(rows, filter, columns) {
|
|
|
704
1141
|
if (filter.length === 0) {
|
|
705
1142
|
return rows;
|
|
706
1143
|
}
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
if (active.length === 0) {
|
|
1144
|
+
const test = compileFilter(filter, columns);
|
|
1145
|
+
if (test === void 0) {
|
|
710
1146
|
return rows;
|
|
711
1147
|
}
|
|
712
|
-
const
|
|
713
|
-
(entry) => compileFilterEntry(entry, byId, columns)
|
|
714
|
-
);
|
|
715
|
-
const filtered = rows.filter((row) => compiled.every((test) => test(row)));
|
|
1148
|
+
const filtered = rows.filter((row) => test(row.row));
|
|
716
1149
|
return filtered.map(
|
|
717
1150
|
(row, index) => row.rowIndex === index ? row : { ...row, rowIndex: index }
|
|
718
1151
|
);
|
|
719
1152
|
}
|
|
720
1153
|
|
|
721
|
-
// src/util/
|
|
722
|
-
function
|
|
723
|
-
return
|
|
1154
|
+
// src/util/rows.ts
|
|
1155
|
+
function resolveShownRows(rows, filter, sort, columns) {
|
|
1156
|
+
return sortRows(filterRows(rows, filter, columns), sort, columns);
|
|
724
1157
|
}
|
|
725
|
-
function
|
|
726
|
-
|
|
727
|
-
return "\0empty";
|
|
728
|
-
}
|
|
729
|
-
if (value instanceof Date) {
|
|
730
|
-
return `\0date:${String(value.getTime())}`;
|
|
731
|
-
}
|
|
732
|
-
switch (typeof value) {
|
|
733
|
-
case "string":
|
|
734
|
-
case "number":
|
|
735
|
-
case "boolean":
|
|
736
|
-
case "bigint":
|
|
737
|
-
case "symbol":
|
|
738
|
-
return `\0${typeof value}:${String(value)}`;
|
|
739
|
-
case "function":
|
|
740
|
-
return "\0function";
|
|
741
|
-
default:
|
|
742
|
-
return `\0object:${JSON.stringify(value)}`;
|
|
743
|
-
}
|
|
1158
|
+
function resolveRows(rowsById, ids) {
|
|
1159
|
+
return ids.map((id) => rowsById.get(id)).filter((row) => row !== void 0);
|
|
744
1160
|
}
|
|
745
|
-
function
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
const
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
}
|
|
1161
|
+
function resolveColumns(columns, ids) {
|
|
1162
|
+
return ids.map((id) => {
|
|
1163
|
+
const columnIndex = columns.findIndex((entry) => entry.id === id);
|
|
1164
|
+
const column = columns[columnIndex];
|
|
1165
|
+
return column === void 0 ? void 0 : { columnId: id, column, columnIndex };
|
|
1166
|
+
}).filter((column) => column !== void 0);
|
|
1167
|
+
}
|
|
1168
|
+
function resolveCell(rowsById, columns, cell) {
|
|
1169
|
+
if (cell === null) {
|
|
1170
|
+
return null;
|
|
756
1171
|
}
|
|
757
|
-
const
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
1172
|
+
const entry = rowsById.get(cell.rowId);
|
|
1173
|
+
const columnIndex = columns.findIndex(
|
|
1174
|
+
(candidate) => candidate.id === cell.columnId
|
|
1175
|
+
);
|
|
1176
|
+
const column = columns[columnIndex];
|
|
1177
|
+
if (entry === void 0 || column === void 0) {
|
|
1178
|
+
return null;
|
|
1179
|
+
}
|
|
1180
|
+
return {
|
|
1181
|
+
rowId: cell.rowId,
|
|
1182
|
+
columnId: cell.columnId,
|
|
1183
|
+
row: entry.row,
|
|
1184
|
+
column,
|
|
1185
|
+
rowIndex: entry.rowIndex,
|
|
1186
|
+
columnIndex,
|
|
1187
|
+
value: accessDotted(entry.row, column.column.field)
|
|
1188
|
+
};
|
|
763
1189
|
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
1190
|
+
|
|
1191
|
+
// src/util/visibility.ts
|
|
1192
|
+
function isColumnVisible(column, visibility) {
|
|
1193
|
+
return visibility[getColumnId(column)] ?? column.hidden !== true;
|
|
1194
|
+
}
|
|
1195
|
+
function applyColumnVisibility(columns, visibility) {
|
|
1196
|
+
const visible = columns.filter(
|
|
1197
|
+
(entry) => isColumnVisible(entry.column, visibility)
|
|
1198
|
+
);
|
|
1199
|
+
return visible.length === columns.length ? columns : visible;
|
|
1200
|
+
}
|
|
1201
|
+
function setColumnVisibility(columns, visibility, columnIds, visible) {
|
|
1202
|
+
const requested = new Set(columnIds);
|
|
1203
|
+
const changed = columns.filter(
|
|
1204
|
+
(entry) => requested.has(entry.id) && isColumnVisible(entry.column, visibility) !== visible
|
|
1205
|
+
);
|
|
1206
|
+
if (changed.length === 0) {
|
|
1207
|
+
return visibility;
|
|
769
1208
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
1209
|
+
return {
|
|
1210
|
+
...visibility,
|
|
1211
|
+
...Object.fromEntries(changed.map((entry) => [entry.id, visible]))
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
// src/util/view.ts
|
|
1216
|
+
var NO_AGGREGATES = [];
|
|
1217
|
+
function identifyRows(rows, getRowId) {
|
|
1218
|
+
return rows.map((row, rowIndex) => ({
|
|
1219
|
+
rowId: resolveRowId(row, rowIndex, getRowId),
|
|
1220
|
+
row,
|
|
1221
|
+
rowIndex,
|
|
1222
|
+
datasetIndex: rowIndex
|
|
1223
|
+
}));
|
|
1224
|
+
}
|
|
1225
|
+
function sizeColumns(visibleColumns, sizing, sizes, resizable, reorderable, groupByDraggable, resizeMode, viewportWidth) {
|
|
1226
|
+
const widths = resolveColumnWidths(
|
|
1227
|
+
visibleColumns.map((entry) => entry.column),
|
|
1228
|
+
sizing,
|
|
1229
|
+
{ sizes, resizable, reorderable, groupByDraggable }
|
|
1230
|
+
);
|
|
1231
|
+
return resizeMode === "fit" && viewportWidth !== null ? fitColumnsToWidth(widths, viewportWidth, sizes) : widths;
|
|
1232
|
+
}
|
|
1233
|
+
function totalAggregates(rows, aggregates, dataColumns) {
|
|
1234
|
+
return computeAggregates(
|
|
1235
|
+
rows.map((entry) => entry.row),
|
|
1236
|
+
aggregates,
|
|
1237
|
+
dataColumns
|
|
1238
|
+
);
|
|
1239
|
+
}
|
|
1240
|
+
function paginate(displayRows, paginated, pagination) {
|
|
1241
|
+
return paginated ? paginateRows(displayRows, pagination) : { rows: displayRows, pageCount: 1, pageIndex: 0 };
|
|
1242
|
+
}
|
|
1243
|
+
function narrowToDataRows(pageRows, rows, reshaped) {
|
|
1244
|
+
return reshaped ? pageRows.filter((entry) => !("kind" in entry)) : rows;
|
|
1245
|
+
}
|
|
1246
|
+
function createGridViewResolver() {
|
|
1247
|
+
const identify = memoizeLast(identifyRows);
|
|
1248
|
+
const orderColumns = memoizeLast(resolveDataColumns);
|
|
1249
|
+
const showColumns = memoizeLast(applyColumnVisibility);
|
|
1250
|
+
const size = memoizeLast(sizeColumns);
|
|
1251
|
+
const filterAndSort = memoizeLast(resolveShownRows);
|
|
1252
|
+
const group = memoizeLast(groupRows);
|
|
1253
|
+
const aggregate = memoizeLast(withGroupAggregates);
|
|
1254
|
+
const total = memoizeLast(totalAggregates);
|
|
1255
|
+
const page = memoizeLast(paginate);
|
|
1256
|
+
const narrow = memoizeLast(narrowToDataRows);
|
|
1257
|
+
const assemble = memoizeLast(
|
|
1258
|
+
(dataColumns, columns, rows, displayRows, pageRows, displayDataRows, pageCount, pageIndex, grandTotal) => ({
|
|
1259
|
+
dataColumns,
|
|
1260
|
+
columns,
|
|
1261
|
+
rows,
|
|
1262
|
+
displayRows,
|
|
1263
|
+
pageRows,
|
|
1264
|
+
displayDataRows,
|
|
1265
|
+
pageCount,
|
|
1266
|
+
pageIndex,
|
|
1267
|
+
grandTotal
|
|
1268
|
+
})
|
|
1269
|
+
);
|
|
1270
|
+
return ({ rows: data, getRowId, columns: definitions, state, options }) => {
|
|
1271
|
+
const paginated = options.paginated ?? false;
|
|
1272
|
+
const aggregates = options.aggregates ?? NO_AGGREGATES;
|
|
1273
|
+
const dataColumns = orderColumns(definitions, state.columnOrder);
|
|
1274
|
+
const columns = size(
|
|
1275
|
+
showColumns(dataColumns, state.columnVisibility),
|
|
1276
|
+
state.columnSizing,
|
|
1277
|
+
options.columnSizeDefaults,
|
|
1278
|
+
options.resizableColumns,
|
|
1279
|
+
options.reorderableColumns,
|
|
1280
|
+
options.groupByDraggableColumns,
|
|
1281
|
+
options.resizeMode ?? "fit",
|
|
1282
|
+
options.viewportWidth ?? null
|
|
1283
|
+
);
|
|
1284
|
+
const rows = filterAndSort(
|
|
1285
|
+
identify(data, getRowId),
|
|
1286
|
+
state.filter,
|
|
1287
|
+
state.columnSort,
|
|
1288
|
+
dataColumns
|
|
1289
|
+
);
|
|
1290
|
+
const displayRows = aggregate(
|
|
1291
|
+
group(rows, state.groupBy, state.groupExpansion, dataColumns),
|
|
1292
|
+
rows,
|
|
1293
|
+
state.groupBy,
|
|
1294
|
+
aggregates,
|
|
1295
|
+
dataColumns,
|
|
1296
|
+
options.groupAggregateDisplay ?? "inline"
|
|
1297
|
+
);
|
|
1298
|
+
const {
|
|
1299
|
+
rows: pageRows,
|
|
1300
|
+
pageCount,
|
|
1301
|
+
pageIndex
|
|
1302
|
+
} = page(displayRows, paginated, state.pagination);
|
|
1303
|
+
return assemble(
|
|
1304
|
+
dataColumns,
|
|
1305
|
+
columns,
|
|
1306
|
+
rows,
|
|
1307
|
+
displayRows,
|
|
1308
|
+
pageRows,
|
|
1309
|
+
narrow(pageRows, rows, state.groupBy.length > 0 || paginated),
|
|
1310
|
+
pageCount,
|
|
1311
|
+
pageIndex,
|
|
1312
|
+
total(rows, aggregates, dataColumns)
|
|
1313
|
+
);
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
function resolveGridView(input) {
|
|
1317
|
+
return createGridViewResolver()(input);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
// src/controller/changes.ts
|
|
1321
|
+
function changedEntryColumnId(previous, next) {
|
|
1322
|
+
const length = Math.max(previous.length, next.length);
|
|
1323
|
+
for (let index = 0; index < length; index++) {
|
|
1324
|
+
const before = previous[index];
|
|
1325
|
+
const after = next[index];
|
|
1326
|
+
if (before?.columnId !== after?.columnId || before?.direction !== after?.direction) {
|
|
1327
|
+
return (after ?? before)?.columnId;
|
|
1328
|
+
}
|
|
774
1329
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
kind: "group",
|
|
783
|
-
groupId,
|
|
784
|
-
level: parentPath.length,
|
|
785
|
-
columnId: level.columnId,
|
|
786
|
-
value: group.value,
|
|
787
|
-
path,
|
|
788
|
-
expanded,
|
|
789
|
-
count: group.rows.length,
|
|
790
|
-
// Renumbered globally once `groupRows` has the whole flattened array —
|
|
791
|
-
// a header has no row of its own to carry a dataset position, so
|
|
792
|
-
// `datasetIndex` takes the same renumbered value `rowIndex` does.
|
|
793
|
-
rowIndex: -1,
|
|
794
|
-
datasetIndex: -1,
|
|
795
|
-
// Set by `withGroupAggregates`, downstream of grouping — empty here
|
|
796
|
-
// since `groupRows` itself never knows about `AggregateState`.
|
|
797
|
-
aggregates: /* @__PURE__ */ new Map()
|
|
798
|
-
};
|
|
799
|
-
out.push(header);
|
|
800
|
-
if (expanded) {
|
|
801
|
-
buildLevel(group.rows, rest, path, expansion, byId, out);
|
|
1330
|
+
return void 0;
|
|
1331
|
+
}
|
|
1332
|
+
function changedId(previous, next) {
|
|
1333
|
+
const length = Math.max(previous.length, next.length);
|
|
1334
|
+
for (let index = 0; index < length; index++) {
|
|
1335
|
+
if (previous[index] !== next[index]) {
|
|
1336
|
+
return next[index] ?? previous[index];
|
|
802
1337
|
}
|
|
803
1338
|
}
|
|
1339
|
+
return void 0;
|
|
804
1340
|
}
|
|
805
|
-
function
|
|
806
|
-
|
|
807
|
-
|
|
1341
|
+
function changedKeys(previous, next) {
|
|
1342
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(next), ...Object.keys(previous)]);
|
|
1343
|
+
return [...keys].filter((key) => previous[key] !== next[key]);
|
|
1344
|
+
}
|
|
1345
|
+
function sameItems(previous, next) {
|
|
1346
|
+
return previous.length === next.length && previous.every((item, index) => item === next[index]);
|
|
1347
|
+
}
|
|
1348
|
+
function samePagination(previous, next) {
|
|
1349
|
+
return previous.pageIndex === next.pageIndex && previous.pageSize === next.pageSize;
|
|
1350
|
+
}
|
|
1351
|
+
function sameValue(previous, next) {
|
|
1352
|
+
return previous instanceof Date && next instanceof Date ? previous.getTime() === next.getTime() : previous === next;
|
|
1353
|
+
}
|
|
1354
|
+
function sameOperand(previous, next) {
|
|
1355
|
+
if (isScalarList(previous) || isScalarList(next)) {
|
|
1356
|
+
return isScalarList(previous) && isScalarList(next) && previous.length === next.length && previous.every((scalar, index) => sameValue(scalar, next[index]));
|
|
808
1357
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1358
|
+
return sameValue(previous, next);
|
|
1359
|
+
}
|
|
1360
|
+
function sameEntry(previous, next) {
|
|
1361
|
+
if ("combinator" in previous || "combinator" in next) {
|
|
1362
|
+
return "combinator" in previous && "combinator" in next && previous.combinator === next.combinator && sameFilter(previous.entries, next.entries);
|
|
813
1363
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
1364
|
+
if (previous.columnId !== next.columnId) {
|
|
1365
|
+
return false;
|
|
1366
|
+
}
|
|
1367
|
+
if ("predicate" in previous || "predicate" in next) {
|
|
1368
|
+
return "predicate" in previous && "predicate" in next && previous.predicate === next.predicate;
|
|
1369
|
+
}
|
|
1370
|
+
if ("operator" in previous || "operator" in next) {
|
|
1371
|
+
return "operator" in previous && "operator" in next && previous.operator === next.operator && sameOperand(previous.value, next.value);
|
|
1372
|
+
}
|
|
1373
|
+
if ("value" in previous || "value" in next) {
|
|
1374
|
+
return "value" in previous && "value" in next && sameValue(previous.value, next.value);
|
|
1375
|
+
}
|
|
1376
|
+
return previous.query === next.query;
|
|
1377
|
+
}
|
|
1378
|
+
function sameFilter(previous, next) {
|
|
1379
|
+
return previous.length === next.length && previous.every((entry, index) => {
|
|
1380
|
+
const other = next[index];
|
|
1381
|
+
return other !== void 0 && sameEntry(entry, other);
|
|
821
1382
|
});
|
|
822
1383
|
}
|
|
823
|
-
|
|
824
|
-
|
|
1384
|
+
|
|
1385
|
+
// src/util/selection.ts
|
|
1386
|
+
var NO_CHANGE = { added: [], removed: [] };
|
|
1387
|
+
function sameSelection(a, b) {
|
|
1388
|
+
return a.length === b.length && a.every((id, index) => id === b[index]);
|
|
825
1389
|
}
|
|
826
|
-
function
|
|
827
|
-
|
|
1390
|
+
function toggleSelection(selection, id, mode) {
|
|
1391
|
+
if (mode === false) {
|
|
1392
|
+
return selection;
|
|
1393
|
+
}
|
|
1394
|
+
if (selection.includes(id)) {
|
|
1395
|
+
return selection.filter((selectedId) => selectedId !== id);
|
|
1396
|
+
}
|
|
1397
|
+
return mode === "single" ? [id] : [...selection, id];
|
|
828
1398
|
}
|
|
829
|
-
function
|
|
830
|
-
|
|
1399
|
+
function selectOnly(selection, id, mode) {
|
|
1400
|
+
if (mode === false) {
|
|
1401
|
+
return selection;
|
|
1402
|
+
}
|
|
1403
|
+
return selection.length === 1 && selection[0] === id ? selection : [id];
|
|
831
1404
|
}
|
|
832
|
-
function
|
|
833
|
-
if (
|
|
834
|
-
return
|
|
1405
|
+
function selectRange(selection, orderedIds, anchorId, focusId, mode) {
|
|
1406
|
+
if (mode !== "multiple") {
|
|
1407
|
+
return selectOnly(selection, focusId, mode);
|
|
835
1408
|
}
|
|
836
|
-
const
|
|
837
|
-
const
|
|
838
|
-
|
|
1409
|
+
const anchor = orderedIds.indexOf(anchorId);
|
|
1410
|
+
const focus = orderedIds.indexOf(focusId);
|
|
1411
|
+
if (anchor === -1 || focus === -1) {
|
|
1412
|
+
return selection;
|
|
1413
|
+
}
|
|
1414
|
+
const next = orderedIds.slice(
|
|
1415
|
+
Math.min(anchor, focus),
|
|
1416
|
+
Math.max(anchor, focus) + 1
|
|
1417
|
+
);
|
|
1418
|
+
return sameSelection(selection, next) ? selection : next;
|
|
1419
|
+
}
|
|
1420
|
+
function selectAll(selection, orderedIds, mode) {
|
|
1421
|
+
if (mode !== "multiple") {
|
|
1422
|
+
return selection;
|
|
1423
|
+
}
|
|
1424
|
+
return sameSelection(selection, orderedIds) ? selection : orderedIds;
|
|
1425
|
+
}
|
|
1426
|
+
function clearSelection(selection) {
|
|
1427
|
+
return selection.length === 0 ? selection : [];
|
|
1428
|
+
}
|
|
1429
|
+
function diffSelection(previous, next) {
|
|
1430
|
+
if (previous === next) {
|
|
1431
|
+
return NO_CHANGE;
|
|
1432
|
+
}
|
|
1433
|
+
const before = new Set(previous);
|
|
1434
|
+
const after = new Set(next);
|
|
1435
|
+
return {
|
|
1436
|
+
added: next.filter((id) => !before.has(id)),
|
|
1437
|
+
removed: previous.filter((id) => !after.has(id))
|
|
839
1438
|
};
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
1439
|
+
}
|
|
1440
|
+
function isSameCell(a, b) {
|
|
1441
|
+
if (a === null || b === null) {
|
|
1442
|
+
return a === b;
|
|
843
1443
|
}
|
|
844
|
-
|
|
845
|
-
next.splice(target, 0, moved);
|
|
846
|
-
return next.length === groupBy.length && next.every((entry, index) => entry === groupBy[index]) ? groupBy : next;
|
|
1444
|
+
return a.rowId === b.rowId && a.columnId === b.columnId;
|
|
847
1445
|
}
|
|
848
|
-
function
|
|
849
|
-
|
|
1446
|
+
function selectCell(selection, cell, mode) {
|
|
1447
|
+
if (mode === false || isSameCell(selection, cell)) {
|
|
1448
|
+
return selection;
|
|
1449
|
+
}
|
|
1450
|
+
return cell;
|
|
1451
|
+
}
|
|
1452
|
+
function toggleCellSelection(selection, cell, mode) {
|
|
1453
|
+
if (mode === false) {
|
|
1454
|
+
return selection;
|
|
1455
|
+
}
|
|
1456
|
+
return isSameCell(selection, cell) ? null : cell;
|
|
1457
|
+
}
|
|
1458
|
+
function intentOf(event, options) {
|
|
1459
|
+
if (event.shiftKey) {
|
|
1460
|
+
return "range";
|
|
1461
|
+
}
|
|
1462
|
+
if (event.ctrlKey || event.metaKey) {
|
|
1463
|
+
return "toggle";
|
|
1464
|
+
}
|
|
1465
|
+
return options?.toggleOnClick === true ? "toggle" : "replace";
|
|
1466
|
+
}
|
|
1467
|
+
function applySelectionIntent(selection, orderedIds, anchorId, id, intent, mode) {
|
|
1468
|
+
switch (intent) {
|
|
1469
|
+
case "toggle":
|
|
1470
|
+
return toggleSelection(selection, id, mode);
|
|
1471
|
+
// A range with no anchor yet spans from the id to itself, which is the
|
|
1472
|
+
// plain click a first Shift-click may as well be.
|
|
1473
|
+
case "range":
|
|
1474
|
+
return selectRange(selection, orderedIds, anchorId ?? id, id, mode);
|
|
1475
|
+
default:
|
|
1476
|
+
return selectOnly(selection, id, mode);
|
|
1477
|
+
}
|
|
850
1478
|
}
|
|
851
1479
|
|
|
852
|
-
// src/
|
|
853
|
-
function
|
|
854
|
-
|
|
1480
|
+
// src/controller/selectionEvents.ts
|
|
1481
|
+
function reportRowSelection(previous, next, rowsById, callbacks) {
|
|
1482
|
+
const diff = diffSelection(previous, next);
|
|
1483
|
+
const added = resolveRows(rowsById, diff.added);
|
|
1484
|
+
const removed = resolveRows(rowsById, diff.removed);
|
|
1485
|
+
for (const row of added) {
|
|
1486
|
+
callbacks.onRowSelect?.({ row, selection: next });
|
|
1487
|
+
}
|
|
1488
|
+
if (added.length > 0) {
|
|
1489
|
+
callbacks.onRowsSelect?.({ rows: added, selection: next });
|
|
1490
|
+
}
|
|
1491
|
+
for (const row of removed) {
|
|
1492
|
+
callbacks.onRowDeselect?.({ row, selection: next });
|
|
1493
|
+
}
|
|
1494
|
+
if (removed.length > 0) {
|
|
1495
|
+
callbacks.onRowsDeselect?.({ rows: removed, selection: next });
|
|
1496
|
+
}
|
|
1497
|
+
callbacks.onRowSelectionChange?.({
|
|
1498
|
+
added,
|
|
1499
|
+
removed,
|
|
1500
|
+
selected: resolveRows(rowsById, next),
|
|
1501
|
+
selection: next
|
|
1502
|
+
});
|
|
1503
|
+
return diff;
|
|
855
1504
|
}
|
|
856
|
-
function
|
|
857
|
-
|
|
1505
|
+
function reportColumnSelection(previous, next, columns, callbacks) {
|
|
1506
|
+
const diff = diffSelection(previous, next);
|
|
1507
|
+
const added = resolveColumns(columns, diff.added);
|
|
1508
|
+
const removed = resolveColumns(columns, diff.removed);
|
|
1509
|
+
for (const column of added) {
|
|
1510
|
+
callbacks.onColumnSelect?.({ column, selection: next });
|
|
1511
|
+
}
|
|
1512
|
+
if (added.length > 0) {
|
|
1513
|
+
callbacks.onColumnsSelect?.({ columns: added, selection: next });
|
|
1514
|
+
}
|
|
1515
|
+
for (const column of removed) {
|
|
1516
|
+
callbacks.onColumnDeselect?.({ column, selection: next });
|
|
1517
|
+
}
|
|
1518
|
+
if (removed.length > 0) {
|
|
1519
|
+
callbacks.onColumnsDeselect?.({ columns: removed, selection: next });
|
|
1520
|
+
}
|
|
1521
|
+
callbacks.onColumnSelectionChange?.({
|
|
1522
|
+
added,
|
|
1523
|
+
removed,
|
|
1524
|
+
selected: resolveColumns(columns, next),
|
|
1525
|
+
selection: next
|
|
1526
|
+
});
|
|
1527
|
+
return diff;
|
|
858
1528
|
}
|
|
859
|
-
function
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
}
|
|
1529
|
+
function reportCellSelection(previous, next, rowsById, columns, callbacks) {
|
|
1530
|
+
const selected = resolveCell(rowsById, columns, next);
|
|
1531
|
+
const deselected = resolveCell(rowsById, columns, previous);
|
|
1532
|
+
if (deselected !== null) {
|
|
1533
|
+
callbacks.onCellDeselect?.({ cell: deselected, selection: next });
|
|
1534
|
+
}
|
|
1535
|
+
if (selected !== null) {
|
|
1536
|
+
callbacks.onCellSelect?.({ cell: selected, selection: next });
|
|
1537
|
+
}
|
|
1538
|
+
callbacks.onCellSelectionChange?.({
|
|
1539
|
+
selected,
|
|
1540
|
+
deselected,
|
|
1541
|
+
selection: next
|
|
1542
|
+
});
|
|
865
1543
|
}
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
1544
|
+
|
|
1545
|
+
// src/controller/selectionActions.ts
|
|
1546
|
+
function indexRows(rows) {
|
|
1547
|
+
return new Map(rows.map((entry) => [entry.rowId, entry]));
|
|
1548
|
+
}
|
|
1549
|
+
function distinct(ids) {
|
|
1550
|
+
return [...new Set(ids)];
|
|
1551
|
+
}
|
|
1552
|
+
function createSelectionActions(grid) {
|
|
1553
|
+
let rowAnchor = null;
|
|
1554
|
+
let columnAnchor = null;
|
|
1555
|
+
const rowsById = memoizeLast(indexRows);
|
|
1556
|
+
function modes() {
|
|
1557
|
+
const selectable = grid.getOptions().selectable;
|
|
1558
|
+
return {
|
|
1559
|
+
rows: selectable?.rows ?? false,
|
|
1560
|
+
columns: selectable?.columns ?? false,
|
|
1561
|
+
cells: selectable?.cells ?? false
|
|
1562
|
+
};
|
|
869
1563
|
}
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
)
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
1564
|
+
function rowIds() {
|
|
1565
|
+
return grid.getView().displayDataRows.map((entry) => entry.rowId);
|
|
1566
|
+
}
|
|
1567
|
+
function columnIds() {
|
|
1568
|
+
return grid.getView().columns.map((entry) => entry.id);
|
|
1569
|
+
}
|
|
1570
|
+
function commitRows(next) {
|
|
1571
|
+
const previous = grid.getState().rowSelection;
|
|
1572
|
+
grid.commit("rowSelection", next, () => {
|
|
1573
|
+
const options = grid.getOptions();
|
|
1574
|
+
const diff = reportRowSelection(
|
|
1575
|
+
previous,
|
|
1576
|
+
next,
|
|
1577
|
+
rowsById(grid.getView().displayDataRows),
|
|
1578
|
+
options
|
|
1579
|
+
);
|
|
1580
|
+
options.onSelectionDiff?.({ target: "rows", ...diff, selection: next });
|
|
1581
|
+
});
|
|
1582
|
+
}
|
|
1583
|
+
function commitColumns(next) {
|
|
1584
|
+
const previous = grid.getState().columnSelection;
|
|
1585
|
+
grid.commit("columnSelection", next, () => {
|
|
1586
|
+
const options = grid.getOptions();
|
|
1587
|
+
const diff = reportColumnSelection(
|
|
1588
|
+
previous,
|
|
1589
|
+
next,
|
|
1590
|
+
grid.getView().columns,
|
|
1591
|
+
options
|
|
1592
|
+
);
|
|
1593
|
+
options.onSelectionDiff?.({
|
|
1594
|
+
target: "columns",
|
|
1595
|
+
...diff,
|
|
1596
|
+
selection: next
|
|
1597
|
+
});
|
|
1598
|
+
});
|
|
1599
|
+
}
|
|
1600
|
+
function commitCell(next) {
|
|
1601
|
+
const previous = grid.getState().cellSelection;
|
|
1602
|
+
grid.commit("cellSelection", next, () => {
|
|
1603
|
+
const view = grid.getView();
|
|
1604
|
+
reportCellSelection(
|
|
1605
|
+
previous,
|
|
1606
|
+
next,
|
|
1607
|
+
rowsById(view.displayDataRows),
|
|
1608
|
+
view.columns,
|
|
1609
|
+
grid.getOptions()
|
|
1610
|
+
);
|
|
1611
|
+
});
|
|
877
1612
|
}
|
|
878
1613
|
return {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1614
|
+
setRowSelection(selection) {
|
|
1615
|
+
if (!sameItems(grid.getState().rowSelection, selection)) {
|
|
1616
|
+
commitRows(selection);
|
|
1617
|
+
}
|
|
1618
|
+
},
|
|
1619
|
+
selectRows(ids, intent = "replace") {
|
|
1620
|
+
const mode = modes().rows;
|
|
1621
|
+
const current = grid.getState().rowSelection;
|
|
1622
|
+
if (mode === false || ids.length === 0) {
|
|
1623
|
+
return;
|
|
1624
|
+
}
|
|
1625
|
+
const next = intent === "toggle" ? ids.reduce(
|
|
1626
|
+
(selection, id) => toggleSelection(selection, id, mode),
|
|
1627
|
+
current
|
|
1628
|
+
) : mode === "single" ? ids.slice(-1) : distinct(ids);
|
|
1629
|
+
rowAnchor = ids.at(-1) ?? null;
|
|
1630
|
+
if (!sameItems(current, next)) {
|
|
1631
|
+
commitRows(next);
|
|
1632
|
+
}
|
|
1633
|
+
},
|
|
1634
|
+
selectRow(rowId, intent) {
|
|
1635
|
+
const next = applySelectionIntent(
|
|
1636
|
+
grid.getState().rowSelection,
|
|
1637
|
+
rowIds(),
|
|
1638
|
+
rowAnchor,
|
|
1639
|
+
rowId,
|
|
1640
|
+
intent,
|
|
1641
|
+
modes().rows
|
|
1642
|
+
);
|
|
1643
|
+
if (intent !== "range") {
|
|
1644
|
+
rowAnchor = rowId;
|
|
1645
|
+
}
|
|
1646
|
+
commitRows(next);
|
|
1647
|
+
},
|
|
1648
|
+
selectAllRows() {
|
|
1649
|
+
commitRows(
|
|
1650
|
+
selectAll(grid.getState().rowSelection, rowIds(), modes().rows)
|
|
1651
|
+
);
|
|
1652
|
+
},
|
|
1653
|
+
clearSelection() {
|
|
1654
|
+
commitRows(clearSelection(grid.getState().rowSelection));
|
|
1655
|
+
commitColumns(clearSelection(grid.getState().columnSelection));
|
|
1656
|
+
commitCell(null);
|
|
1657
|
+
},
|
|
1658
|
+
setColumnSelection(selection) {
|
|
1659
|
+
if (!sameItems(grid.getState().columnSelection, selection)) {
|
|
1660
|
+
commitColumns(selection);
|
|
1661
|
+
}
|
|
1662
|
+
},
|
|
1663
|
+
selectColumn(columnId, intent) {
|
|
1664
|
+
const next = applySelectionIntent(
|
|
1665
|
+
grid.getState().columnSelection,
|
|
1666
|
+
columnIds(),
|
|
1667
|
+
columnAnchor,
|
|
1668
|
+
columnId,
|
|
1669
|
+
intent,
|
|
1670
|
+
modes().columns
|
|
1671
|
+
);
|
|
1672
|
+
if (intent !== "range") {
|
|
1673
|
+
columnAnchor = columnId;
|
|
1674
|
+
}
|
|
1675
|
+
commitColumns(next);
|
|
1676
|
+
},
|
|
1677
|
+
setCellSelection(selection) {
|
|
1678
|
+
if (!isSameCell(grid.getState().cellSelection, selection)) {
|
|
1679
|
+
commitCell(selection);
|
|
1680
|
+
}
|
|
1681
|
+
},
|
|
1682
|
+
selectCell(cell, intent) {
|
|
1683
|
+
const current = grid.getState().cellSelection;
|
|
1684
|
+
const mode = modes().cells;
|
|
1685
|
+
commitCell(
|
|
1686
|
+
intent === "toggle" ? toggleCellSelection(current, cell, mode) : selectCell(current, cell, mode)
|
|
1687
|
+
);
|
|
1688
|
+
}
|
|
886
1689
|
};
|
|
887
1690
|
}
|
|
888
1691
|
|
|
889
|
-
// src/
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
1692
|
+
// src/controller/createGridController.ts
|
|
1693
|
+
var DEFAULT_PAGE_SIZE = 25;
|
|
1694
|
+
var NO_ROWS = [];
|
|
1695
|
+
var NO_COLUMNS = [];
|
|
1696
|
+
var SLICE_KEYS = [
|
|
1697
|
+
"columnSizing",
|
|
1698
|
+
"columnOrder",
|
|
1699
|
+
"columnVisibility",
|
|
1700
|
+
"columnSort",
|
|
1701
|
+
"filter",
|
|
1702
|
+
"groupBy",
|
|
1703
|
+
"groupExpansion",
|
|
1704
|
+
"pagination",
|
|
1705
|
+
"rowSelection",
|
|
1706
|
+
"columnSelection",
|
|
1707
|
+
"cellSelection"
|
|
1708
|
+
];
|
|
1709
|
+
var DEFAULT_OPTION = {
|
|
1710
|
+
columnSizing: "defaultColumnSizing",
|
|
1711
|
+
columnOrder: "defaultColumnOrder",
|
|
1712
|
+
columnVisibility: "defaultColumnVisibility",
|
|
1713
|
+
columnSort: "defaultColumnSort",
|
|
1714
|
+
filter: "defaultFilter",
|
|
1715
|
+
groupBy: "defaultGroupBy",
|
|
1716
|
+
groupExpansion: "defaultGroupExpansion",
|
|
1717
|
+
pagination: "defaultPagination",
|
|
1718
|
+
rowSelection: "defaultRowSelection",
|
|
1719
|
+
columnSelection: "defaultColumnSelection",
|
|
1720
|
+
cellSelection: "defaultCellSelection"
|
|
1721
|
+
};
|
|
1722
|
+
function startingState(options) {
|
|
1723
|
+
return {
|
|
1724
|
+
columnSizing: options.defaultColumnSizing ?? {},
|
|
1725
|
+
columnOrder: options.defaultColumnOrder ?? [],
|
|
1726
|
+
columnVisibility: options.defaultColumnVisibility ?? {},
|
|
1727
|
+
columnSort: options.defaultColumnSort ?? [],
|
|
1728
|
+
filter: options.defaultFilter ?? [],
|
|
1729
|
+
groupBy: options.defaultGroupBy ?? [],
|
|
1730
|
+
groupExpansion: options.defaultGroupExpansion ?? [],
|
|
1731
|
+
pagination: options.defaultPagination ?? {
|
|
1732
|
+
pageIndex: 0,
|
|
1733
|
+
pageSize: DEFAULT_PAGE_SIZE
|
|
1734
|
+
},
|
|
1735
|
+
rowSelection: options.defaultRowSelection ?? [],
|
|
1736
|
+
columnSelection: options.defaultColumnSelection ?? [],
|
|
1737
|
+
cellSelection: options.defaultCellSelection ?? null
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
function definedColumns(columns, rows) {
|
|
1741
|
+
if (columns !== void 0 && columns.length > 0) {
|
|
1742
|
+
return columns;
|
|
1743
|
+
}
|
|
1744
|
+
if (rows !== void 0 && rows.length > 0) {
|
|
1745
|
+
return defineColumnsFromRows(rows);
|
|
1746
|
+
}
|
|
1747
|
+
return NO_COLUMNS;
|
|
1748
|
+
}
|
|
1749
|
+
function pagingInputsOf(state) {
|
|
1750
|
+
return {
|
|
1751
|
+
filter: state.filter,
|
|
1752
|
+
columnSort: state.columnSort,
|
|
1753
|
+
groupBy: state.groupBy
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
function createGridController(initial) {
|
|
1757
|
+
let options = initial;
|
|
1758
|
+
const own = startingState(initial);
|
|
1759
|
+
const resolveView = createGridViewResolver();
|
|
1760
|
+
const resolveColumns2 = memoizeLast(definedColumns);
|
|
1761
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1762
|
+
const reportedConflicts = /* @__PURE__ */ new Set();
|
|
1763
|
+
let heldReports;
|
|
1764
|
+
let state = resolveSlices();
|
|
1765
|
+
let pagingInputs = pagingInputsOf(state);
|
|
1766
|
+
reportConflicts();
|
|
1767
|
+
function controlledValue(key) {
|
|
1768
|
+
const controlled = options;
|
|
1769
|
+
return controlled[key];
|
|
1770
|
+
}
|
|
1771
|
+
function isControlled(key) {
|
|
1772
|
+
return controlledValue(key) !== void 0;
|
|
1773
|
+
}
|
|
1774
|
+
function resolveSlice(key) {
|
|
1775
|
+
const controlled = controlledValue(key);
|
|
1776
|
+
return controlled === void 0 ? own[key] : controlled;
|
|
1777
|
+
}
|
|
1778
|
+
function resolveSlices() {
|
|
1779
|
+
return {
|
|
1780
|
+
columnSizing: resolveSlice("columnSizing"),
|
|
1781
|
+
columnOrder: resolveSlice("columnOrder"),
|
|
1782
|
+
columnVisibility: resolveSlice("columnVisibility"),
|
|
1783
|
+
columnSort: resolveSlice("columnSort"),
|
|
1784
|
+
filter: resolveSlice("filter"),
|
|
1785
|
+
groupBy: resolveSlice("groupBy"),
|
|
1786
|
+
groupExpansion: resolveSlice("groupExpansion"),
|
|
1787
|
+
pagination: resolveSlice("pagination"),
|
|
1788
|
+
rowSelection: resolveSlice("rowSelection"),
|
|
1789
|
+
columnSelection: resolveSlice("columnSelection"),
|
|
1790
|
+
cellSelection: resolveSlice("cellSelection")
|
|
1791
|
+
};
|
|
1792
|
+
}
|
|
1793
|
+
function reportConflicts() {
|
|
1794
|
+
for (const key of SLICE_KEYS) {
|
|
1795
|
+
const defaultKey = DEFAULT_OPTION[key];
|
|
1796
|
+
if (reportedConflicts.has(key) || !isControlled(key) || options[defaultKey] === void 0) {
|
|
1797
|
+
continue;
|
|
1798
|
+
}
|
|
1799
|
+
reportedConflicts.add(key);
|
|
1800
|
+
reportError(
|
|
1801
|
+
`\`${key}\` and \`${defaultKey}\` are both set \u2014 \`${key}\` is controlled, so \`${defaultKey}\` is ignored.`
|
|
1802
|
+
);
|
|
898
1803
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
1804
|
+
}
|
|
1805
|
+
function refresh() {
|
|
1806
|
+
let next = resolveSlices();
|
|
1807
|
+
if (next.filter !== pagingInputs.filter || next.columnSort !== pagingInputs.columnSort || next.groupBy !== pagingInputs.groupBy) {
|
|
1808
|
+
pagingInputs = pagingInputsOf(next);
|
|
1809
|
+
if (!isControlled("pagination") && own.pagination.pageIndex !== 0) {
|
|
1810
|
+
own.pagination = { ...own.pagination, pageIndex: 0 };
|
|
1811
|
+
next = { ...next, pagination: own.pagination };
|
|
1812
|
+
}
|
|
907
1813
|
}
|
|
1814
|
+
state = SLICE_KEYS.every((key) => next[key] === state[key]) ? state : next;
|
|
908
1815
|
}
|
|
909
|
-
|
|
910
|
-
|
|
1816
|
+
function notify() {
|
|
1817
|
+
for (const listener of [...listeners]) {
|
|
1818
|
+
listener();
|
|
1819
|
+
}
|
|
911
1820
|
}
|
|
912
|
-
|
|
1821
|
+
function commit(key, next, report) {
|
|
1822
|
+
if (next === state[key]) {
|
|
1823
|
+
return;
|
|
1824
|
+
}
|
|
1825
|
+
if (!isControlled(key)) {
|
|
1826
|
+
own[key] = next;
|
|
1827
|
+
}
|
|
1828
|
+
if (heldReports !== void 0) {
|
|
1829
|
+
heldReports.push(report);
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
refresh();
|
|
1833
|
+
report();
|
|
1834
|
+
notify();
|
|
1835
|
+
}
|
|
1836
|
+
function getView() {
|
|
1837
|
+
return resolveView({
|
|
1838
|
+
rows: options.dataSource ?? NO_ROWS,
|
|
1839
|
+
getRowId: options.getRowId,
|
|
1840
|
+
columns: resolveColumns2(options.columns, options.dataSource),
|
|
1841
|
+
state,
|
|
1842
|
+
options: {
|
|
1843
|
+
paginated: options.paginated,
|
|
1844
|
+
aggregates: options.aggregates,
|
|
1845
|
+
groupAggregateDisplay: options.groupAggregateDisplay,
|
|
1846
|
+
columnSizeDefaults: options.columnSizeDefaults,
|
|
1847
|
+
resizableColumns: options.resizableColumns,
|
|
1848
|
+
reorderableColumns: options.reorderableColumns,
|
|
1849
|
+
groupByDraggableColumns: options.groupByDraggableColumns,
|
|
1850
|
+
resizeMode: options.resizeMode,
|
|
1851
|
+
viewportWidth: options.viewportWidth
|
|
1852
|
+
}
|
|
1853
|
+
});
|
|
1854
|
+
}
|
|
1855
|
+
function commitColumnSizing(next, columnId, width, phase) {
|
|
1856
|
+
commit("columnSizing", next, () => {
|
|
1857
|
+
options.onColumnResize?.({ columnId, width, sizing: next, phase });
|
|
1858
|
+
});
|
|
1859
|
+
}
|
|
1860
|
+
function definedWidth(columnId) {
|
|
1861
|
+
const entry = getView().dataColumns.find(
|
|
1862
|
+
(candidate) => candidate.id === columnId
|
|
1863
|
+
);
|
|
1864
|
+
const [resolved] = entry === void 0 ? [] : resolveColumnWidths(
|
|
1865
|
+
[entry.column],
|
|
1866
|
+
{},
|
|
1867
|
+
{
|
|
1868
|
+
sizes: options.columnSizeDefaults
|
|
1869
|
+
}
|
|
1870
|
+
);
|
|
1871
|
+
return resolved?.width ?? 0;
|
|
1872
|
+
}
|
|
1873
|
+
function commitColumnVisibility(next) {
|
|
1874
|
+
const previous = state.columnVisibility;
|
|
1875
|
+
commit("columnVisibility", next, () => {
|
|
1876
|
+
const changed = new Set(changedKeys(previous, next));
|
|
1877
|
+
const shown = getView().dataColumns.map((entry) => entry.id).filter((id) => changed.delete(id));
|
|
1878
|
+
options.onColumnVisibilityChange?.({
|
|
1879
|
+
columnIds: [...shown, ...changed],
|
|
1880
|
+
visibility: next
|
|
1881
|
+
});
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
function changeColumnVisibility(columnIds, visible) {
|
|
1885
|
+
commitColumnVisibility(
|
|
1886
|
+
setColumnVisibility(
|
|
1887
|
+
getView().dataColumns,
|
|
1888
|
+
state.columnVisibility,
|
|
1889
|
+
columnIds,
|
|
1890
|
+
visible
|
|
1891
|
+
)
|
|
1892
|
+
);
|
|
1893
|
+
}
|
|
1894
|
+
function commitGroupBy(next, columnId) {
|
|
1895
|
+
commit("groupBy", next, () => {
|
|
1896
|
+
options.onGroupByChange?.({ columnId, groupBy: next });
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
function commitGroupExpansion(next, groupId) {
|
|
1900
|
+
commit("groupExpansion", next, () => {
|
|
1901
|
+
options.onGroupExpansionChange?.({ groupId, expansion: next });
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1904
|
+
function commitPagination(next) {
|
|
1905
|
+
commit("pagination", next, () => {
|
|
1906
|
+
options.onPaginationChange?.({
|
|
1907
|
+
pagination: next,
|
|
1908
|
+
pageCount: paginateRows(getView().displayRows, next).pageCount
|
|
1909
|
+
});
|
|
1910
|
+
});
|
|
1911
|
+
}
|
|
1912
|
+
function goToPage(pageIndex) {
|
|
1913
|
+
const current = state.pagination;
|
|
1914
|
+
const clamped = paginateRows(getView().displayRows, {
|
|
1915
|
+
...current,
|
|
1916
|
+
pageIndex
|
|
1917
|
+
}).pageIndex;
|
|
1918
|
+
commitPagination({ ...current, pageIndex: clamped });
|
|
1919
|
+
}
|
|
1920
|
+
function shownPageIndex() {
|
|
1921
|
+
return paginateRows(getView().displayRows, state.pagination).pageIndex;
|
|
1922
|
+
}
|
|
1923
|
+
const selection = createSelectionActions({
|
|
1924
|
+
getState: () => state,
|
|
1925
|
+
getOptions: () => options,
|
|
1926
|
+
getView,
|
|
1927
|
+
commit
|
|
1928
|
+
});
|
|
1929
|
+
const controller = {
|
|
1930
|
+
...selection,
|
|
1931
|
+
getOptions: () => options,
|
|
1932
|
+
setOptions(next) {
|
|
1933
|
+
options = next;
|
|
1934
|
+
reportConflicts();
|
|
1935
|
+
refresh();
|
|
1936
|
+
},
|
|
1937
|
+
getState: () => state,
|
|
1938
|
+
getView,
|
|
1939
|
+
restoreState(saved) {
|
|
1940
|
+
const reports = [];
|
|
1941
|
+
heldReports = reports;
|
|
1942
|
+
try {
|
|
1943
|
+
restoreSlices(saved);
|
|
1944
|
+
} finally {
|
|
1945
|
+
heldReports = void 0;
|
|
1946
|
+
}
|
|
1947
|
+
if (saved.pagination !== void 0) {
|
|
1948
|
+
pagingInputs = pagingInputsOf(resolveSlices());
|
|
1949
|
+
}
|
|
1950
|
+
refresh();
|
|
1951
|
+
for (const report of reports) {
|
|
1952
|
+
report();
|
|
1953
|
+
}
|
|
1954
|
+
if (reports.length > 0) {
|
|
1955
|
+
notify();
|
|
1956
|
+
}
|
|
1957
|
+
},
|
|
1958
|
+
subscribe(listener) {
|
|
1959
|
+
listeners.add(listener);
|
|
1960
|
+
return () => {
|
|
1961
|
+
listeners.delete(listener);
|
|
1962
|
+
};
|
|
1963
|
+
},
|
|
1964
|
+
setColumnSizing(sizing) {
|
|
1965
|
+
const [columnId] = changedKeys(state.columnSizing, sizing);
|
|
1966
|
+
if (columnId !== void 0) {
|
|
1967
|
+
commitColumnSizing(
|
|
1968
|
+
sizing,
|
|
1969
|
+
columnId,
|
|
1970
|
+
sizing[columnId] ?? definedWidth(columnId),
|
|
1971
|
+
"end"
|
|
1972
|
+
);
|
|
1973
|
+
}
|
|
1974
|
+
},
|
|
1975
|
+
resizeColumn(columnId, width, phase) {
|
|
1976
|
+
commitColumnSizing(
|
|
1977
|
+
{ ...state.columnSizing, [columnId]: width },
|
|
1978
|
+
columnId,
|
|
1979
|
+
width,
|
|
1980
|
+
phase
|
|
1981
|
+
);
|
|
1982
|
+
},
|
|
1983
|
+
cancelColumnResize(columnId, startSizing, startWidth) {
|
|
1984
|
+
commitColumnSizing(
|
|
1985
|
+
revertColumnSize(state.columnSizing, startSizing, columnId),
|
|
1986
|
+
columnId,
|
|
1987
|
+
startWidth,
|
|
1988
|
+
"end"
|
|
1989
|
+
);
|
|
1990
|
+
},
|
|
1991
|
+
setColumnOrder(order) {
|
|
1992
|
+
const columnId = changedId(state.columnOrder, order);
|
|
1993
|
+
if (columnId === void 0) {
|
|
1994
|
+
return;
|
|
1995
|
+
}
|
|
1996
|
+
commit("columnOrder", order, () => {
|
|
1997
|
+
options.onColumnOrderChange?.({ columnId, order });
|
|
1998
|
+
});
|
|
1999
|
+
},
|
|
2000
|
+
/**
|
|
2001
|
+
* Applied to every id in display order rather than to the stored order,
|
|
2002
|
+
* which starts empty and may name only some columns, so would have
|
|
2003
|
+
* nothing to rearrange.
|
|
2004
|
+
*/
|
|
2005
|
+
moveColumn(columnId, beforeId) {
|
|
2006
|
+
const orderedIds = getView().dataColumns.map((entry) => entry.id);
|
|
2007
|
+
const next = moveColumnBefore(orderedIds, columnId, beforeId);
|
|
2008
|
+
if (next === orderedIds) {
|
|
2009
|
+
return;
|
|
2010
|
+
}
|
|
2011
|
+
commit("columnOrder", next, () => {
|
|
2012
|
+
options.onColumnOrderChange?.({ columnId, order: next });
|
|
2013
|
+
});
|
|
2014
|
+
},
|
|
2015
|
+
setColumnVisibility(visibility) {
|
|
2016
|
+
if (changedKeys(state.columnVisibility, visibility).length > 0) {
|
|
2017
|
+
commitColumnVisibility(visibility);
|
|
2018
|
+
}
|
|
2019
|
+
},
|
|
2020
|
+
showColumns(columnIds) {
|
|
2021
|
+
changeColumnVisibility(columnIds, true);
|
|
2022
|
+
},
|
|
2023
|
+
hideColumns(columnIds) {
|
|
2024
|
+
changeColumnVisibility(columnIds, false);
|
|
2025
|
+
},
|
|
2026
|
+
setFilter(filter) {
|
|
2027
|
+
if (sameFilter(state.filter, filter)) {
|
|
2028
|
+
return;
|
|
2029
|
+
}
|
|
2030
|
+
commit("filter", filter, () => {
|
|
2031
|
+
options.onFilterChange?.({ filter });
|
|
2032
|
+
});
|
|
2033
|
+
},
|
|
2034
|
+
setColumnSort(sort) {
|
|
2035
|
+
const columnId = changedEntryColumnId(state.columnSort, sort);
|
|
2036
|
+
if (columnId === void 0) {
|
|
2037
|
+
return;
|
|
2038
|
+
}
|
|
2039
|
+
commit("columnSort", sort, () => {
|
|
2040
|
+
options.onColumnSortChange?.({ columnId, sort });
|
|
2041
|
+
});
|
|
2042
|
+
},
|
|
2043
|
+
toggleColumnSort(columnId, { stack = false } = {}) {
|
|
2044
|
+
const next = toggleColumnSort(state.columnSort, columnId, { stack });
|
|
2045
|
+
commit("columnSort", next, () => {
|
|
2046
|
+
options.onColumnSortChange?.({ columnId, sort: next });
|
|
2047
|
+
});
|
|
2048
|
+
},
|
|
2049
|
+
setGroupBy(groupBy) {
|
|
2050
|
+
const columnId = changedEntryColumnId(state.groupBy, groupBy);
|
|
2051
|
+
if (columnId !== void 0) {
|
|
2052
|
+
commitGroupBy(groupBy, columnId);
|
|
2053
|
+
}
|
|
2054
|
+
},
|
|
2055
|
+
toggleGroupBy(columnId) {
|
|
2056
|
+
const grouped = state.groupBy.some(
|
|
2057
|
+
(entry) => entry.columnId === columnId
|
|
2058
|
+
);
|
|
2059
|
+
commitGroupBy(
|
|
2060
|
+
grouped ? state.groupBy.filter((entry) => entry.columnId !== columnId) : [...state.groupBy, { columnId }],
|
|
2061
|
+
columnId
|
|
2062
|
+
);
|
|
2063
|
+
},
|
|
2064
|
+
moveGroupBy(columnId, beforeColumnId) {
|
|
2065
|
+
commitGroupBy(
|
|
2066
|
+
moveGroupByBefore(state.groupBy, columnId, beforeColumnId),
|
|
2067
|
+
columnId
|
|
2068
|
+
);
|
|
2069
|
+
},
|
|
2070
|
+
setGroupExpansion(expansion) {
|
|
2071
|
+
if (!sameItems(state.groupExpansion, expansion)) {
|
|
2072
|
+
commitGroupExpansion(expansion, null);
|
|
2073
|
+
}
|
|
2074
|
+
},
|
|
2075
|
+
toggleGroupExpansion(groupId) {
|
|
2076
|
+
commitGroupExpansion(
|
|
2077
|
+
toggleGroupExpansion(state.groupExpansion, groupId),
|
|
2078
|
+
groupId
|
|
2079
|
+
);
|
|
2080
|
+
},
|
|
2081
|
+
expandAllGroups() {
|
|
2082
|
+
commitGroupExpansion(expandAllGroups(state.groupExpansion), null);
|
|
2083
|
+
},
|
|
2084
|
+
collapseAllGroups() {
|
|
2085
|
+
commitGroupExpansion(collapseAllGroups(getView().displayRows), null);
|
|
2086
|
+
},
|
|
2087
|
+
setPagination(pagination) {
|
|
2088
|
+
if (!samePagination(state.pagination, pagination)) {
|
|
2089
|
+
commitPagination(pagination);
|
|
2090
|
+
}
|
|
2091
|
+
},
|
|
2092
|
+
goToPage,
|
|
2093
|
+
nextPage() {
|
|
2094
|
+
goToPage(shownPageIndex() + 1);
|
|
2095
|
+
},
|
|
2096
|
+
previousPage() {
|
|
2097
|
+
goToPage(shownPageIndex() - 1);
|
|
2098
|
+
},
|
|
2099
|
+
setPageSize(pageSize) {
|
|
2100
|
+
const first = { pageIndex: 0, pageSize };
|
|
2101
|
+
commitPagination({
|
|
2102
|
+
...first,
|
|
2103
|
+
pageIndex: paginateRows(getView().displayRows, first).pageIndex
|
|
2104
|
+
});
|
|
2105
|
+
}
|
|
2106
|
+
};
|
|
2107
|
+
function restoreSlices(saved) {
|
|
2108
|
+
if (saved.columnSizing !== void 0) {
|
|
2109
|
+
controller.setColumnSizing(saved.columnSizing);
|
|
2110
|
+
}
|
|
2111
|
+
if (saved.columnOrder !== void 0) {
|
|
2112
|
+
controller.setColumnOrder(saved.columnOrder);
|
|
2113
|
+
}
|
|
2114
|
+
if (saved.columnVisibility !== void 0) {
|
|
2115
|
+
controller.setColumnVisibility(saved.columnVisibility);
|
|
2116
|
+
}
|
|
2117
|
+
if (saved.columnSort !== void 0) {
|
|
2118
|
+
controller.setColumnSort(saved.columnSort);
|
|
2119
|
+
}
|
|
2120
|
+
if (saved.filter !== void 0) {
|
|
2121
|
+
controller.setFilter(reviveFilter(saved.filter, getView().dataColumns));
|
|
2122
|
+
}
|
|
2123
|
+
if (saved.groupBy !== void 0) {
|
|
2124
|
+
controller.setGroupBy(saved.groupBy);
|
|
2125
|
+
}
|
|
2126
|
+
if (saved.groupExpansion !== void 0) {
|
|
2127
|
+
controller.setGroupExpansion(saved.groupExpansion);
|
|
2128
|
+
}
|
|
2129
|
+
if (saved.pagination !== void 0) {
|
|
2130
|
+
controller.setPagination(saved.pagination);
|
|
2131
|
+
}
|
|
2132
|
+
if (saved.rowSelection !== void 0) {
|
|
2133
|
+
controller.setRowSelection(saved.rowSelection);
|
|
2134
|
+
}
|
|
2135
|
+
if (saved.columnSelection !== void 0) {
|
|
2136
|
+
controller.setColumnSelection(saved.columnSelection);
|
|
2137
|
+
}
|
|
2138
|
+
if (saved.cellSelection !== void 0) {
|
|
2139
|
+
controller.setCellSelection(saved.cellSelection);
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
return controller;
|
|
913
2143
|
}
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
2144
|
+
|
|
2145
|
+
// src/util/navigation.ts
|
|
2146
|
+
var HEADER_ROW = -1;
|
|
2147
|
+
function clampFocus(focus, rowCount, columnCount) {
|
|
2148
|
+
return {
|
|
2149
|
+
rowIndex: Math.min(Math.max(focus.rowIndex, HEADER_ROW), rowCount - 1),
|
|
2150
|
+
columnIndex: Math.min(
|
|
2151
|
+
Math.max(focus.columnIndex, 0),
|
|
2152
|
+
Math.max(columnCount - 1, 0)
|
|
2153
|
+
)
|
|
2154
|
+
};
|
|
2155
|
+
}
|
|
2156
|
+
function noRowsSkippable() {
|
|
2157
|
+
return false;
|
|
2158
|
+
}
|
|
2159
|
+
function skipSkippableRows(rowIndex, direction, rowCount, isSkippableRow, fallback) {
|
|
2160
|
+
let next = rowIndex;
|
|
2161
|
+
while (next >= 0 && next < rowCount && isSkippableRow(next)) {
|
|
2162
|
+
const stepped = next + direction;
|
|
2163
|
+
if (stepped < HEADER_ROW || stepped >= rowCount) {
|
|
2164
|
+
return fallback;
|
|
2165
|
+
}
|
|
2166
|
+
next = stepped;
|
|
920
2167
|
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
if (
|
|
925
|
-
return
|
|
2168
|
+
return next;
|
|
2169
|
+
}
|
|
2170
|
+
function nextFocusForKey(key, modifiers, focus, rowCount, columnCount, pageSize, isSkippableRow = noRowsSkippable) {
|
|
2171
|
+
if (modifiers.altKey) {
|
|
2172
|
+
return null;
|
|
2173
|
+
}
|
|
2174
|
+
const { rowIndex, columnIndex } = focus;
|
|
2175
|
+
switch (key) {
|
|
2176
|
+
case "ArrowLeft":
|
|
2177
|
+
if (modifiers.ctrlKey) return null;
|
|
2178
|
+
return { rowIndex, columnIndex: columnIndex - 1 };
|
|
2179
|
+
case "ArrowRight":
|
|
2180
|
+
if (modifiers.ctrlKey) return null;
|
|
2181
|
+
return { rowIndex, columnIndex: columnIndex + 1 };
|
|
2182
|
+
case "ArrowUp":
|
|
2183
|
+
return {
|
|
2184
|
+
rowIndex: skipSkippableRows(
|
|
2185
|
+
rowIndex - 1,
|
|
2186
|
+
-1,
|
|
2187
|
+
rowCount,
|
|
2188
|
+
isSkippableRow,
|
|
2189
|
+
rowIndex
|
|
2190
|
+
),
|
|
2191
|
+
columnIndex
|
|
2192
|
+
};
|
|
2193
|
+
case "ArrowDown":
|
|
2194
|
+
return {
|
|
2195
|
+
rowIndex: skipSkippableRows(
|
|
2196
|
+
rowIndex + 1,
|
|
2197
|
+
1,
|
|
2198
|
+
rowCount,
|
|
2199
|
+
isSkippableRow,
|
|
2200
|
+
rowIndex
|
|
2201
|
+
),
|
|
2202
|
+
columnIndex
|
|
2203
|
+
};
|
|
2204
|
+
// Ctrl takes Home and End to the grid's ends rather than the row's, which
|
|
2205
|
+
// is the one place Ctrl is navigation rather than reorder.
|
|
2206
|
+
case "Home":
|
|
2207
|
+
return modifiers.ctrlKey ? { rowIndex: HEADER_ROW, columnIndex: 0 } : { rowIndex, columnIndex: 0 };
|
|
2208
|
+
case "End":
|
|
2209
|
+
return modifiers.ctrlKey ? {
|
|
2210
|
+
rowIndex: skipSkippableRows(
|
|
2211
|
+
rowCount - 1,
|
|
2212
|
+
-1,
|
|
2213
|
+
rowCount,
|
|
2214
|
+
isSkippableRow,
|
|
2215
|
+
rowIndex
|
|
2216
|
+
),
|
|
2217
|
+
columnIndex: columnCount - 1
|
|
2218
|
+
} : { rowIndex, columnIndex: columnCount - 1 };
|
|
2219
|
+
case "PageUp":
|
|
2220
|
+
return {
|
|
2221
|
+
rowIndex: skipSkippableRows(
|
|
2222
|
+
rowIndex - pageSize,
|
|
2223
|
+
-1,
|
|
2224
|
+
rowCount,
|
|
2225
|
+
isSkippableRow,
|
|
2226
|
+
rowIndex
|
|
2227
|
+
),
|
|
2228
|
+
columnIndex
|
|
2229
|
+
};
|
|
2230
|
+
case "PageDown":
|
|
2231
|
+
return {
|
|
2232
|
+
rowIndex: skipSkippableRows(
|
|
2233
|
+
rowIndex + pageSize,
|
|
2234
|
+
1,
|
|
2235
|
+
rowCount,
|
|
2236
|
+
isSkippableRow,
|
|
2237
|
+
rowIndex
|
|
2238
|
+
),
|
|
2239
|
+
columnIndex
|
|
2240
|
+
};
|
|
2241
|
+
default:
|
|
2242
|
+
return null;
|
|
926
2243
|
}
|
|
927
|
-
const page = rows.slice(firstUnit.start, lastUnit.end);
|
|
928
|
-
const renumbered = page.map(
|
|
929
|
-
(entry, index) => entry.rowIndex === index ? entry : { ...entry, rowIndex: index }
|
|
930
|
-
);
|
|
931
|
-
return { rows: renumbered, pageCount, pageIndex };
|
|
932
2244
|
}
|
|
933
2245
|
|
|
934
2246
|
// src/util/paginationWindow.ts
|
|
@@ -966,180 +2278,426 @@ function paginationWindow(currentPage, pageCount, options) {
|
|
|
966
2278
|
return entries;
|
|
967
2279
|
}
|
|
968
2280
|
|
|
969
|
-
// src/util/
|
|
970
|
-
|
|
971
|
-
|
|
2281
|
+
// src/util/format.ts
|
|
2282
|
+
var DATE_FIELDS = {
|
|
2283
|
+
year: "numeric",
|
|
2284
|
+
month: "numeric",
|
|
2285
|
+
day: "numeric"
|
|
2286
|
+
};
|
|
2287
|
+
var TIME_FIELDS = {
|
|
2288
|
+
hour: "numeric",
|
|
2289
|
+
minute: "numeric",
|
|
2290
|
+
second: "numeric"
|
|
2291
|
+
};
|
|
2292
|
+
var DATE_TIME_FIELDS = {
|
|
2293
|
+
...DATE_FIELDS,
|
|
2294
|
+
...TIME_FIELDS
|
|
2295
|
+
};
|
|
2296
|
+
var CURRENCY_DIGITS = {
|
|
2297
|
+
minimumFractionDigits: 2,
|
|
2298
|
+
maximumFractionDigits: 2
|
|
2299
|
+
};
|
|
2300
|
+
var NO_FORMAT = {};
|
|
2301
|
+
var formatters = /* @__PURE__ */ new WeakMap();
|
|
2302
|
+
function cached(format, key, create) {
|
|
2303
|
+
const owner = format ?? NO_FORMAT;
|
|
2304
|
+
let byKey = formatters.get(owner);
|
|
2305
|
+
if (byKey === void 0) {
|
|
2306
|
+
byKey = /* @__PURE__ */ new Map();
|
|
2307
|
+
formatters.set(owner, byKey);
|
|
2308
|
+
}
|
|
2309
|
+
const existing = byKey.get(key);
|
|
2310
|
+
if (existing !== void 0) {
|
|
2311
|
+
return existing;
|
|
2312
|
+
}
|
|
2313
|
+
const formatter = create();
|
|
2314
|
+
byKey.set(key, formatter);
|
|
2315
|
+
return formatter;
|
|
2316
|
+
}
|
|
2317
|
+
function localeKey(locale) {
|
|
2318
|
+
return typeof locale === "string" ? locale : locale?.join(",") ?? "";
|
|
2319
|
+
}
|
|
2320
|
+
function isNumericType(type) {
|
|
2321
|
+
return type === "number" || type === "decimal" || type === "currency" || type === "percent";
|
|
2322
|
+
}
|
|
2323
|
+
function numberOptions(type, format) {
|
|
2324
|
+
switch (type) {
|
|
2325
|
+
case "currency":
|
|
2326
|
+
return format?.currency === void 0 ? { ...CURRENCY_DIGITS, ...format } : { style: "currency", ...format };
|
|
2327
|
+
case "percent":
|
|
2328
|
+
return { style: "percent", ...format };
|
|
2329
|
+
default:
|
|
2330
|
+
return format ?? {};
|
|
2331
|
+
}
|
|
972
2332
|
}
|
|
973
|
-
function
|
|
974
|
-
|
|
2333
|
+
function dateOptions(type, format) {
|
|
2334
|
+
if (format !== void 0) {
|
|
2335
|
+
return format;
|
|
2336
|
+
}
|
|
2337
|
+
if (type === "date") return DATE_FIELDS;
|
|
2338
|
+
if (type === "time") return TIME_FIELDS;
|
|
2339
|
+
return DATE_TIME_FIELDS;
|
|
975
2340
|
}
|
|
976
|
-
function
|
|
977
|
-
|
|
978
|
-
|
|
2341
|
+
function formatNumber(value, type, format, locale) {
|
|
2342
|
+
const formatter = cached(
|
|
2343
|
+
format,
|
|
2344
|
+
`number|${type ?? ""}|${localeKey(locale)}`,
|
|
2345
|
+
() => new Intl.NumberFormat(
|
|
2346
|
+
locale,
|
|
2347
|
+
numberOptions(type, format)
|
|
2348
|
+
)
|
|
2349
|
+
);
|
|
2350
|
+
return formatter.format(value);
|
|
2351
|
+
}
|
|
2352
|
+
function formatDate(value, type, format, locale) {
|
|
2353
|
+
if (Number.isNaN(value.getTime())) {
|
|
2354
|
+
return String(value);
|
|
2355
|
+
}
|
|
2356
|
+
const formatter = cached(
|
|
2357
|
+
format,
|
|
2358
|
+
`date|${type ?? ""}|${localeKey(locale)}`,
|
|
2359
|
+
() => new Intl.DateTimeFormat(
|
|
2360
|
+
locale,
|
|
2361
|
+
dateOptions(type, format)
|
|
2362
|
+
)
|
|
2363
|
+
);
|
|
2364
|
+
return formatter.format(value);
|
|
2365
|
+
}
|
|
2366
|
+
function formatOther(value) {
|
|
2367
|
+
if (typeof value === "function") {
|
|
2368
|
+
return "(function)";
|
|
2369
|
+
}
|
|
2370
|
+
if (typeof value === "object" && value !== null) {
|
|
2371
|
+
try {
|
|
2372
|
+
return JSON.stringify(value);
|
|
2373
|
+
} catch {
|
|
2374
|
+
return Object.prototype.toString.call(value);
|
|
2375
|
+
}
|
|
979
2376
|
}
|
|
2377
|
+
return String(value);
|
|
2378
|
+
}
|
|
2379
|
+
function formatCellValue(value, column, locale, row, messages) {
|
|
2380
|
+
if (column.valueFormatter !== void 0) {
|
|
2381
|
+
return column.valueFormatter(value, row);
|
|
2382
|
+
}
|
|
2383
|
+
if (value === null || value === void 0) {
|
|
2384
|
+
return "";
|
|
2385
|
+
}
|
|
2386
|
+
if (typeof value === "boolean" && messages !== void 0) {
|
|
2387
|
+
return value ? messages.booleanTrue : messages.booleanFalse;
|
|
2388
|
+
}
|
|
2389
|
+
const { type, format } = column;
|
|
2390
|
+
const formatted = format !== void 0 || locale !== void 0;
|
|
980
2391
|
if (value instanceof Date) {
|
|
981
|
-
return
|
|
2392
|
+
return formatted ? formatDate(value, type, format, locale) : value.toLocaleString();
|
|
982
2393
|
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
case "symbol":
|
|
989
|
-
return `\0${typeof value}:${String(value)}`;
|
|
990
|
-
case "function":
|
|
991
|
-
return "\0function";
|
|
992
|
-
default:
|
|
993
|
-
return `\0object:${JSON.stringify(value)}`;
|
|
2394
|
+
if (formatted && (typeof value === "number" || typeof value === "bigint") && isNumericType(type)) {
|
|
2395
|
+
return formatNumber(value, type, format, locale);
|
|
2396
|
+
}
|
|
2397
|
+
if (typeof value === "string") {
|
|
2398
|
+
return value;
|
|
994
2399
|
}
|
|
2400
|
+
return formatOther(value);
|
|
995
2401
|
}
|
|
996
|
-
function
|
|
997
|
-
|
|
998
|
-
|
|
2402
|
+
function aggregateFormatColumn(value, spec, column) {
|
|
2403
|
+
const plain = {
|
|
2404
|
+
field: spec.columnId,
|
|
2405
|
+
type: "number"
|
|
2406
|
+
};
|
|
2407
|
+
if (column === void 0 || spec.fn === "count" || spec.fn === "countDistinct") {
|
|
2408
|
+
return plain;
|
|
999
2409
|
}
|
|
1000
|
-
const
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
total += toNumber(value);
|
|
1008
|
-
}
|
|
1009
|
-
return total;
|
|
1010
|
-
}
|
|
1011
|
-
case "avg": {
|
|
1012
|
-
const present = values.filter((value) => !isEmpty2(value));
|
|
1013
|
-
if (present.length === 0) return void 0;
|
|
1014
|
-
const total = present.reduce(
|
|
1015
|
-
(acc, value) => acc + toNumber(value),
|
|
1016
|
-
0
|
|
1017
|
-
);
|
|
1018
|
-
return total / present.length;
|
|
1019
|
-
}
|
|
1020
|
-
case "min":
|
|
1021
|
-
case "max": {
|
|
1022
|
-
const type = column?.column.type;
|
|
1023
|
-
let result;
|
|
1024
|
-
for (const value of values) {
|
|
1025
|
-
if (isEmpty2(value)) continue;
|
|
1026
|
-
if (result === void 0) {
|
|
1027
|
-
result = value;
|
|
1028
|
-
continue;
|
|
1029
|
-
}
|
|
1030
|
-
const comparison = compareValues(value, result, type);
|
|
1031
|
-
if (fn === "min" ? comparison < 0 : comparison > 0) {
|
|
1032
|
-
result = value;
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
return result;
|
|
1036
|
-
}
|
|
1037
|
-
case "countDistinct": {
|
|
1038
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1039
|
-
for (const value of values) {
|
|
1040
|
-
if (isEmpty2(value)) continue;
|
|
1041
|
-
seen.add(distinctKey(value));
|
|
1042
|
-
}
|
|
1043
|
-
return seen.size;
|
|
1044
|
-
}
|
|
2410
|
+
const numeric = typeof value === "number" || typeof value === "bigint";
|
|
2411
|
+
return column.valueFormatter === void 0 && numeric && !isNumericType(column.type) ? plain : column;
|
|
2412
|
+
}
|
|
2413
|
+
function formatAggregateValue(value, spec, column, locale) {
|
|
2414
|
+
const target = aggregateFormatColumn(value, spec, column);
|
|
2415
|
+
if (typeof value === "number" && target.valueFormatter === void 0 && target.format === void 0 && locale === void 0) {
|
|
2416
|
+
return value.toLocaleString();
|
|
1045
2417
|
}
|
|
2418
|
+
return formatCellValue(value, target, locale);
|
|
1046
2419
|
}
|
|
1047
|
-
|
|
1048
|
-
|
|
2420
|
+
|
|
2421
|
+
// src/util/filterEditor.ts
|
|
2422
|
+
function touchesColumn(entry, columnId) {
|
|
2423
|
+
return "combinator" in entry ? entry.entries.some((nested) => touchesColumn(nested, columnId)) : entry.columnId === columnId;
|
|
1049
2424
|
}
|
|
1050
|
-
function
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
2425
|
+
function isOperatorOn(entry, columnId) {
|
|
2426
|
+
return "operator" in entry && entry.columnId === columnId;
|
|
2427
|
+
}
|
|
2428
|
+
function isConditionOn(entry, columnId) {
|
|
2429
|
+
return isOperatorOn(entry, columnId) && entry.operator !== "in";
|
|
2430
|
+
}
|
|
2431
|
+
function valuesShape(entry, columnId) {
|
|
2432
|
+
const values = (candidate) => candidate !== void 0 && isOperatorOn(candidate, columnId) && candidate.operator === "in" && isScalarList(candidate.value) ? candidate.value : void 0;
|
|
2433
|
+
const blanks = (candidate) => candidate !== void 0 && isOperatorOn(candidate, columnId) && candidate.operator === "isEmpty";
|
|
2434
|
+
const alone = values(entry);
|
|
2435
|
+
if (alone !== void 0) {
|
|
2436
|
+
return { kind: "values", values: alone, includeBlanks: false };
|
|
1054
2437
|
}
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
const value = typeof spec.fn === "function" ? spec.fn(rows) : reduceBuiltIn(rows, spec.fn, byId.get(spec.columnId));
|
|
1058
|
-
results.set(keyOf(spec), value);
|
|
2438
|
+
if (!("combinator" in entry) || entry.combinator !== "or" || entry.entries.length !== 2) {
|
|
2439
|
+
return void 0;
|
|
1059
2440
|
}
|
|
1060
|
-
|
|
2441
|
+
const [first, second] = entry.entries;
|
|
2442
|
+
const listed = blanks(first) ? values(second) : values(first);
|
|
2443
|
+
return listed !== void 0 && (blanks(first) || blanks(second)) ? { kind: "values", values: listed, includeBlanks: true } : void 0;
|
|
1061
2444
|
}
|
|
1062
|
-
function
|
|
1063
|
-
const
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
2445
|
+
function conditionsShape(touching, columnId) {
|
|
2446
|
+
const [only] = touching;
|
|
2447
|
+
const grouped = touching.length === 1 && only !== void 0 && "combinator" in only;
|
|
2448
|
+
const entries = grouped ? only.entries : touching;
|
|
2449
|
+
const combinator = grouped ? only.combinator : "and";
|
|
2450
|
+
if (entries.length === 0 || entries.length > 2) {
|
|
2451
|
+
return void 0;
|
|
2452
|
+
}
|
|
2453
|
+
const conditions = entries.filter((entry) => isConditionOn(entry, columnId));
|
|
2454
|
+
return conditions.length === entries.length ? { kind: "conditions", conditions, combinator } : void 0;
|
|
1072
2455
|
}
|
|
1073
|
-
function
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
2456
|
+
function describeColumnFilter(filter, columnId) {
|
|
2457
|
+
const touching = filter.filter((entry) => touchesColumn(entry, columnId));
|
|
2458
|
+
const [only] = touching;
|
|
2459
|
+
if (only === void 0) {
|
|
2460
|
+
return { kind: "none" };
|
|
2461
|
+
}
|
|
2462
|
+
return (touching.length === 1 ? valuesShape(only, columnId) : void 0) ?? conditionsShape(touching, columnId) ?? { kind: "custom" };
|
|
2463
|
+
}
|
|
2464
|
+
function isOfferable(value) {
|
|
2465
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value instanceof Date;
|
|
2466
|
+
}
|
|
2467
|
+
function matchesSearch(label, search) {
|
|
2468
|
+
return label.toLowerCase().includes(search.toLowerCase());
|
|
2469
|
+
}
|
|
2470
|
+
function columnValueOptions(rows, dataColumns, filter, columnId, query = {}) {
|
|
2471
|
+
const column = dataColumns.find((entry) => entry.id === columnId)?.column;
|
|
2472
|
+
if (column === void 0) {
|
|
2473
|
+
return { options: [], total: 0, truncated: false, blanks: 0 };
|
|
2474
|
+
}
|
|
2475
|
+
const keep = compileFilter(
|
|
2476
|
+
filter.filter((entry) => !touchesColumn(entry, columnId)),
|
|
2477
|
+
dataColumns
|
|
2478
|
+
);
|
|
2479
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
2480
|
+
let blanks = 0;
|
|
2481
|
+
for (const row of rows) {
|
|
2482
|
+
if (keep !== void 0 && !keep(row)) {
|
|
1079
2483
|
continue;
|
|
1080
2484
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
2485
|
+
const value = accessDotted(row, column.field);
|
|
2486
|
+
if (isEmptyCell(value)) {
|
|
2487
|
+
blanks++;
|
|
2488
|
+
} else if (isOfferable(value)) {
|
|
2489
|
+
const key = bucketKey(value);
|
|
2490
|
+
const bucket = buckets.get(key);
|
|
2491
|
+
if (bucket === void 0) {
|
|
2492
|
+
buckets.set(key, { value, row, count: 1 });
|
|
2493
|
+
} else {
|
|
2494
|
+
bucket.count++;
|
|
2495
|
+
}
|
|
1088
2496
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
2497
|
+
}
|
|
2498
|
+
const { search = "", limit, locale } = query;
|
|
2499
|
+
const options = [...buckets.values()].sort((a, b) => compareValues(a.value, b.value, column.type)).map(({ value, row, count }) => ({
|
|
2500
|
+
value,
|
|
2501
|
+
label: formatCellValue(value, column, locale, row),
|
|
2502
|
+
count
|
|
2503
|
+
})).filter((option) => matchesSearch(option.label, search));
|
|
2504
|
+
const shown = limit === void 0 ? options : options.slice(0, limit);
|
|
2505
|
+
return {
|
|
2506
|
+
options: shown,
|
|
2507
|
+
total: options.length,
|
|
2508
|
+
truncated: shown.length < options.length,
|
|
2509
|
+
blanks
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
function everyOption(options) {
|
|
2513
|
+
return new Map(
|
|
2514
|
+
options.map((option) => [bucketKey(option.value), option.value])
|
|
2515
|
+
);
|
|
2516
|
+
}
|
|
2517
|
+
function initialFilterEditorDraft(shape, values) {
|
|
2518
|
+
const draft = {
|
|
2519
|
+
mode: "values",
|
|
2520
|
+
options: values.options,
|
|
2521
|
+
blanks: values.blanks,
|
|
2522
|
+
search: "",
|
|
2523
|
+
checked: everyOption(values.options),
|
|
2524
|
+
includeBlanks: values.blanks > 0,
|
|
2525
|
+
conditions: [],
|
|
2526
|
+
combinator: "and"
|
|
2527
|
+
};
|
|
2528
|
+
switch (shape.kind) {
|
|
2529
|
+
case "values":
|
|
2530
|
+
return {
|
|
2531
|
+
...draft,
|
|
2532
|
+
checked: new Map(
|
|
2533
|
+
shape.values.filter((value) => !isEmptyCell(value)).map((value) => [bucketKey(value), value])
|
|
2534
|
+
),
|
|
2535
|
+
includeBlanks: shape.includeBlanks
|
|
1113
2536
|
};
|
|
1114
|
-
|
|
2537
|
+
case "conditions":
|
|
2538
|
+
return {
|
|
2539
|
+
...draft,
|
|
2540
|
+
mode: "conditions",
|
|
2541
|
+
conditions: shape.conditions,
|
|
2542
|
+
combinator: shape.combinator
|
|
2543
|
+
};
|
|
2544
|
+
case "none":
|
|
2545
|
+
case "custom":
|
|
2546
|
+
return draft;
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
function visibleFilterOptions(draft) {
|
|
2550
|
+
return draft.search === "" ? draft.options : draft.options.filter(
|
|
2551
|
+
(option) => matchesSearch(option.label, draft.search)
|
|
2552
|
+
);
|
|
2553
|
+
}
|
|
2554
|
+
function selectAllCoversBlanks(draft) {
|
|
2555
|
+
return draft.search === "" && draft.blanks > 0;
|
|
2556
|
+
}
|
|
2557
|
+
function selectAllState(draft) {
|
|
2558
|
+
const states = visibleFilterOptions(draft).map(
|
|
2559
|
+
(option) => draft.checked.has(bucketKey(option.value))
|
|
2560
|
+
);
|
|
2561
|
+
if (selectAllCoversBlanks(draft)) {
|
|
2562
|
+
states.push(draft.includeBlanks);
|
|
2563
|
+
}
|
|
2564
|
+
if (states.length > 0 && states.every(Boolean)) {
|
|
2565
|
+
return "checked";
|
|
2566
|
+
}
|
|
2567
|
+
return states.some(Boolean) ? "mixed" : "unchecked";
|
|
2568
|
+
}
|
|
2569
|
+
function toggleAll(draft) {
|
|
2570
|
+
const check = selectAllState(draft) !== "checked";
|
|
2571
|
+
const checked = new Map(draft.checked);
|
|
2572
|
+
for (const option of visibleFilterOptions(draft)) {
|
|
2573
|
+
const key = bucketKey(option.value);
|
|
2574
|
+
if (check) {
|
|
2575
|
+
checked.set(key, option.value);
|
|
2576
|
+
} else {
|
|
2577
|
+
checked.delete(key);
|
|
1115
2578
|
}
|
|
1116
2579
|
}
|
|
1117
|
-
return
|
|
2580
|
+
return {
|
|
2581
|
+
...draft,
|
|
2582
|
+
mode: "values",
|
|
2583
|
+
checked,
|
|
2584
|
+
includeBlanks: selectAllCoversBlanks(draft) ? check : draft.includeBlanks
|
|
2585
|
+
};
|
|
1118
2586
|
}
|
|
1119
|
-
function
|
|
1120
|
-
|
|
1121
|
-
|
|
2587
|
+
function filterEditorReducer(draft, action) {
|
|
2588
|
+
switch (action.type) {
|
|
2589
|
+
case "search":
|
|
2590
|
+
return { ...draft, search: action.search };
|
|
2591
|
+
case "toggleValue": {
|
|
2592
|
+
const key = bucketKey(action.value);
|
|
2593
|
+
const checked = new Map(draft.checked);
|
|
2594
|
+
if (checked.has(key)) {
|
|
2595
|
+
checked.delete(key);
|
|
2596
|
+
} else {
|
|
2597
|
+
checked.set(key, action.value);
|
|
2598
|
+
}
|
|
2599
|
+
return { ...draft, mode: "values", checked };
|
|
2600
|
+
}
|
|
2601
|
+
case "toggleAll":
|
|
2602
|
+
return toggleAll(draft);
|
|
2603
|
+
case "setIncludeBlanks":
|
|
2604
|
+
return { ...draft, mode: "values", includeBlanks: action.includeBlanks };
|
|
2605
|
+
case "setConditions":
|
|
2606
|
+
return {
|
|
2607
|
+
...draft,
|
|
2608
|
+
mode: "conditions",
|
|
2609
|
+
conditions: action.conditions,
|
|
2610
|
+
combinator: action.combinator ?? draft.combinator
|
|
2611
|
+
};
|
|
2612
|
+
case "clear":
|
|
2613
|
+
return {
|
|
2614
|
+
...draft,
|
|
2615
|
+
search: "",
|
|
2616
|
+
checked: everyOption(draft.options),
|
|
2617
|
+
includeBlanks: draft.blanks > 0,
|
|
2618
|
+
conditions: []
|
|
2619
|
+
};
|
|
1122
2620
|
}
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
2621
|
+
}
|
|
2622
|
+
function checksEverything(draft) {
|
|
2623
|
+
return draft.options.every(
|
|
2624
|
+
(option) => draft.checked.has(bucketKey(option.value))
|
|
2625
|
+
) && (draft.includeBlanks || draft.blanks === 0);
|
|
2626
|
+
}
|
|
2627
|
+
function draftEntries(draft, columnId) {
|
|
2628
|
+
if (draft.mode === "conditions") {
|
|
2629
|
+
const conditions = draft.conditions.map((condition) => ({
|
|
2630
|
+
...condition,
|
|
2631
|
+
columnId
|
|
2632
|
+
}));
|
|
2633
|
+
return conditions.length > 1 ? [{ combinator: draft.combinator, entries: conditions }] : conditions;
|
|
2634
|
+
}
|
|
2635
|
+
if (checksEverything(draft)) {
|
|
2636
|
+
return [];
|
|
2637
|
+
}
|
|
2638
|
+
const picked = {
|
|
2639
|
+
columnId,
|
|
2640
|
+
operator: "in",
|
|
2641
|
+
value: [...draft.checked.values()]
|
|
2642
|
+
};
|
|
2643
|
+
return draft.includeBlanks ? [
|
|
2644
|
+
{
|
|
2645
|
+
combinator: "or",
|
|
2646
|
+
entries: [picked, { columnId, operator: "isEmpty" }]
|
|
1140
2647
|
}
|
|
1141
|
-
|
|
1142
|
-
|
|
2648
|
+
] : [picked];
|
|
2649
|
+
}
|
|
2650
|
+
function draftToFilter(draft, columnId, current) {
|
|
2651
|
+
const replacement = draftEntries(draft, columnId);
|
|
2652
|
+
const first = current.findIndex((entry) => touchesColumn(entry, columnId));
|
|
2653
|
+
if (first === -1) {
|
|
2654
|
+
return replacement.length === 0 ? current : [...current, ...replacement];
|
|
2655
|
+
}
|
|
2656
|
+
const kept = current.filter((entry) => !touchesColumn(entry, columnId));
|
|
2657
|
+
return [...kept.slice(0, first), ...replacement, ...kept.slice(first)];
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
// src/messages.ts
|
|
2661
|
+
function selectedCount(count, target) {
|
|
2662
|
+
const noun = target === "rows" ? "row" : "column";
|
|
2663
|
+
if (count === 0) {
|
|
2664
|
+
return `No ${noun}s selected`;
|
|
2665
|
+
}
|
|
2666
|
+
return count === 1 ? `1 ${noun} selected` : `${String(count)} ${noun}s selected`;
|
|
2667
|
+
}
|
|
2668
|
+
var defaultMessages = {
|
|
2669
|
+
pagerLabel: "Pagination",
|
|
2670
|
+
previousPage: "Previous",
|
|
2671
|
+
nextPage: "Next",
|
|
2672
|
+
pageSizeLabel: "Rows per page",
|
|
2673
|
+
pageButtonLabel: (page) => `Page ${String(page)}`,
|
|
2674
|
+
pageStatus: (page, pageCount) => `Page ${String(page)} of ${String(pageCount)}`,
|
|
2675
|
+
loadingMore: "Loading more\u2026",
|
|
2676
|
+
booleanTrue: "true",
|
|
2677
|
+
booleanFalse: "false",
|
|
2678
|
+
blankGroupValue: "(blank)",
|
|
2679
|
+
groupByBarLabel: "Grouped by",
|
|
2680
|
+
groupByBarPlaceholder: "Drag a column here to group by it",
|
|
2681
|
+
groupByChipLabel: (columnName, level, levelCount) => levelCount > 1 ? `${columnName}, level ${String(level)} of ${String(levelCount)}` : columnName,
|
|
2682
|
+
removeGroupBy: (columnName) => `Stop grouping by ${columnName}`,
|
|
2683
|
+
columnResized: (columnName, width) => `${columnName}, ${String(width)} pixels wide`,
|
|
2684
|
+
columnMoved: (columnName, position, columnCount) => `${columnName}, column ${String(position)} of ${String(columnCount)}`,
|
|
2685
|
+
columnSorted: (columnName, direction, key, keyCount) => {
|
|
2686
|
+
const sorted = `${columnName} sorted ${direction === "asc" ? "ascending" : "descending"}`;
|
|
2687
|
+
return keyCount > 1 ? `${sorted}, key ${String(key)} of ${String(keyCount)}` : sorted;
|
|
2688
|
+
},
|
|
2689
|
+
sortCleared: (columnName) => `${columnName}, sort cleared`,
|
|
2690
|
+
groupedBy: (columnName, level, levelCount) => levelCount > 1 ? `Grouped by ${columnName}, level ${String(level)} of ${String(levelCount)}` : `Grouped by ${columnName}`,
|
|
2691
|
+
groupingRemoved: (columnName) => `${columnName}, grouping removed`,
|
|
2692
|
+
groupExpanded: "Group expanded",
|
|
2693
|
+
groupCollapsed: "Group collapsed",
|
|
2694
|
+
allGroupsExpanded: "All groups expanded",
|
|
2695
|
+
allGroupsCollapsed: "All groups collapsed",
|
|
2696
|
+
selectedCount,
|
|
2697
|
+
cellSelected: (columnName, rowNumber) => `${columnName}, row ${String(rowNumber)}, selected`
|
|
2698
|
+
};
|
|
2699
|
+
function resolveMessages(messages) {
|
|
2700
|
+
return messages === void 0 ? defaultMessages : { ...defaultMessages, ...messages };
|
|
1143
2701
|
}
|
|
1144
2702
|
|
|
1145
2703
|
// src/util/virtualization.ts
|
|
@@ -1190,6 +2748,7 @@ export {
|
|
|
1190
2748
|
alignmentForType,
|
|
1191
2749
|
applyColumnOrder,
|
|
1192
2750
|
applyColumnResize,
|
|
2751
|
+
applyColumnVisibility,
|
|
1193
2752
|
applySelectionIntent,
|
|
1194
2753
|
beginColumnResize,
|
|
1195
2754
|
buildKeyShortcuts,
|
|
@@ -1198,18 +2757,29 @@ export {
|
|
|
1198
2757
|
clearAllFilters,
|
|
1199
2758
|
clearSelection,
|
|
1200
2759
|
collapseAllGroups,
|
|
2760
|
+
columnValueOptions,
|
|
1201
2761
|
compareValues,
|
|
1202
2762
|
computeAggregates,
|
|
2763
|
+
createGridController,
|
|
2764
|
+
createGridViewResolver,
|
|
2765
|
+
defaultMessages,
|
|
1203
2766
|
defineColumnsFromRows,
|
|
2767
|
+
describeColumnFilter,
|
|
1204
2768
|
diffSelection,
|
|
2769
|
+
draftToFilter,
|
|
1205
2770
|
expandAllGroups,
|
|
2771
|
+
filterEditorReducer,
|
|
1206
2772
|
filterQueryFor,
|
|
1207
2773
|
filterRows,
|
|
1208
2774
|
fitColumnsToWidth,
|
|
2775
|
+
formatAggregateValue,
|
|
2776
|
+
formatCellValue,
|
|
1209
2777
|
getColumnId,
|
|
1210
2778
|
groupRowId,
|
|
1211
2779
|
groupRows,
|
|
2780
|
+
initialFilterEditorDraft,
|
|
1212
2781
|
intentOf,
|
|
2782
|
+
isColumnVisible,
|
|
1213
2783
|
isSameCell,
|
|
1214
2784
|
matchesQuery,
|
|
1215
2785
|
moveColumnBefore,
|
|
@@ -1221,20 +2791,27 @@ export {
|
|
|
1221
2791
|
paginationWindow,
|
|
1222
2792
|
resolveCell,
|
|
1223
2793
|
resolveColumnConstraints,
|
|
2794
|
+
resolveColumnHeaderText,
|
|
1224
2795
|
resolveColumnLabel,
|
|
1225
2796
|
resolveColumnWidths,
|
|
1226
2797
|
resolveColumns,
|
|
2798
|
+
resolveDataColumns,
|
|
1227
2799
|
resolveDropBefore,
|
|
2800
|
+
resolveGridView,
|
|
1228
2801
|
resolveKeyboardDropTarget,
|
|
2802
|
+
resolveMessages,
|
|
1229
2803
|
resolveRowId,
|
|
1230
2804
|
resolveRows,
|
|
1231
2805
|
resolveShownRows,
|
|
1232
2806
|
revertColumnSize,
|
|
1233
2807
|
selectAll,
|
|
2808
|
+
selectAllState,
|
|
1234
2809
|
selectCell,
|
|
1235
2810
|
selectOnly,
|
|
1236
2811
|
selectRange,
|
|
2812
|
+
serializeGridState,
|
|
1237
2813
|
setColumnFilter,
|
|
2814
|
+
setColumnVisibility,
|
|
1238
2815
|
sizeColumnToContent,
|
|
1239
2816
|
sortDirectionFor,
|
|
1240
2817
|
sortPriorityFor,
|
|
@@ -1244,6 +2821,7 @@ export {
|
|
|
1244
2821
|
toggleGroupExpansion,
|
|
1245
2822
|
toggleSelection,
|
|
1246
2823
|
totalColumnWidth,
|
|
2824
|
+
visibleFilterOptions,
|
|
1247
2825
|
visibleRange,
|
|
1248
2826
|
withGroupAggregates
|
|
1249
2827
|
};
|