@gridkitjs/core 0.12.1 → 0.14.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/README.md +1 -1
- package/dist/index.d.ts +2781 -1771
- package/dist/index.js +1699 -527
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -91,6 +91,9 @@ function buildKeyShortcuts(capabilities) {
|
|
|
91
91
|
// Down rather than reusing Up: it reads as "drill into groups", and Up is
|
|
92
92
|
// already sort's own mnemonic on the same header.
|
|
93
93
|
capabilities.groupable ? "Alt+ArrowDown" : "",
|
|
94
|
+
// Excel's own key for its filter dropdown is Alt+ArrowDown, which
|
|
95
|
+
// grouping already holds here; Shift sets the filter apart from it.
|
|
96
|
+
capabilities.filterable === true ? "Alt+Shift+ArrowDown" : "",
|
|
94
97
|
// The ContextMenu key needs no mention: it says what it does on its face.
|
|
95
98
|
capabilities.contextMenu === true ? "Shift+F10" : ""
|
|
96
99
|
].filter(Boolean).join(" ");
|
|
@@ -2185,6 +2188,1304 @@ function createCommandContext({
|
|
|
2185
2188
|
};
|
|
2186
2189
|
}
|
|
2187
2190
|
|
|
2191
|
+
// src/util/format.ts
|
|
2192
|
+
var DATE_FIELDS = {
|
|
2193
|
+
year: "numeric",
|
|
2194
|
+
month: "numeric",
|
|
2195
|
+
day: "numeric"
|
|
2196
|
+
};
|
|
2197
|
+
var TIME_FIELDS = {
|
|
2198
|
+
hour: "numeric",
|
|
2199
|
+
minute: "numeric",
|
|
2200
|
+
second: "numeric"
|
|
2201
|
+
};
|
|
2202
|
+
var DATE_TIME_FIELDS = {
|
|
2203
|
+
...DATE_FIELDS,
|
|
2204
|
+
...TIME_FIELDS
|
|
2205
|
+
};
|
|
2206
|
+
var CURRENCY_DIGITS = {
|
|
2207
|
+
minimumFractionDigits: 2,
|
|
2208
|
+
maximumFractionDigits: 2
|
|
2209
|
+
};
|
|
2210
|
+
var NO_FORMAT = {};
|
|
2211
|
+
var formatters = /* @__PURE__ */ new WeakMap();
|
|
2212
|
+
function cached(format, key, create) {
|
|
2213
|
+
const owner = format ?? NO_FORMAT;
|
|
2214
|
+
let byKey = formatters.get(owner);
|
|
2215
|
+
if (byKey === void 0) {
|
|
2216
|
+
byKey = /* @__PURE__ */ new Map();
|
|
2217
|
+
formatters.set(owner, byKey);
|
|
2218
|
+
}
|
|
2219
|
+
const existing = byKey.get(key);
|
|
2220
|
+
if (existing !== void 0) {
|
|
2221
|
+
return existing;
|
|
2222
|
+
}
|
|
2223
|
+
const formatter = create();
|
|
2224
|
+
byKey.set(key, formatter);
|
|
2225
|
+
return formatter;
|
|
2226
|
+
}
|
|
2227
|
+
function localeKey(locale) {
|
|
2228
|
+
return typeof locale === "string" ? locale : locale?.join(",") ?? "";
|
|
2229
|
+
}
|
|
2230
|
+
function isNumericType(type) {
|
|
2231
|
+
return type === "number" || type === "decimal" || type === "currency" || type === "percent";
|
|
2232
|
+
}
|
|
2233
|
+
function numberOptions(type, format) {
|
|
2234
|
+
switch (type) {
|
|
2235
|
+
case "currency":
|
|
2236
|
+
return format?.currency === void 0 ? { ...CURRENCY_DIGITS, ...format } : { style: "currency", ...format };
|
|
2237
|
+
case "percent":
|
|
2238
|
+
return { style: "percent", ...format };
|
|
2239
|
+
default:
|
|
2240
|
+
return format ?? {};
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
function dateOptions(type, format) {
|
|
2244
|
+
if (format !== void 0) {
|
|
2245
|
+
return format;
|
|
2246
|
+
}
|
|
2247
|
+
if (type === "date") return DATE_FIELDS;
|
|
2248
|
+
if (type === "time") return TIME_FIELDS;
|
|
2249
|
+
return DATE_TIME_FIELDS;
|
|
2250
|
+
}
|
|
2251
|
+
function formatNumber(value, type, format, locale) {
|
|
2252
|
+
const formatter = cached(
|
|
2253
|
+
format,
|
|
2254
|
+
`number|${type ?? ""}|${localeKey(locale)}`,
|
|
2255
|
+
() => new Intl.NumberFormat(
|
|
2256
|
+
locale,
|
|
2257
|
+
numberOptions(type, format)
|
|
2258
|
+
)
|
|
2259
|
+
);
|
|
2260
|
+
return formatter.format(value);
|
|
2261
|
+
}
|
|
2262
|
+
function formatDate(value, type, format, locale) {
|
|
2263
|
+
if (Number.isNaN(value.getTime())) {
|
|
2264
|
+
return String(value);
|
|
2265
|
+
}
|
|
2266
|
+
const formatter = cached(
|
|
2267
|
+
format,
|
|
2268
|
+
`date|${type ?? ""}|${localeKey(locale)}`,
|
|
2269
|
+
() => new Intl.DateTimeFormat(
|
|
2270
|
+
locale,
|
|
2271
|
+
dateOptions(type, format)
|
|
2272
|
+
)
|
|
2273
|
+
);
|
|
2274
|
+
return formatter.format(value);
|
|
2275
|
+
}
|
|
2276
|
+
function formatOther(value) {
|
|
2277
|
+
if (typeof value === "function") {
|
|
2278
|
+
return "(function)";
|
|
2279
|
+
}
|
|
2280
|
+
if (typeof value === "object" && value !== null) {
|
|
2281
|
+
try {
|
|
2282
|
+
return JSON.stringify(value);
|
|
2283
|
+
} catch {
|
|
2284
|
+
return Object.prototype.toString.call(value);
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
return String(value);
|
|
2288
|
+
}
|
|
2289
|
+
function formatCellValue(value, column, locale, row, messages) {
|
|
2290
|
+
if (column.valueFormatter !== void 0) {
|
|
2291
|
+
return column.valueFormatter(value, row);
|
|
2292
|
+
}
|
|
2293
|
+
if (value === null || value === void 0) {
|
|
2294
|
+
return "";
|
|
2295
|
+
}
|
|
2296
|
+
if (typeof value === "boolean" && messages !== void 0) {
|
|
2297
|
+
return value ? messages.booleanTrue : messages.booleanFalse;
|
|
2298
|
+
}
|
|
2299
|
+
const { type, format } = column;
|
|
2300
|
+
const formatted = format !== void 0 || locale !== void 0;
|
|
2301
|
+
if (value instanceof Date) {
|
|
2302
|
+
return formatted ? formatDate(value, type, format, locale) : value.toLocaleString();
|
|
2303
|
+
}
|
|
2304
|
+
if (formatted && (typeof value === "number" || typeof value === "bigint") && isNumericType(type)) {
|
|
2305
|
+
return formatNumber(value, type, format, locale);
|
|
2306
|
+
}
|
|
2307
|
+
if (typeof value === "string") {
|
|
2308
|
+
return value;
|
|
2309
|
+
}
|
|
2310
|
+
return formatOther(value);
|
|
2311
|
+
}
|
|
2312
|
+
function aggregateFormatColumn(value, spec, column) {
|
|
2313
|
+
const plain = {
|
|
2314
|
+
field: spec.columnId,
|
|
2315
|
+
type: "number"
|
|
2316
|
+
};
|
|
2317
|
+
if (column === void 0 || spec.fn === "count" || spec.fn === "countDistinct") {
|
|
2318
|
+
return plain;
|
|
2319
|
+
}
|
|
2320
|
+
const numeric = typeof value === "number" || typeof value === "bigint";
|
|
2321
|
+
return column.valueFormatter === void 0 && numeric && !isNumericType(column.type) ? plain : column;
|
|
2322
|
+
}
|
|
2323
|
+
function formatAggregateValue(value, spec, column, locale) {
|
|
2324
|
+
const target = aggregateFormatColumn(value, spec, column);
|
|
2325
|
+
if (typeof value === "number" && target.valueFormatter === void 0 && target.format === void 0 && locale === void 0) {
|
|
2326
|
+
return value.toLocaleString();
|
|
2327
|
+
}
|
|
2328
|
+
return formatCellValue(value, target, locale);
|
|
2329
|
+
}
|
|
2330
|
+
function formatGroupValue(value, column, locale, messages) {
|
|
2331
|
+
return value === null || value === void 0 ? messages.blankGroupValue : formatCellValue(value, column, locale, void 0, messages);
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
// src/export/buildExportTable.ts
|
|
2335
|
+
var EMPTY_CELL = { value: null, text: "" };
|
|
2336
|
+
function isDataRow(entry) {
|
|
2337
|
+
return !("kind" in entry);
|
|
2338
|
+
}
|
|
2339
|
+
function pickColumns(view, selection) {
|
|
2340
|
+
let picked;
|
|
2341
|
+
if (selection === "visible") {
|
|
2342
|
+
picked = view.columns;
|
|
2343
|
+
} else if (selection === "all") {
|
|
2344
|
+
picked = view.dataColumns;
|
|
2345
|
+
} else {
|
|
2346
|
+
const byId = new Map(view.dataColumns.map((entry) => [entry.id, entry]));
|
|
2347
|
+
picked = [...new Set(selection)].flatMap((id) => byId.get(id) ?? []);
|
|
2348
|
+
}
|
|
2349
|
+
return picked.filter((entry) => entry.column.exportable !== false);
|
|
2350
|
+
}
|
|
2351
|
+
function describeColumns(picked, source) {
|
|
2352
|
+
const shown = new Map(source.view.columns.map((entry) => [entry.id, entry]));
|
|
2353
|
+
const resolved = resolveColumnWidths(
|
|
2354
|
+
picked.map((entry) => entry.column),
|
|
2355
|
+
source.state.columnSizing,
|
|
2356
|
+
{ sizes: source.options.columnSizeDefaults }
|
|
2357
|
+
);
|
|
2358
|
+
return resolved.map((entry) => {
|
|
2359
|
+
const rendered = shown.get(entry.id) ?? entry;
|
|
2360
|
+
return {
|
|
2361
|
+
id: rendered.id,
|
|
2362
|
+
header: resolveColumnHeaderText(rendered.column),
|
|
2363
|
+
type: rendered.column.type ?? "string",
|
|
2364
|
+
format: rendered.column.format,
|
|
2365
|
+
alignment: rendered.alignment,
|
|
2366
|
+
width: rendered.width
|
|
2367
|
+
};
|
|
2368
|
+
});
|
|
2369
|
+
}
|
|
2370
|
+
function scopedRows(source, scope) {
|
|
2371
|
+
const { view, state } = source;
|
|
2372
|
+
switch (scope) {
|
|
2373
|
+
case "all":
|
|
2374
|
+
return view.rows;
|
|
2375
|
+
case "page":
|
|
2376
|
+
return view.displayDataRows;
|
|
2377
|
+
case "selection": {
|
|
2378
|
+
const selected = new Set(state.rowSelection);
|
|
2379
|
+
return view.rows.filter((entry) => selected.has(entry.rowId));
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
function typedValue(value, text) {
|
|
2384
|
+
if (value === null || value === void 0) {
|
|
2385
|
+
return null;
|
|
2386
|
+
}
|
|
2387
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value instanceof Date ? value : text;
|
|
2388
|
+
}
|
|
2389
|
+
function dataCell(row, column, context) {
|
|
2390
|
+
const raw = accessDotted(row, column.field);
|
|
2391
|
+
const text = formatCellValue(
|
|
2392
|
+
raw,
|
|
2393
|
+
column,
|
|
2394
|
+
context.locale,
|
|
2395
|
+
row,
|
|
2396
|
+
context.messages
|
|
2397
|
+
);
|
|
2398
|
+
return {
|
|
2399
|
+
value: column.exportValue === void 0 ? typedValue(raw, text) : column.exportValue(raw, row),
|
|
2400
|
+
text
|
|
2401
|
+
};
|
|
2402
|
+
}
|
|
2403
|
+
function aggregateCell(results, specs, column, locale) {
|
|
2404
|
+
const parts = specs.flatMap((spec) => {
|
|
2405
|
+
const value = results.get(spec.id ?? spec.columnId);
|
|
2406
|
+
return value === null || value === void 0 ? [] : [{ value, text: formatAggregateValue(value, spec, column, locale) }];
|
|
2407
|
+
});
|
|
2408
|
+
const [only] = parts;
|
|
2409
|
+
if (only === void 0) {
|
|
2410
|
+
return EMPTY_CELL;
|
|
2411
|
+
}
|
|
2412
|
+
if (parts.length === 1) {
|
|
2413
|
+
return { value: typedValue(only.value, only.text), text: only.text };
|
|
2414
|
+
}
|
|
2415
|
+
const text = parts.map((part) => part.text).join(", ");
|
|
2416
|
+
return { value: text, text };
|
|
2417
|
+
}
|
|
2418
|
+
function aggregateCells(results, context) {
|
|
2419
|
+
return context.columns.map((entry) => {
|
|
2420
|
+
const specs = context.specsByColumn.get(entry.id);
|
|
2421
|
+
return specs === void 0 ? EMPTY_CELL : aggregateCell(results, specs, entry.column, context.locale);
|
|
2422
|
+
});
|
|
2423
|
+
}
|
|
2424
|
+
function groupLabel(entry, source) {
|
|
2425
|
+
const column = source.view.dataColumns.find(
|
|
2426
|
+
(candidate) => candidate.id === entry.columnId
|
|
2427
|
+
)?.column ?? { field: entry.columnId };
|
|
2428
|
+
const value = formatGroupValue(
|
|
2429
|
+
entry.value,
|
|
2430
|
+
column,
|
|
2431
|
+
source.options.locale,
|
|
2432
|
+
source.messages
|
|
2433
|
+
);
|
|
2434
|
+
return `${resolveColumnHeaderText(column)}: ${value}`;
|
|
2435
|
+
}
|
|
2436
|
+
function toExportRow(entry, source, context) {
|
|
2437
|
+
if (isDataRow(entry)) {
|
|
2438
|
+
return {
|
|
2439
|
+
kind: "data",
|
|
2440
|
+
rowId: entry.rowId,
|
|
2441
|
+
cells: context.columns.map(
|
|
2442
|
+
(column) => dataCell(entry.row, column.column, context)
|
|
2443
|
+
)
|
|
2444
|
+
};
|
|
2445
|
+
}
|
|
2446
|
+
if (entry.kind === "group") {
|
|
2447
|
+
return {
|
|
2448
|
+
kind: "group",
|
|
2449
|
+
level: entry.level,
|
|
2450
|
+
groupId: entry.groupId,
|
|
2451
|
+
label: groupLabel(entry, source),
|
|
2452
|
+
count: entry.count,
|
|
2453
|
+
cells: context.display === "inline" ? aggregateCells(entry.aggregates, context) : context.columns.map(() => EMPTY_CELL)
|
|
2454
|
+
};
|
|
2455
|
+
}
|
|
2456
|
+
return {
|
|
2457
|
+
kind: "groupSummary",
|
|
2458
|
+
level: entry.level,
|
|
2459
|
+
cells: aggregateCells(entry.aggregates, context)
|
|
2460
|
+
};
|
|
2461
|
+
}
|
|
2462
|
+
function specsByColumnOf(specs) {
|
|
2463
|
+
const byColumn = /* @__PURE__ */ new Map();
|
|
2464
|
+
for (const spec of specs) {
|
|
2465
|
+
const owned = byColumn.get(spec.columnId);
|
|
2466
|
+
if (owned === void 0) {
|
|
2467
|
+
byColumn.set(spec.columnId, [spec]);
|
|
2468
|
+
} else {
|
|
2469
|
+
owned.push(spec);
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
return byColumn;
|
|
2473
|
+
}
|
|
2474
|
+
function buildExportTable(source, options = {}) {
|
|
2475
|
+
const { view, state } = source;
|
|
2476
|
+
const specs = options.includeAggregates ?? true ? source.options.aggregates ?? [] : [];
|
|
2477
|
+
const columns = pickColumns(view, options.columns ?? "visible");
|
|
2478
|
+
const context = {
|
|
2479
|
+
columns,
|
|
2480
|
+
specsByColumn: specsByColumnOf(specs),
|
|
2481
|
+
display: source.options.groupAggregateDisplay ?? "inline",
|
|
2482
|
+
locale: source.options.locale,
|
|
2483
|
+
messages: source.messages
|
|
2484
|
+
};
|
|
2485
|
+
const rows = scopedRows(source, options.scope ?? "all");
|
|
2486
|
+
const grouped = groupRows(rows, state.groupBy, [], view.dataColumns);
|
|
2487
|
+
const displayRows = options.includeGroups ?? true ? withGroupAggregates(
|
|
2488
|
+
grouped,
|
|
2489
|
+
rows,
|
|
2490
|
+
state.groupBy,
|
|
2491
|
+
specs,
|
|
2492
|
+
view.dataColumns,
|
|
2493
|
+
context.display
|
|
2494
|
+
) : grouped.filter(isDataRow);
|
|
2495
|
+
let footer = null;
|
|
2496
|
+
if (specs.length > 0) {
|
|
2497
|
+
const totals = rows === view.rows ? view.grandTotal : computeAggregates(
|
|
2498
|
+
rows.map((entry) => entry.row),
|
|
2499
|
+
specs,
|
|
2500
|
+
view.dataColumns
|
|
2501
|
+
);
|
|
2502
|
+
footer = { kind: "total", cells: aggregateCells(totals, context) };
|
|
2503
|
+
}
|
|
2504
|
+
return {
|
|
2505
|
+
columns: describeColumns(columns, source),
|
|
2506
|
+
header: options.includeHeader ?? true,
|
|
2507
|
+
rows: displayRows.map((entry) => toExportRow(entry, source, context)),
|
|
2508
|
+
footer
|
|
2509
|
+
};
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2512
|
+
// src/export/htmlTable.ts
|
|
2513
|
+
var ENTITIES = {
|
|
2514
|
+
"&": "&",
|
|
2515
|
+
"<": "<",
|
|
2516
|
+
">": ">",
|
|
2517
|
+
'"': """,
|
|
2518
|
+
"'": "'"
|
|
2519
|
+
};
|
|
2520
|
+
function escapeHtml(text) {
|
|
2521
|
+
return text.replace(/[&<>"']/g, (char) => ENTITIES[char] ?? char);
|
|
2522
|
+
}
|
|
2523
|
+
function cellHtml(tag, text, column) {
|
|
2524
|
+
const alignment = column?.alignment ?? "left";
|
|
2525
|
+
const style = alignment === "left" ? "" : ` style="text-align:${alignment}"`;
|
|
2526
|
+
return `<${tag}${style}>${escapeHtml(text)}</${tag}>`;
|
|
2527
|
+
}
|
|
2528
|
+
function cellsHtml(cells, columns) {
|
|
2529
|
+
return cells.map((cell, index) => cellHtml("td", cell.text, columns[index])).join("");
|
|
2530
|
+
}
|
|
2531
|
+
function groupRowHtml(row, columns) {
|
|
2532
|
+
const firstAggregate = row.cells.findIndex((cell) => cell.text !== "");
|
|
2533
|
+
const span = Math.max(
|
|
2534
|
+
1,
|
|
2535
|
+
firstAggregate === -1 ? row.cells.length : firstAggregate
|
|
2536
|
+
);
|
|
2537
|
+
const colspan = span > 1 ? ` colspan="${String(span)}"` : "";
|
|
2538
|
+
const label = `<td${colspan}>${escapeHtml(row.label)}</td>`;
|
|
2539
|
+
const aggregates = row.cells.slice(span).map((cell, index) => cellHtml("td", cell.text, columns[span + index])).join("");
|
|
2540
|
+
return `<tr class="export-group" data-level="${String(row.level)}">${label}${aggregates}</tr>`;
|
|
2541
|
+
}
|
|
2542
|
+
function rowHtml(row, columns) {
|
|
2543
|
+
switch (row.kind) {
|
|
2544
|
+
case "data":
|
|
2545
|
+
return `<tr>${cellsHtml(row.cells, columns)}</tr>`;
|
|
2546
|
+
case "group":
|
|
2547
|
+
return groupRowHtml(row, columns);
|
|
2548
|
+
case "groupSummary":
|
|
2549
|
+
return `<tr class="export-group-summary" data-level="${String(row.level)}">${cellsHtml(row.cells, columns)}</tr>`;
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
function toHtmlTable(table, options = {}) {
|
|
2553
|
+
const { columns } = table;
|
|
2554
|
+
const caption = options.caption === void 0 ? "" : `<caption>${escapeHtml(options.caption)}</caption>`;
|
|
2555
|
+
const head = table.header ? `<thead><tr>${columns.map((column) => cellHtml("th", column.header, column)).join("")}</tr></thead>` : "";
|
|
2556
|
+
const body = `<tbody>${table.rows.map((row) => rowHtml(row, columns)).join("")}</tbody>`;
|
|
2557
|
+
const foot = table.footer === null ? "" : `<tfoot><tr>${cellsHtml(table.footer.cells, columns)}</tr></tfoot>`;
|
|
2558
|
+
return `<table class="gridkit-export-table">${caption}${head}${body}${foot}</table>`;
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
// src/export/records.ts
|
|
2562
|
+
function rawText(value) {
|
|
2563
|
+
if (value === null) {
|
|
2564
|
+
return "";
|
|
2565
|
+
}
|
|
2566
|
+
if (value instanceof Date) {
|
|
2567
|
+
return Number.isNaN(value.getTime()) ? "" : value.toISOString();
|
|
2568
|
+
}
|
|
2569
|
+
return String(value);
|
|
2570
|
+
}
|
|
2571
|
+
function cellField(cell, values) {
|
|
2572
|
+
return {
|
|
2573
|
+
text: values === "raw" ? rawText(cell.value) : cell.text,
|
|
2574
|
+
isNumber: typeof cell.value === "number"
|
|
2575
|
+
};
|
|
2576
|
+
}
|
|
2577
|
+
function textField(text) {
|
|
2578
|
+
return { text, isNumber: false };
|
|
2579
|
+
}
|
|
2580
|
+
function textRecords(table, values) {
|
|
2581
|
+
const records = [];
|
|
2582
|
+
if (table.header) {
|
|
2583
|
+
records.push(table.columns.map((column) => textField(column.header)));
|
|
2584
|
+
}
|
|
2585
|
+
for (const row of table.rows) {
|
|
2586
|
+
records.push(
|
|
2587
|
+
row.cells.map(
|
|
2588
|
+
(cell, index) => row.kind === "group" && index === 0 ? textField(row.label) : cellField(cell, values)
|
|
2589
|
+
)
|
|
2590
|
+
);
|
|
2591
|
+
}
|
|
2592
|
+
if (table.footer !== null) {
|
|
2593
|
+
records.push(table.footer.cells.map((cell) => cellField(cell, values)));
|
|
2594
|
+
}
|
|
2595
|
+
return records;
|
|
2596
|
+
}
|
|
2597
|
+
|
|
2598
|
+
// src/export/tsv.ts
|
|
2599
|
+
var SEPARATORS = /\r\n|[\t\r\n]/g;
|
|
2600
|
+
function toTsv(table, options = {}) {
|
|
2601
|
+
return textRecords(table, options.values ?? "text").map(
|
|
2602
|
+
(record) => record.map((field) => field.text.replace(SEPARATORS, " ")).join(" ")
|
|
2603
|
+
).join("\n");
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
// src/export/copy.ts
|
|
2607
|
+
function isCopyable(column) {
|
|
2608
|
+
return column.column.exportable !== false;
|
|
2609
|
+
}
|
|
2610
|
+
function hasRow(source, rowId) {
|
|
2611
|
+
return source.view.rows.some((entry) => entry.rowId === rowId);
|
|
2612
|
+
}
|
|
2613
|
+
function hasColumn(source, columnId) {
|
|
2614
|
+
return source.view.columns.some(
|
|
2615
|
+
(entry) => entry.id === columnId && isCopyable(entry)
|
|
2616
|
+
);
|
|
2617
|
+
}
|
|
2618
|
+
function selectionCopy(source) {
|
|
2619
|
+
const { state, view } = source;
|
|
2620
|
+
const selectedRows = new Set(state.rowSelection);
|
|
2621
|
+
const count = view.rows.filter(
|
|
2622
|
+
(entry) => selectedRows.has(entry.rowId)
|
|
2623
|
+
).length;
|
|
2624
|
+
if (count > 0) {
|
|
2625
|
+
return { kind: "rows", count };
|
|
2626
|
+
}
|
|
2627
|
+
const selectedColumns = new Set(state.columnSelection);
|
|
2628
|
+
const columnIds = view.columns.filter((entry) => selectedColumns.has(entry.id) && isCopyable(entry)).map((entry) => entry.id);
|
|
2629
|
+
if (columnIds.length > 0 && view.rows.length > 0) {
|
|
2630
|
+
return { kind: "columns", columnIds };
|
|
2631
|
+
}
|
|
2632
|
+
const cell = state.cellSelection;
|
|
2633
|
+
if (cell !== null && hasRow(source, cell.rowId) && hasColumn(source, cell.columnId)) {
|
|
2634
|
+
return { kind: "cell", rowId: cell.rowId, columnId: cell.columnId };
|
|
2635
|
+
}
|
|
2636
|
+
return null;
|
|
2637
|
+
}
|
|
2638
|
+
function canCopySelection(source) {
|
|
2639
|
+
return selectionCopy(source) !== null;
|
|
2640
|
+
}
|
|
2641
|
+
function withRows(source, rowIds) {
|
|
2642
|
+
return { ...source, state: { ...source.state, rowSelection: rowIds } };
|
|
2643
|
+
}
|
|
2644
|
+
function contentOf(source, { scope, columns, header }, unit) {
|
|
2645
|
+
const table = buildExportTable(source, {
|
|
2646
|
+
scope,
|
|
2647
|
+
columns: columns ?? "visible",
|
|
2648
|
+
includeHeader: header,
|
|
2649
|
+
includeGroups: false,
|
|
2650
|
+
includeAggregates: false
|
|
2651
|
+
});
|
|
2652
|
+
if (table.columns.length === 0 || table.rows.length === 0) {
|
|
2653
|
+
return null;
|
|
2654
|
+
}
|
|
2655
|
+
return {
|
|
2656
|
+
text: toTsv(table),
|
|
2657
|
+
html: toHtmlTable(table),
|
|
2658
|
+
count: unit === "columns" ? table.columns.length : table.rows.length,
|
|
2659
|
+
unit
|
|
2660
|
+
};
|
|
2661
|
+
}
|
|
2662
|
+
function cellContent(source, rowId, columnId) {
|
|
2663
|
+
if (!hasRow(source, rowId) || !hasColumn(source, columnId)) {
|
|
2664
|
+
return null;
|
|
2665
|
+
}
|
|
2666
|
+
return contentOf(
|
|
2667
|
+
withRows(source, [rowId]),
|
|
2668
|
+
{ scope: "selection", columns: [columnId], header: false },
|
|
2669
|
+
"cells"
|
|
2670
|
+
);
|
|
2671
|
+
}
|
|
2672
|
+
function rowContent(source, rowId) {
|
|
2673
|
+
if (!hasRow(source, rowId)) {
|
|
2674
|
+
return null;
|
|
2675
|
+
}
|
|
2676
|
+
return contentOf(
|
|
2677
|
+
withRows(source, [rowId]),
|
|
2678
|
+
{ scope: "selection", header: false },
|
|
2679
|
+
"rows"
|
|
2680
|
+
);
|
|
2681
|
+
}
|
|
2682
|
+
function selectionContent(source) {
|
|
2683
|
+
const selection = selectionCopy(source);
|
|
2684
|
+
switch (selection?.kind) {
|
|
2685
|
+
case void 0:
|
|
2686
|
+
return null;
|
|
2687
|
+
case "rows":
|
|
2688
|
+
return contentOf(
|
|
2689
|
+
source,
|
|
2690
|
+
{ scope: "selection", header: selection.count > 1 },
|
|
2691
|
+
"rows"
|
|
2692
|
+
);
|
|
2693
|
+
case "columns":
|
|
2694
|
+
return contentOf(
|
|
2695
|
+
source,
|
|
2696
|
+
{ scope: "all", columns: selection.columnIds, header: true },
|
|
2697
|
+
"columns"
|
|
2698
|
+
);
|
|
2699
|
+
case "cell":
|
|
2700
|
+
return cellContent(source, selection.rowId, selection.columnId);
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
function copyContent(source, request) {
|
|
2704
|
+
switch (request.kind) {
|
|
2705
|
+
case "cell":
|
|
2706
|
+
return cellContent(source, request.rowId, request.columnId);
|
|
2707
|
+
case "row":
|
|
2708
|
+
return rowContent(source, request.rowId);
|
|
2709
|
+
case "selection":
|
|
2710
|
+
return selectionContent(source);
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
|
|
2714
|
+
// src/export/exportFile.ts
|
|
2715
|
+
function withExtension(fileName, extension) {
|
|
2716
|
+
const suffix = `.${extension}`;
|
|
2717
|
+
return fileName.toLowerCase().endsWith(suffix.toLowerCase()) ? fileName : fileName + suffix;
|
|
2718
|
+
}
|
|
2719
|
+
function writerFor(format, writers) {
|
|
2720
|
+
if (typeof format !== "string") {
|
|
2721
|
+
return format;
|
|
2722
|
+
}
|
|
2723
|
+
const writer = writers.get(format);
|
|
2724
|
+
if (writer === void 0) {
|
|
2725
|
+
reportError(
|
|
2726
|
+
`there is no export writer for \`${format}\` \u2014 register one through \`exportWriters\`.`
|
|
2727
|
+
);
|
|
2728
|
+
return null;
|
|
2729
|
+
}
|
|
2730
|
+
return writer;
|
|
2731
|
+
}
|
|
2732
|
+
function fileNameFor(options, writer) {
|
|
2733
|
+
const { fileName = "export" } = options;
|
|
2734
|
+
const name = typeof fileName === "function" ? fileName(writer.format) : fileName;
|
|
2735
|
+
return withExtension(name, writer.fileExtension);
|
|
2736
|
+
}
|
|
2737
|
+
function exportFile(source, format, options, writers) {
|
|
2738
|
+
const writer = writerFor(format, writers);
|
|
2739
|
+
if (writer === null) {
|
|
2740
|
+
return null;
|
|
2741
|
+
}
|
|
2742
|
+
const content = writer.write(buildExportTable(source, options), {
|
|
2743
|
+
locale: source.options.locale,
|
|
2744
|
+
messages: source.messages,
|
|
2745
|
+
options
|
|
2746
|
+
});
|
|
2747
|
+
const fileName = fileNameFor(options, writer);
|
|
2748
|
+
const { mimeType } = writer;
|
|
2749
|
+
return content instanceof Promise ? content.then((resolved) => ({ fileName, mimeType, content: resolved })) : { fileName, mimeType, content };
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2752
|
+
// src/export/print.ts
|
|
2753
|
+
var PORTRAIT_COLUMN_LIMIT = 6;
|
|
2754
|
+
function resolveOrientation(table, options) {
|
|
2755
|
+
return options.orientation ?? (table.columns.length > PORTRAIT_COLUMN_LIMIT ? "landscape" : "portrait");
|
|
2756
|
+
}
|
|
2757
|
+
function timestampText(timestamp, locale) {
|
|
2758
|
+
const date = timestamp === true ? /* @__PURE__ */ new Date() : timestamp;
|
|
2759
|
+
return new Intl.DateTimeFormat(locale, {
|
|
2760
|
+
dateStyle: "medium",
|
|
2761
|
+
timeStyle: "short"
|
|
2762
|
+
}).format(date);
|
|
2763
|
+
}
|
|
2764
|
+
function line(tag, className, text) {
|
|
2765
|
+
return text === void 0 || text === "" ? "" : `<${tag} class="${className}">${escapeHtml(text)}</${tag}>`;
|
|
2766
|
+
}
|
|
2767
|
+
function headerHtml(options) {
|
|
2768
|
+
const { timestamp = false } = options;
|
|
2769
|
+
const lines = line("h1", "print-title", options.title) + line("p", "print-subtitle", options.subtitle) + (timestamp === false ? "" : line("p", "print-timestamp", timestampText(timestamp, options.locale)));
|
|
2770
|
+
return lines === "" ? "" : `<header class="gridkit-print-header">${lines}</header>`;
|
|
2771
|
+
}
|
|
2772
|
+
function buildPrintDocument(table, options = {}) {
|
|
2773
|
+
const footer = line("footer", "gridkit-print-footer", options.footer);
|
|
2774
|
+
return {
|
|
2775
|
+
title: options.title ?? "",
|
|
2776
|
+
bodyHtml: `${headerHtml(options)}${toHtmlTable(table)}${footer}`,
|
|
2777
|
+
page: {
|
|
2778
|
+
paperSize: options.paperSize ?? "A4",
|
|
2779
|
+
orientation: resolveOrientation(table, options),
|
|
2780
|
+
pageNumbers: options.pageNumbers ?? true,
|
|
2781
|
+
fitToWidth: options.fitToWidth ?? false
|
|
2782
|
+
}
|
|
2783
|
+
};
|
|
2784
|
+
}
|
|
2785
|
+
function exportPrintDocument(source, options = {}) {
|
|
2786
|
+
return buildPrintDocument(buildExportTable(source, options), {
|
|
2787
|
+
...options,
|
|
2788
|
+
title: options.title ?? source.options.label,
|
|
2789
|
+
locale: options.locale ?? source.options.locale
|
|
2790
|
+
});
|
|
2791
|
+
}
|
|
2792
|
+
|
|
2793
|
+
// src/export/csv.ts
|
|
2794
|
+
var BOM = "\uFEFF";
|
|
2795
|
+
var FORMULA_START = /^[=+\-@\t\r]/;
|
|
2796
|
+
var SIGN_START = /^[+-]/;
|
|
2797
|
+
var NEEDS_QUOTES = /["\r\n]/;
|
|
2798
|
+
function autoDelimiter(locale) {
|
|
2799
|
+
const decimal = new Intl.NumberFormat(locale).formatToParts(1.5).find((part) => part.type === "decimal")?.value;
|
|
2800
|
+
return decimal === "," ? ";" : ",";
|
|
2801
|
+
}
|
|
2802
|
+
function neutralize(field) {
|
|
2803
|
+
const { text } = field;
|
|
2804
|
+
if (!FORMULA_START.test(text) || field.isNumber && SIGN_START.test(text)) {
|
|
2805
|
+
return text;
|
|
2806
|
+
}
|
|
2807
|
+
return `'${text}`;
|
|
2808
|
+
}
|
|
2809
|
+
function quote(text, delimiter) {
|
|
2810
|
+
return text.includes(delimiter) || NEEDS_QUOTES.test(text) ? `"${text.replaceAll('"', '""')}"` : text;
|
|
2811
|
+
}
|
|
2812
|
+
function toCsv(table, options = {}) {
|
|
2813
|
+
const delimiter = options.delimiter === "auto" ? autoDelimiter(options.locale) : options.delimiter ?? ",";
|
|
2814
|
+
const guard = options.neutralizeFormulas ?? true;
|
|
2815
|
+
const lines = textRecords(table, options.values ?? "text").map(
|
|
2816
|
+
(record) => record.map((field) => quote(guard ? neutralize(field) : field.text, delimiter)).join(delimiter)
|
|
2817
|
+
);
|
|
2818
|
+
return (options.bom ?? true ? BOM : "") + lines.join(options.eol ?? "\r\n");
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
// src/export/json.ts
|
|
2822
|
+
function uniqueNames(names) {
|
|
2823
|
+
const used = /* @__PURE__ */ new Set();
|
|
2824
|
+
return names.map((name) => {
|
|
2825
|
+
let unique = name;
|
|
2826
|
+
for (let n = 2; used.has(unique); n += 1) {
|
|
2827
|
+
unique = `${name} (${String(n)})`;
|
|
2828
|
+
}
|
|
2829
|
+
used.add(unique);
|
|
2830
|
+
return unique;
|
|
2831
|
+
});
|
|
2832
|
+
}
|
|
2833
|
+
function toJson(table, options = {}) {
|
|
2834
|
+
const keys = options.keys === "header" ? uniqueNames(table.columns.map((column) => column.header)) : table.columns.map((column) => column.id);
|
|
2835
|
+
const records = table.rows.flatMap(
|
|
2836
|
+
(row) => row.kind === "data" ? [
|
|
2837
|
+
Object.fromEntries(
|
|
2838
|
+
keys.map((key, index) => [key, row.cells[index]?.value ?? null])
|
|
2839
|
+
)
|
|
2840
|
+
] : []
|
|
2841
|
+
);
|
|
2842
|
+
return JSON.stringify(records, null, options.space);
|
|
2843
|
+
}
|
|
2844
|
+
|
|
2845
|
+
// src/export/writer.ts
|
|
2846
|
+
var csvWriter = {
|
|
2847
|
+
format: "csv",
|
|
2848
|
+
fileExtension: "csv",
|
|
2849
|
+
mimeType: "text/csv;charset=utf-8",
|
|
2850
|
+
write: (table, { locale, options }) => toCsv(table, { locale, ...options.csv })
|
|
2851
|
+
};
|
|
2852
|
+
var jsonWriter = {
|
|
2853
|
+
format: "json",
|
|
2854
|
+
fileExtension: "json",
|
|
2855
|
+
mimeType: "application/json",
|
|
2856
|
+
write: (table, { options }) => toJson(table, options.json)
|
|
2857
|
+
};
|
|
2858
|
+
function resolveExportWriters(writers) {
|
|
2859
|
+
return new Map(
|
|
2860
|
+
[csvWriter, jsonWriter, ...writers ?? []].map((writer) => [
|
|
2861
|
+
writer.format,
|
|
2862
|
+
writer
|
|
2863
|
+
])
|
|
2864
|
+
);
|
|
2865
|
+
}
|
|
2866
|
+
|
|
2867
|
+
// src/filterMenu/operators.ts
|
|
2868
|
+
function filterOperatorFamily(type) {
|
|
2869
|
+
return kindOf(type);
|
|
2870
|
+
}
|
|
2871
|
+
var familyOperators = {
|
|
2872
|
+
text: [
|
|
2873
|
+
"contains",
|
|
2874
|
+
"notContains",
|
|
2875
|
+
"eq",
|
|
2876
|
+
"ne",
|
|
2877
|
+
"startsWith",
|
|
2878
|
+
"endsWith",
|
|
2879
|
+
"isEmpty",
|
|
2880
|
+
"isNotEmpty"
|
|
2881
|
+
],
|
|
2882
|
+
number: [
|
|
2883
|
+
"eq",
|
|
2884
|
+
"ne",
|
|
2885
|
+
"gt",
|
|
2886
|
+
"gte",
|
|
2887
|
+
"lt",
|
|
2888
|
+
"lte",
|
|
2889
|
+
"between",
|
|
2890
|
+
"isEmpty",
|
|
2891
|
+
"isNotEmpty"
|
|
2892
|
+
],
|
|
2893
|
+
date: ["eq", "ne", "lt", "gt", "between", "isEmpty", "isNotEmpty"],
|
|
2894
|
+
boolean: ["eq", "isEmpty", "isNotEmpty"]
|
|
2895
|
+
};
|
|
2896
|
+
var instantOperators = [
|
|
2897
|
+
"lt",
|
|
2898
|
+
"gt",
|
|
2899
|
+
"between",
|
|
2900
|
+
"isEmpty",
|
|
2901
|
+
"isNotEmpty"
|
|
2902
|
+
];
|
|
2903
|
+
function defaultFilterOperators(type) {
|
|
2904
|
+
return type === "dateTime" || type === "time" ? instantOperators : familyOperators[filterOperatorFamily(type)];
|
|
2905
|
+
}
|
|
2906
|
+
function filterOperandArity(operator) {
|
|
2907
|
+
switch (operator) {
|
|
2908
|
+
case "isEmpty":
|
|
2909
|
+
case "isNotEmpty":
|
|
2910
|
+
return 0;
|
|
2911
|
+
case "between":
|
|
2912
|
+
return 2;
|
|
2913
|
+
case "eq":
|
|
2914
|
+
case "ne":
|
|
2915
|
+
case "contains":
|
|
2916
|
+
case "notContains":
|
|
2917
|
+
case "startsWith":
|
|
2918
|
+
case "endsWith":
|
|
2919
|
+
case "gt":
|
|
2920
|
+
case "gte":
|
|
2921
|
+
case "lt":
|
|
2922
|
+
case "lte":
|
|
2923
|
+
case "in":
|
|
2924
|
+
return 1;
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
var NUMBER_INPUT = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
2928
|
+
var DATE_INPUT = /^(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3}))?)?)?$/;
|
|
2929
|
+
function parseNumber(text) {
|
|
2930
|
+
const value = Number(text);
|
|
2931
|
+
return NUMBER_INPUT.test(text) && Number.isFinite(value) ? value : void 0;
|
|
2932
|
+
}
|
|
2933
|
+
function parseDate(text) {
|
|
2934
|
+
const match = DATE_INPUT.exec(text);
|
|
2935
|
+
if (match === null) {
|
|
2936
|
+
return void 0;
|
|
2937
|
+
}
|
|
2938
|
+
const [
|
|
2939
|
+
,
|
|
2940
|
+
year,
|
|
2941
|
+
month,
|
|
2942
|
+
day,
|
|
2943
|
+
hours = "0",
|
|
2944
|
+
minutes = "0",
|
|
2945
|
+
seconds = "0",
|
|
2946
|
+
fraction = ""
|
|
2947
|
+
] = match;
|
|
2948
|
+
if (Number(hours) > 23 || Number(minutes) > 59 || Number(seconds) > 59) {
|
|
2949
|
+
return void 0;
|
|
2950
|
+
}
|
|
2951
|
+
const date = new Date(
|
|
2952
|
+
Number(year),
|
|
2953
|
+
Number(month) - 1,
|
|
2954
|
+
Number(day),
|
|
2955
|
+
Number(hours),
|
|
2956
|
+
Number(minutes),
|
|
2957
|
+
Number(seconds),
|
|
2958
|
+
Number(fraction.padEnd(3, "0"))
|
|
2959
|
+
);
|
|
2960
|
+
return date.getFullYear() === Number(year) && date.getMonth() === Number(month) - 1 && date.getDate() === Number(day) ? date : void 0;
|
|
2961
|
+
}
|
|
2962
|
+
function parseBoolean(text) {
|
|
2963
|
+
if (text === "true") {
|
|
2964
|
+
return true;
|
|
2965
|
+
}
|
|
2966
|
+
return text === "false" ? false : void 0;
|
|
2967
|
+
}
|
|
2968
|
+
function parseFilterOperand(text, type) {
|
|
2969
|
+
if (text === "") {
|
|
2970
|
+
return void 0;
|
|
2971
|
+
}
|
|
2972
|
+
switch (filterOperatorFamily(type)) {
|
|
2973
|
+
case "text":
|
|
2974
|
+
return text;
|
|
2975
|
+
case "number":
|
|
2976
|
+
return parseNumber(text.trim());
|
|
2977
|
+
case "date":
|
|
2978
|
+
return parseDate(text.trim());
|
|
2979
|
+
case "boolean":
|
|
2980
|
+
return parseBoolean(text.trim());
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
function pad(value, width = 2) {
|
|
2984
|
+
return String(value).padStart(width, "0");
|
|
2985
|
+
}
|
|
2986
|
+
function dayInput(date) {
|
|
2987
|
+
return `${pad(date.getFullYear(), 4)}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
2988
|
+
}
|
|
2989
|
+
function momentInput(date) {
|
|
2990
|
+
const minute = `${dayInput(date)}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
2991
|
+
const seconds = date.getSeconds();
|
|
2992
|
+
const milliseconds = date.getMilliseconds();
|
|
2993
|
+
if (seconds === 0 && milliseconds === 0) {
|
|
2994
|
+
return minute;
|
|
2995
|
+
}
|
|
2996
|
+
const second = `${minute}:${pad(seconds)}`;
|
|
2997
|
+
return milliseconds === 0 ? second : `${second}.${pad(milliseconds, 3)}`;
|
|
2998
|
+
}
|
|
2999
|
+
function formatFilterOperand(value, type) {
|
|
3000
|
+
if (value === null || value === void 0) {
|
|
3001
|
+
return "";
|
|
3002
|
+
}
|
|
3003
|
+
const date = filterOperatorFamily(type) === "date" ? toDate(value) : void 0;
|
|
3004
|
+
if (date === void 0) {
|
|
3005
|
+
return String(value);
|
|
3006
|
+
}
|
|
3007
|
+
return type === "date" ? dayInput(date) : momentInput(date);
|
|
3008
|
+
}
|
|
3009
|
+
|
|
3010
|
+
// src/filterMenu/options.ts
|
|
3011
|
+
var DEFAULT_FILTER_VALUE_LIMIT = 1e4;
|
|
3012
|
+
function conditionOperators(operators) {
|
|
3013
|
+
return operators.includes("in") ? operators.filter((operator) => operator !== "in") : operators;
|
|
3014
|
+
}
|
|
3015
|
+
function resolveColumnFilterMenu(options, column) {
|
|
3016
|
+
if (!(column.filterable ?? options.filterableColumns ?? false)) {
|
|
3017
|
+
return null;
|
|
3018
|
+
}
|
|
3019
|
+
const grid = options.filterMenu;
|
|
3020
|
+
const own = column.filterMenu;
|
|
3021
|
+
return {
|
|
3022
|
+
ui: own?.ui ?? grid?.ui ?? "simple",
|
|
3023
|
+
operators: conditionOperators(
|
|
3024
|
+
own?.operators ?? defaultFilterOperators(column.type)
|
|
3025
|
+
),
|
|
3026
|
+
family: filterOperatorFamily(column.type),
|
|
3027
|
+
showCounts: grid?.showCounts ?? false,
|
|
3028
|
+
valueLimit: grid?.valueLimit ?? DEFAULT_FILTER_VALUE_LIMIT
|
|
3029
|
+
};
|
|
3030
|
+
}
|
|
3031
|
+
|
|
3032
|
+
// src/messages.ts
|
|
3033
|
+
function localeKey2(locale) {
|
|
3034
|
+
return typeof locale === "string" ? locale : locale?.join(",") ?? "";
|
|
3035
|
+
}
|
|
3036
|
+
var countFormats = /* @__PURE__ */ new Map();
|
|
3037
|
+
function countFormat(locale) {
|
|
3038
|
+
const key = localeKey2(locale);
|
|
3039
|
+
let format = countFormats.get(key);
|
|
3040
|
+
if (format === void 0) {
|
|
3041
|
+
const numberFormat = new Intl.NumberFormat(locale, {
|
|
3042
|
+
maximumFractionDigits: 0
|
|
3043
|
+
});
|
|
3044
|
+
format = (count) => numberFormat.format(count);
|
|
3045
|
+
countFormats.set(key, format);
|
|
3046
|
+
}
|
|
3047
|
+
return format;
|
|
3048
|
+
}
|
|
3049
|
+
function columnCount(n, count, change) {
|
|
3050
|
+
return count === 1 ? `1 column ${change}` : `${n(count)} columns ${change}`;
|
|
3051
|
+
}
|
|
3052
|
+
function searchResults(n, count) {
|
|
3053
|
+
if (count === 0) {
|
|
3054
|
+
return "No rows found";
|
|
3055
|
+
}
|
|
3056
|
+
return count === 1 ? "1 row found" : `${n(count)} rows found`;
|
|
3057
|
+
}
|
|
3058
|
+
function selectedCount(n, count, target) {
|
|
3059
|
+
const noun = target === "rows" ? "row" : "column";
|
|
3060
|
+
if (count === 0) {
|
|
3061
|
+
return `No ${noun}s selected`;
|
|
3062
|
+
}
|
|
3063
|
+
return count === 1 ? `1 ${noun} selected` : `${n(count)} ${noun}s selected`;
|
|
3064
|
+
}
|
|
3065
|
+
var operatorLabels = {
|
|
3066
|
+
eq: "Equals",
|
|
3067
|
+
ne: "Does not equal",
|
|
3068
|
+
contains: "Contains",
|
|
3069
|
+
notContains: "Does not contain",
|
|
3070
|
+
startsWith: "Starts with",
|
|
3071
|
+
endsWith: "Ends with",
|
|
3072
|
+
gt: "Greater than",
|
|
3073
|
+
gte: "Greater than or equal to",
|
|
3074
|
+
lt: "Less than",
|
|
3075
|
+
lte: "Less than or equal to",
|
|
3076
|
+
between: "Between",
|
|
3077
|
+
in: "Is one of",
|
|
3078
|
+
isEmpty: "Is blank",
|
|
3079
|
+
isNotEmpty: "Is not blank"
|
|
3080
|
+
};
|
|
3081
|
+
var dateOperatorLabels = {
|
|
3082
|
+
lt: "Before",
|
|
3083
|
+
lte: "On or before",
|
|
3084
|
+
gt: "After",
|
|
3085
|
+
gte: "On or after"
|
|
3086
|
+
};
|
|
3087
|
+
function filterOperatorLabel(operator, family) {
|
|
3088
|
+
return (family === "date" ? dateOperatorLabels[operator] : void 0) ?? operatorLabels[operator];
|
|
3089
|
+
}
|
|
3090
|
+
function filterSearchFirst(n, total) {
|
|
3091
|
+
return total === 1 ? "Type to search 1 value" : `Type to search ${n(total)} values`;
|
|
3092
|
+
}
|
|
3093
|
+
function filterResults(n, shown, total) {
|
|
3094
|
+
return `${n(shown)} of ${n(total)} ${total === 1 ? "row" : "rows"}`;
|
|
3095
|
+
}
|
|
3096
|
+
var filterValueRequests = {
|
|
3097
|
+
text: "Enter a value",
|
|
3098
|
+
number: "Enter a number",
|
|
3099
|
+
date: "Enter a date",
|
|
3100
|
+
boolean: "Choose a value"
|
|
3101
|
+
};
|
|
3102
|
+
var filterOperatorMenus = {
|
|
3103
|
+
text: "Text filters",
|
|
3104
|
+
number: "Number filters",
|
|
3105
|
+
date: "Date filters",
|
|
3106
|
+
boolean: "Boolean filters"
|
|
3107
|
+
};
|
|
3108
|
+
function copied(n, count, unit) {
|
|
3109
|
+
return count === 1 ? `1 ${unit.slice(0, -1)} copied` : `${n(count)} ${unit} copied`;
|
|
3110
|
+
}
|
|
3111
|
+
function createDefaultMessages(locale) {
|
|
3112
|
+
const n = countFormat(locale);
|
|
3113
|
+
return {
|
|
3114
|
+
pagerLabel: "Pagination",
|
|
3115
|
+
firstPage: "First",
|
|
3116
|
+
previousPage: "Previous",
|
|
3117
|
+
nextPage: "Next",
|
|
3118
|
+
lastPage: "Last",
|
|
3119
|
+
pageSizeLabel: "Rows per page",
|
|
3120
|
+
pageButtonLabel: (page) => `Page ${n(page)}`,
|
|
3121
|
+
pageStatus: (page, pageCount) => `Page ${n(page)} of ${n(pageCount)}`,
|
|
3122
|
+
loadingMore: "Loading more\u2026",
|
|
3123
|
+
booleanTrue: "true",
|
|
3124
|
+
booleanFalse: "false",
|
|
3125
|
+
blankGroupValue: "(blank)",
|
|
3126
|
+
groupByBarLabel: "Grouped by",
|
|
3127
|
+
groupByBarPlaceholder: "Drag a column here to group by it",
|
|
3128
|
+
groupByChipLabel: (columnName2, level, levelCount) => levelCount > 1 ? `${columnName2}, level ${n(level)} of ${n(levelCount)}` : columnName2,
|
|
3129
|
+
removeGroupBy: (columnName2) => `Stop grouping by ${columnName2}`,
|
|
3130
|
+
columnResized: (columnName2, width) => `${columnName2}, ${n(width)} pixels wide`,
|
|
3131
|
+
columnMoved: (columnName2, position, columnCount2) => `${columnName2}, column ${n(position)} of ${n(columnCount2)}`,
|
|
3132
|
+
columnSorted: (columnName2, direction, key, keyCount) => {
|
|
3133
|
+
const sorted = `${columnName2} sorted ${direction === "asc" ? "ascending" : "descending"}`;
|
|
3134
|
+
return keyCount > 1 ? `${sorted}, key ${n(key)} of ${n(keyCount)}` : sorted;
|
|
3135
|
+
},
|
|
3136
|
+
sortCleared: (columnName2) => `${columnName2}, sort cleared`,
|
|
3137
|
+
groupedBy: (columnName2, level, levelCount) => levelCount > 1 ? `Grouped by ${columnName2}, level ${n(level)} of ${n(levelCount)}` : `Grouped by ${columnName2}`,
|
|
3138
|
+
groupingRemoved: (columnName2) => `${columnName2}, grouping removed`,
|
|
3139
|
+
groupExpanded: "Group expanded",
|
|
3140
|
+
groupCollapsed: "Group collapsed",
|
|
3141
|
+
allGroupsExpanded: "All groups expanded",
|
|
3142
|
+
allGroupsCollapsed: "All groups collapsed",
|
|
3143
|
+
selectedCount: (count, target) => selectedCount(n, count, target),
|
|
3144
|
+
cellSelected: (columnName2, rowNumber) => `${columnName2}, row ${n(rowNumber)}, selected`,
|
|
3145
|
+
columnHidden: (columnName2) => `${columnName2}, column hidden`,
|
|
3146
|
+
columnShown: (columnName2) => `${columnName2}, column shown`,
|
|
3147
|
+
columnsHidden: (count) => columnCount(n, count, "hidden"),
|
|
3148
|
+
columnsShown: (count) => columnCount(n, count, "shown"),
|
|
3149
|
+
columnsAutoFitted: (count) => columnCount(n, count, "autofitted"),
|
|
3150
|
+
headerMenuLabel: (columnName2) => `${columnName2} column menu`,
|
|
3151
|
+
cellMenuLabel: "Row menu",
|
|
3152
|
+
groupMenuLabel: "Group menu",
|
|
3153
|
+
bodyMenuLabel: "Grid menu",
|
|
3154
|
+
sortAscending: "Sort ascending",
|
|
3155
|
+
sortDescending: "Sort descending",
|
|
3156
|
+
clearSort: "Clear sort",
|
|
3157
|
+
clearAllSorting: "Clear all sorting",
|
|
3158
|
+
groupByColumn: (columnName2) => `Group by ${columnName2}`,
|
|
3159
|
+
ungroupAll: "Ungroup all",
|
|
3160
|
+
expandAllGroups: "Expand all groups",
|
|
3161
|
+
collapseAllGroups: "Collapse all groups",
|
|
3162
|
+
hideColumn: "Hide column",
|
|
3163
|
+
autoFitColumn: "Autofit column",
|
|
3164
|
+
autoFitAllColumns: "Autofit all columns",
|
|
3165
|
+
selectAllRows: "Select all rows",
|
|
3166
|
+
clearSelection: "Clear selection",
|
|
3167
|
+
clearFilters: "Clear filters",
|
|
3168
|
+
chooseColumns: "Choose columns",
|
|
3169
|
+
toolbarLabel: "Grid toolbar",
|
|
3170
|
+
searchLabel: "Search",
|
|
3171
|
+
searchPlaceholder: "Search\u2026",
|
|
3172
|
+
moreToolbarItems: "More",
|
|
3173
|
+
searchResults: (count) => searchResults(n, count),
|
|
3174
|
+
columnChooserLabel: "Columns",
|
|
3175
|
+
columnChooserSearchLabel: "Search columns",
|
|
3176
|
+
showAllColumns: "Show all",
|
|
3177
|
+
noMatchingColumns: "No matching columns",
|
|
3178
|
+
filterOperatorLabel,
|
|
3179
|
+
filterBlanks: "(Blanks)",
|
|
3180
|
+
filterSearchFirst: (total) => filterSearchFirst(n, total),
|
|
3181
|
+
filterMoreValues: (count) => `${n(count)} more, refine the search`,
|
|
3182
|
+
openFilter: "Filter\u2026",
|
|
3183
|
+
clearColumnFilter: "Clear filter",
|
|
3184
|
+
filterMenuLabel: (columnName2) => `${columnName2} filter`,
|
|
3185
|
+
columnFiltered: "Filtered",
|
|
3186
|
+
applyFilter: "OK",
|
|
3187
|
+
cancelFilter: "Cancel",
|
|
3188
|
+
customFilter: "Custom filter",
|
|
3189
|
+
filterResults: (shown, total) => filterResults(n, shown, total),
|
|
3190
|
+
filterConditionLabel: (position) => `Condition ${n(position)}`,
|
|
3191
|
+
filterOperatorFieldLabel: "Operator",
|
|
3192
|
+
filterValueLabel: "Value",
|
|
3193
|
+
filterFromLabel: "From",
|
|
3194
|
+
filterToLabel: "To",
|
|
3195
|
+
filterCombinatorLabel: "Combine conditions",
|
|
3196
|
+
filterAnd: "And",
|
|
3197
|
+
filterOr: "Or",
|
|
3198
|
+
filterValueInvalid: (family) => filterValueRequests[family],
|
|
3199
|
+
filterSearchLabel: "Search values",
|
|
3200
|
+
filterSelectAll: "Select all",
|
|
3201
|
+
filterValuesLabel: "Values",
|
|
3202
|
+
filterByCondition: "Filtered by condition",
|
|
3203
|
+
filterOperatorMenu: (family) => filterOperatorMenus[family],
|
|
3204
|
+
filterBackToValues: "Back to values",
|
|
3205
|
+
exportMenu: "Export",
|
|
3206
|
+
exportCsv: "Export to CSV",
|
|
3207
|
+
exportJson: "Export to JSON",
|
|
3208
|
+
exportXlsx: "Export to Excel",
|
|
3209
|
+
exportPdf: "Export to PDF",
|
|
3210
|
+
exportSelectionCsv: "Export selection to CSV",
|
|
3211
|
+
exportSelectionJson: "Export selection to JSON",
|
|
3212
|
+
exportSelectionXlsx: "Export selection to Excel",
|
|
3213
|
+
exportFailed: "Export failed",
|
|
3214
|
+
copyCell: "Copy cell",
|
|
3215
|
+
copyRow: "Copy row",
|
|
3216
|
+
copySelection: "Copy selection",
|
|
3217
|
+
copied: (count, unit) => copied(n, count, unit),
|
|
3218
|
+
copyFailed: "Copy failed",
|
|
3219
|
+
print: "Print"
|
|
3220
|
+
};
|
|
3221
|
+
}
|
|
3222
|
+
var defaultMessages = createDefaultMessages();
|
|
3223
|
+
var localeDefaults = /* @__PURE__ */ new Map();
|
|
3224
|
+
function defaultsFor(locale) {
|
|
3225
|
+
if (locale === void 0) {
|
|
3226
|
+
return defaultMessages;
|
|
3227
|
+
}
|
|
3228
|
+
const key = localeKey2(locale);
|
|
3229
|
+
let defaults = localeDefaults.get(key);
|
|
3230
|
+
if (defaults === void 0) {
|
|
3231
|
+
defaults = createDefaultMessages(locale);
|
|
3232
|
+
localeDefaults.set(key, defaults);
|
|
3233
|
+
}
|
|
3234
|
+
return defaults;
|
|
3235
|
+
}
|
|
3236
|
+
function resolveMessages(messages, locale) {
|
|
3237
|
+
const defaults = defaultsFor(locale);
|
|
3238
|
+
return messages === void 0 ? defaults : { ...defaults, ...messages };
|
|
3239
|
+
}
|
|
3240
|
+
|
|
3241
|
+
// src/util/filterEditor.ts
|
|
3242
|
+
function touchesColumn(entry, columnId) {
|
|
3243
|
+
return "combinator" in entry ? entry.entries.some((nested) => touchesColumn(nested, columnId)) : entry.columnId === columnId;
|
|
3244
|
+
}
|
|
3245
|
+
function isOperatorOn(entry, columnId) {
|
|
3246
|
+
return "operator" in entry && entry.columnId === columnId;
|
|
3247
|
+
}
|
|
3248
|
+
function isConditionOn(entry, columnId) {
|
|
3249
|
+
return isOperatorOn(entry, columnId) && entry.operator !== "in";
|
|
3250
|
+
}
|
|
3251
|
+
function valuesShape(entry, columnId) {
|
|
3252
|
+
const values = (candidate) => candidate !== void 0 && isOperatorOn(candidate, columnId) && candidate.operator === "in" && isScalarList(candidate.value) ? candidate.value : void 0;
|
|
3253
|
+
const blanks = (candidate) => candidate !== void 0 && isOperatorOn(candidate, columnId) && candidate.operator === "isEmpty";
|
|
3254
|
+
const alone = values(entry);
|
|
3255
|
+
if (alone !== void 0) {
|
|
3256
|
+
return { kind: "values", values: alone, includeBlanks: false };
|
|
3257
|
+
}
|
|
3258
|
+
if (!("combinator" in entry) || entry.combinator !== "or" || entry.entries.length !== 2) {
|
|
3259
|
+
return void 0;
|
|
3260
|
+
}
|
|
3261
|
+
const [first, second] = entry.entries;
|
|
3262
|
+
const listed = blanks(first) ? values(second) : values(first);
|
|
3263
|
+
return listed !== void 0 && (blanks(first) || blanks(second)) ? { kind: "values", values: listed, includeBlanks: true } : void 0;
|
|
3264
|
+
}
|
|
3265
|
+
function conditionsShape(touching, columnId) {
|
|
3266
|
+
const [only] = touching;
|
|
3267
|
+
const grouped = touching.length === 1 && only !== void 0 && "combinator" in only;
|
|
3268
|
+
const entries = grouped ? only.entries : touching;
|
|
3269
|
+
const combinator = grouped ? only.combinator : "and";
|
|
3270
|
+
if (entries.length === 0 || entries.length > 2) {
|
|
3271
|
+
return void 0;
|
|
3272
|
+
}
|
|
3273
|
+
const conditions = entries.filter((entry) => isConditionOn(entry, columnId));
|
|
3274
|
+
return conditions.length === entries.length ? { kind: "conditions", conditions, combinator } : void 0;
|
|
3275
|
+
}
|
|
3276
|
+
function describeColumnFilter(filter, columnId) {
|
|
3277
|
+
const touching = filter.filter((entry) => touchesColumn(entry, columnId));
|
|
3278
|
+
const [only] = touching;
|
|
3279
|
+
if (only === void 0) {
|
|
3280
|
+
return { kind: "none" };
|
|
3281
|
+
}
|
|
3282
|
+
return (touching.length === 1 ? valuesShape(only, columnId) : void 0) ?? conditionsShape(touching, columnId) ?? { kind: "custom" };
|
|
3283
|
+
}
|
|
3284
|
+
function isColumnFiltered(filter, columnId) {
|
|
3285
|
+
return filter.some((entry) => touchesColumn(entry, columnId));
|
|
3286
|
+
}
|
|
3287
|
+
function isOfferable(value) {
|
|
3288
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value instanceof Date;
|
|
3289
|
+
}
|
|
3290
|
+
function matchesSearch(label, search) {
|
|
3291
|
+
return label.toLowerCase().includes(search.toLowerCase());
|
|
3292
|
+
}
|
|
3293
|
+
function columnValueOptions(rows, dataColumns, filter, columnId, query = {}) {
|
|
3294
|
+
const column = dataColumns.find((entry) => entry.id === columnId)?.column;
|
|
3295
|
+
if (column === void 0) {
|
|
3296
|
+
return { options: [], total: 0, truncated: false, blanks: 0 };
|
|
3297
|
+
}
|
|
3298
|
+
const keep = compileFilter(
|
|
3299
|
+
filter.filter((entry) => !touchesColumn(entry, columnId)),
|
|
3300
|
+
dataColumns
|
|
3301
|
+
);
|
|
3302
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
3303
|
+
let blanks = 0;
|
|
3304
|
+
for (const row of rows) {
|
|
3305
|
+
if (keep !== void 0 && !keep(row)) {
|
|
3306
|
+
continue;
|
|
3307
|
+
}
|
|
3308
|
+
const value = accessDotted(row, column.field);
|
|
3309
|
+
if (isEmptyCell(value)) {
|
|
3310
|
+
blanks++;
|
|
3311
|
+
} else if (isOfferable(value)) {
|
|
3312
|
+
const key = filterValueKey(value, column.type);
|
|
3313
|
+
const bucket = buckets.get(key);
|
|
3314
|
+
if (bucket === void 0) {
|
|
3315
|
+
buckets.set(key, { value, row, count: 1 });
|
|
3316
|
+
} else {
|
|
3317
|
+
bucket.count++;
|
|
3318
|
+
}
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
const { search = "", limit, locale } = query;
|
|
3322
|
+
const messages = resolveMessages(query.messages, locale);
|
|
3323
|
+
const options = [...buckets.values()].sort((a, b) => compareValues(a.value, b.value, column.type)).map(({ value, row, count }) => ({
|
|
3324
|
+
value,
|
|
3325
|
+
label: formatCellValue(value, column, locale, row, messages),
|
|
3326
|
+
count
|
|
3327
|
+
})).filter((option) => matchesSearch(option.label, search));
|
|
3328
|
+
const shown = limit === void 0 ? options : options.slice(0, limit);
|
|
3329
|
+
return {
|
|
3330
|
+
options: shown,
|
|
3331
|
+
total: options.length,
|
|
3332
|
+
truncated: shown.length < options.length,
|
|
3333
|
+
blanks,
|
|
3334
|
+
columnType: column.type
|
|
3335
|
+
};
|
|
3336
|
+
}
|
|
3337
|
+
function keyOf2(draft, value) {
|
|
3338
|
+
return filterValueKey(value, draft.columnType);
|
|
3339
|
+
}
|
|
3340
|
+
function everyOption(draft) {
|
|
3341
|
+
return new Map(
|
|
3342
|
+
draft.options.map((option) => [keyOf2(draft, option.value), option.value])
|
|
3343
|
+
);
|
|
3344
|
+
}
|
|
3345
|
+
function initialFilterEditorDraft(shape, values) {
|
|
3346
|
+
const draft = {
|
|
3347
|
+
mode: "values",
|
|
3348
|
+
options: values.options,
|
|
3349
|
+
blanks: values.blanks,
|
|
3350
|
+
search: "",
|
|
3351
|
+
checked: everyOption(values),
|
|
3352
|
+
includeBlanks: values.blanks > 0,
|
|
3353
|
+
conditions: [],
|
|
3354
|
+
combinator: "and",
|
|
3355
|
+
columnType: values.columnType
|
|
3356
|
+
};
|
|
3357
|
+
switch (shape.kind) {
|
|
3358
|
+
case "values":
|
|
3359
|
+
return {
|
|
3360
|
+
...draft,
|
|
3361
|
+
checked: new Map(
|
|
3362
|
+
shape.values.filter((value) => !isEmptyCell(value)).map((value) => [keyOf2(draft, value), value])
|
|
3363
|
+
),
|
|
3364
|
+
includeBlanks: shape.includeBlanks
|
|
3365
|
+
};
|
|
3366
|
+
case "conditions":
|
|
3367
|
+
return {
|
|
3368
|
+
...draft,
|
|
3369
|
+
mode: "conditions",
|
|
3370
|
+
conditions: shape.conditions,
|
|
3371
|
+
combinator: shape.combinator
|
|
3372
|
+
};
|
|
3373
|
+
case "none":
|
|
3374
|
+
case "custom":
|
|
3375
|
+
return draft;
|
|
3376
|
+
}
|
|
3377
|
+
}
|
|
3378
|
+
function visibleFilterOptions(draft) {
|
|
3379
|
+
return draft.search === "" ? draft.options : draft.options.filter(
|
|
3380
|
+
(option) => matchesSearch(option.label, draft.search)
|
|
3381
|
+
);
|
|
3382
|
+
}
|
|
3383
|
+
function selectAllCoversBlanks(draft) {
|
|
3384
|
+
return draft.search === "" && draft.blanks > 0;
|
|
3385
|
+
}
|
|
3386
|
+
function selectAllState(draft) {
|
|
3387
|
+
const states = visibleFilterOptions(draft).map(
|
|
3388
|
+
(option) => draft.checked.has(keyOf2(draft, option.value))
|
|
3389
|
+
);
|
|
3390
|
+
if (selectAllCoversBlanks(draft)) {
|
|
3391
|
+
states.push(draft.includeBlanks);
|
|
3392
|
+
}
|
|
3393
|
+
if (states.length > 0 && states.every(Boolean)) {
|
|
3394
|
+
return "checked";
|
|
3395
|
+
}
|
|
3396
|
+
return states.some(Boolean) ? "mixed" : "unchecked";
|
|
3397
|
+
}
|
|
3398
|
+
function toggleAll(draft) {
|
|
3399
|
+
const check = selectAllState(draft) !== "checked";
|
|
3400
|
+
const checked = new Map(draft.checked);
|
|
3401
|
+
for (const option of visibleFilterOptions(draft)) {
|
|
3402
|
+
const key = keyOf2(draft, option.value);
|
|
3403
|
+
if (check) {
|
|
3404
|
+
checked.set(key, option.value);
|
|
3405
|
+
} else {
|
|
3406
|
+
checked.delete(key);
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3409
|
+
return {
|
|
3410
|
+
...draft,
|
|
3411
|
+
mode: "values",
|
|
3412
|
+
checked,
|
|
3413
|
+
includeBlanks: selectAllCoversBlanks(draft) ? check : draft.includeBlanks
|
|
3414
|
+
};
|
|
3415
|
+
}
|
|
3416
|
+
function filterEditorReducer(draft, action) {
|
|
3417
|
+
switch (action.type) {
|
|
3418
|
+
case "search":
|
|
3419
|
+
return { ...draft, search: action.search };
|
|
3420
|
+
case "toggleValue": {
|
|
3421
|
+
const key = keyOf2(draft, action.value);
|
|
3422
|
+
const checked = new Map(draft.checked);
|
|
3423
|
+
if (checked.has(key)) {
|
|
3424
|
+
checked.delete(key);
|
|
3425
|
+
} else {
|
|
3426
|
+
checked.set(key, action.value);
|
|
3427
|
+
}
|
|
3428
|
+
return { ...draft, mode: "values", checked };
|
|
3429
|
+
}
|
|
3430
|
+
case "toggleAll":
|
|
3431
|
+
return toggleAll(draft);
|
|
3432
|
+
case "setIncludeBlanks":
|
|
3433
|
+
return { ...draft, mode: "values", includeBlanks: action.includeBlanks };
|
|
3434
|
+
case "setConditions":
|
|
3435
|
+
return {
|
|
3436
|
+
...draft,
|
|
3437
|
+
mode: "conditions",
|
|
3438
|
+
conditions: action.conditions,
|
|
3439
|
+
combinator: action.combinator ?? draft.combinator
|
|
3440
|
+
};
|
|
3441
|
+
case "clear":
|
|
3442
|
+
return {
|
|
3443
|
+
...draft,
|
|
3444
|
+
search: "",
|
|
3445
|
+
checked: everyOption(draft),
|
|
3446
|
+
includeBlanks: draft.blanks > 0,
|
|
3447
|
+
conditions: []
|
|
3448
|
+
};
|
|
3449
|
+
}
|
|
3450
|
+
}
|
|
3451
|
+
function checksEverything(draft) {
|
|
3452
|
+
return draft.options.every(
|
|
3453
|
+
(option) => draft.checked.has(keyOf2(draft, option.value))
|
|
3454
|
+
) && (draft.includeBlanks || draft.blanks === 0);
|
|
3455
|
+
}
|
|
3456
|
+
function draftEntries(draft, columnId) {
|
|
3457
|
+
if (draft.mode === "conditions") {
|
|
3458
|
+
const conditions = draft.conditions.map((condition) => ({
|
|
3459
|
+
...condition,
|
|
3460
|
+
columnId
|
|
3461
|
+
}));
|
|
3462
|
+
return conditions.length > 1 ? [{ combinator: draft.combinator, entries: conditions }] : conditions;
|
|
3463
|
+
}
|
|
3464
|
+
if (checksEverything(draft)) {
|
|
3465
|
+
return [];
|
|
3466
|
+
}
|
|
3467
|
+
const picked = {
|
|
3468
|
+
columnId,
|
|
3469
|
+
operator: "in",
|
|
3470
|
+
value: [...draft.checked.values()]
|
|
3471
|
+
};
|
|
3472
|
+
return draft.includeBlanks ? [
|
|
3473
|
+
{
|
|
3474
|
+
combinator: "or",
|
|
3475
|
+
entries: [picked, { columnId, operator: "isEmpty" }]
|
|
3476
|
+
}
|
|
3477
|
+
] : [picked];
|
|
3478
|
+
}
|
|
3479
|
+
function draftToFilter(draft, columnId, current) {
|
|
3480
|
+
const replacement = draftEntries(draft, columnId);
|
|
3481
|
+
const first = current.findIndex((entry) => touchesColumn(entry, columnId));
|
|
3482
|
+
if (first === -1) {
|
|
3483
|
+
return replacement.length === 0 ? current : [...current, ...replacement];
|
|
3484
|
+
}
|
|
3485
|
+
const kept = current.filter((entry) => !touchesColumn(entry, columnId));
|
|
3486
|
+
return [...kept.slice(0, first), ...replacement, ...kept.slice(first)];
|
|
3487
|
+
}
|
|
3488
|
+
|
|
2188
3489
|
// src/commands/builtInCommands.ts
|
|
2189
3490
|
function isOn(context, areas) {
|
|
2190
3491
|
return areas.includes(context.target.area);
|
|
@@ -2207,6 +3508,10 @@ function groupedColumn(context) {
|
|
|
2207
3508
|
const column = columnOn(context, ["header", "group"]);
|
|
2208
3509
|
return column !== null && isGroupedBy(context, column.id) ? column : null;
|
|
2209
3510
|
}
|
|
3511
|
+
function filterableColumn(context) {
|
|
3512
|
+
const column = columnOn(context, ["header"]);
|
|
3513
|
+
return column !== null && resolveColumnFilterMenu(context.options, column.column) !== null ? column : null;
|
|
3514
|
+
}
|
|
2210
3515
|
function hideableColumn(context) {
|
|
2211
3516
|
const column = columnOn(context, ["header"]);
|
|
2212
3517
|
return column !== null && column.column.hideable !== false ? column : null;
|
|
@@ -2261,6 +3566,63 @@ function columnCommand({
|
|
|
2261
3566
|
}
|
|
2262
3567
|
};
|
|
2263
3568
|
}
|
|
3569
|
+
var EXPORT_AREAS = ["grid", "toolbar", "body", "cell"];
|
|
3570
|
+
function exportCommand({
|
|
3571
|
+
id,
|
|
3572
|
+
format,
|
|
3573
|
+
label,
|
|
3574
|
+
selection = false
|
|
3575
|
+
}) {
|
|
3576
|
+
return {
|
|
3577
|
+
id,
|
|
3578
|
+
label: ({ messages }) => label(messages),
|
|
3579
|
+
isVisible: (context) => isOn(context, EXPORT_AREAS) && resolveExportWriters(context.options.exportWriters).has(format) && (!selection || context.state.rowSelection.length > 0),
|
|
3580
|
+
isEnabled: (context) => (selection ? context.selectedRows() : context.view.rows).length > 0,
|
|
3581
|
+
execute: (context) => {
|
|
3582
|
+
const { export: defaults = {}, exportWriters } = context.options;
|
|
3583
|
+
const file = exportFile(
|
|
3584
|
+
context,
|
|
3585
|
+
format,
|
|
3586
|
+
selection ? { ...defaults, scope: "selection" } : defaults,
|
|
3587
|
+
resolveExportWriters(exportWriters)
|
|
3588
|
+
);
|
|
3589
|
+
if (file !== null) {
|
|
3590
|
+
context.host.saveFile(file);
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
};
|
|
3594
|
+
}
|
|
3595
|
+
function cellRequest(context, kind) {
|
|
3596
|
+
const { target } = context;
|
|
3597
|
+
if (target.area !== "cell") {
|
|
3598
|
+
return null;
|
|
3599
|
+
}
|
|
3600
|
+
return kind === "cell" ? { kind, rowId: target.rowId, columnId: target.columnId } : { kind, rowId: target.rowId };
|
|
3601
|
+
}
|
|
3602
|
+
function copyCommand({
|
|
3603
|
+
id,
|
|
3604
|
+
label,
|
|
3605
|
+
request,
|
|
3606
|
+
isEnabled
|
|
3607
|
+
}) {
|
|
3608
|
+
function contentFor(context) {
|
|
3609
|
+
const asked = request(context);
|
|
3610
|
+
return asked === null ? null : copyContent(context, asked);
|
|
3611
|
+
}
|
|
3612
|
+
return {
|
|
3613
|
+
id,
|
|
3614
|
+
label: ({ messages }) => label(messages),
|
|
3615
|
+
icon: "copy",
|
|
3616
|
+
isVisible: (context) => request(context) !== null,
|
|
3617
|
+
isEnabled: isEnabled ?? ((context) => contentFor(context) !== null),
|
|
3618
|
+
execute: (context) => {
|
|
3619
|
+
const content = contentFor(context);
|
|
3620
|
+
if (content !== null) {
|
|
3621
|
+
context.host.writeClipboard(content);
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
};
|
|
3625
|
+
}
|
|
2264
3626
|
function sortCommand(direction) {
|
|
2265
3627
|
return columnCommand({
|
|
2266
3628
|
id: direction === "asc" ? "sort.ascending" : "sort.descending",
|
|
@@ -2382,6 +3744,29 @@ function builtInCommands() {
|
|
|
2382
3744
|
host.openPanel("columnChooser", target);
|
|
2383
3745
|
}
|
|
2384
3746
|
},
|
|
3747
|
+
// Opened below the header it was asked for, as the chooser is.
|
|
3748
|
+
columnCommand({
|
|
3749
|
+
id: "filter.open",
|
|
3750
|
+
label: ({ messages }) => messages.openFilter,
|
|
3751
|
+
find: filterableColumn,
|
|
3752
|
+
execute: (_column, { host, target }) => {
|
|
3753
|
+
host.openPanel("filter", target);
|
|
3754
|
+
}
|
|
3755
|
+
}),
|
|
3756
|
+
// Every entry about the column goes, whichever editor wrote it — or
|
|
3757
|
+
// none did, as with a predicate set in code — as applying an editor
|
|
3758
|
+
// replaces them all.
|
|
3759
|
+
columnCommand({
|
|
3760
|
+
id: "filter.clear",
|
|
3761
|
+
label: ({ messages }) => messages.clearColumnFilter,
|
|
3762
|
+
find: filterableColumn,
|
|
3763
|
+
isEnabled: (column, { state }) => isColumnFiltered(state.filter, column.id),
|
|
3764
|
+
execute: (column, { actions, state }) => {
|
|
3765
|
+
actions.setFilter(
|
|
3766
|
+
state.filter.filter((entry) => !touchesColumn(entry, column.id))
|
|
3767
|
+
);
|
|
3768
|
+
}
|
|
3769
|
+
}),
|
|
2385
3770
|
{
|
|
2386
3771
|
id: "selection.selectAllRows",
|
|
2387
3772
|
label: ({ messages }) => messages.selectAllRows,
|
|
@@ -2408,6 +3793,75 @@ function builtInCommands() {
|
|
|
2408
3793
|
execute: ({ actions }) => {
|
|
2409
3794
|
actions.setFilter([]);
|
|
2410
3795
|
}
|
|
3796
|
+
},
|
|
3797
|
+
exportCommand({
|
|
3798
|
+
id: "export.csv",
|
|
3799
|
+
format: "csv",
|
|
3800
|
+
label: ({ exportCsv }) => exportCsv
|
|
3801
|
+
}),
|
|
3802
|
+
exportCommand({
|
|
3803
|
+
id: "export.json",
|
|
3804
|
+
format: "json",
|
|
3805
|
+
label: ({ exportJson }) => exportJson
|
|
3806
|
+
}),
|
|
3807
|
+
exportCommand({
|
|
3808
|
+
id: "export.xlsx",
|
|
3809
|
+
format: "xlsx",
|
|
3810
|
+
label: ({ exportXlsx }) => exportXlsx
|
|
3811
|
+
}),
|
|
3812
|
+
exportCommand({
|
|
3813
|
+
id: "export.pdf",
|
|
3814
|
+
format: "pdf",
|
|
3815
|
+
label: ({ exportPdf }) => exportPdf
|
|
3816
|
+
}),
|
|
3817
|
+
exportCommand({
|
|
3818
|
+
id: "exportSelection.csv",
|
|
3819
|
+
format: "csv",
|
|
3820
|
+
label: ({ exportSelectionCsv }) => exportSelectionCsv,
|
|
3821
|
+
selection: true
|
|
3822
|
+
}),
|
|
3823
|
+
exportCommand({
|
|
3824
|
+
id: "exportSelection.json",
|
|
3825
|
+
format: "json",
|
|
3826
|
+
label: ({ exportSelectionJson }) => exportSelectionJson,
|
|
3827
|
+
selection: true
|
|
3828
|
+
}),
|
|
3829
|
+
exportCommand({
|
|
3830
|
+
id: "exportSelection.xlsx",
|
|
3831
|
+
format: "xlsx",
|
|
3832
|
+
label: ({ exportSelectionXlsx }) => exportSelectionXlsx,
|
|
3833
|
+
selection: true
|
|
3834
|
+
}),
|
|
3835
|
+
copyCommand({
|
|
3836
|
+
id: "copy.cell",
|
|
3837
|
+
label: ({ copyCell }) => copyCell,
|
|
3838
|
+
request: (context) => cellRequest(context, "cell")
|
|
3839
|
+
}),
|
|
3840
|
+
copyCommand({
|
|
3841
|
+
id: "copy.row",
|
|
3842
|
+
label: ({ copyRow }) => copyRow,
|
|
3843
|
+
request: (context) => cellRequest(context, "row")
|
|
3844
|
+
}),
|
|
3845
|
+
// Shown wherever the grid as a whole is asked for, as the exports are,
|
|
3846
|
+
// once anything can be selected; enabled once something is.
|
|
3847
|
+
copyCommand({
|
|
3848
|
+
id: "copy.selection",
|
|
3849
|
+
label: ({ copySelection }) => copySelection,
|
|
3850
|
+
request: (context) => isOn(context, EXPORT_AREAS) && isAnythingSelectable(context.options.selectable) ? { kind: "selection" } : null,
|
|
3851
|
+
isEnabled: canCopySelection
|
|
3852
|
+
}),
|
|
3853
|
+
// Shown where the exports are, under the grid's `print` defaults. A grid
|
|
3854
|
+
// with no rows still prints its header; one with no columns, nothing.
|
|
3855
|
+
{
|
|
3856
|
+
id: "print",
|
|
3857
|
+
label: ({ messages }) => messages.print,
|
|
3858
|
+
icon: "print",
|
|
3859
|
+
isVisible: (context) => isOn(context, EXPORT_AREAS),
|
|
3860
|
+
isEnabled: ({ view }) => view.columns.length > 0,
|
|
3861
|
+
execute: (context) => {
|
|
3862
|
+
const { print: options = {} } = context.options;
|
|
3863
|
+
context.host.print(exportPrintDocument(context, options), options);
|
|
3864
|
+
}
|
|
2411
3865
|
}
|
|
2412
3866
|
];
|
|
2413
3867
|
}
|
|
@@ -2554,6 +4008,9 @@ var defaultContextMenu = {
|
|
|
2554
4008
|
"sort.descending",
|
|
2555
4009
|
"sort.clear",
|
|
2556
4010
|
"separator",
|
|
4011
|
+
"filter.open",
|
|
4012
|
+
"filter.clear",
|
|
4013
|
+
"separator",
|
|
2557
4014
|
"group.add",
|
|
2558
4015
|
"group.remove",
|
|
2559
4016
|
"separator",
|
|
@@ -2564,6 +4021,10 @@ var defaultContextMenu = {
|
|
|
2564
4021
|
"column.choose"
|
|
2565
4022
|
],
|
|
2566
4023
|
cell: [
|
|
4024
|
+
"copy.cell",
|
|
4025
|
+
"copy.row",
|
|
4026
|
+
"copy.selection",
|
|
4027
|
+
"separator",
|
|
2567
4028
|
"selection.selectAllRows",
|
|
2568
4029
|
"selection.clear",
|
|
2569
4030
|
"separator",
|
|
@@ -2680,6 +4141,23 @@ function toolbarEntries(toolbar) {
|
|
|
2680
4141
|
function isSpacer(entry) {
|
|
2681
4142
|
return entry.type === "spacer";
|
|
2682
4143
|
}
|
|
4144
|
+
function exportMenu() {
|
|
4145
|
+
return {
|
|
4146
|
+
type: "submenu",
|
|
4147
|
+
id: "export",
|
|
4148
|
+
label: ({ messages }) => messages.exportMenu,
|
|
4149
|
+
items: [
|
|
4150
|
+
"export.csv",
|
|
4151
|
+
"export.json",
|
|
4152
|
+
"export.xlsx",
|
|
4153
|
+
"export.pdf",
|
|
4154
|
+
"separator",
|
|
4155
|
+
"exportSelection.csv",
|
|
4156
|
+
"exportSelection.json",
|
|
4157
|
+
"exportSelection.xlsx"
|
|
4158
|
+
]
|
|
4159
|
+
};
|
|
4160
|
+
}
|
|
2683
4161
|
function resolveToolbar(entries, options) {
|
|
2684
4162
|
const { commands, contextFor } = options;
|
|
2685
4163
|
function resolveEntry(entry, index) {
|
|
@@ -2695,11 +4173,12 @@ function resolveToolbar(entries, options) {
|
|
|
2695
4173
|
if (entry === "separator") {
|
|
2696
4174
|
return { type: "separator", key: `separator-${String(index)}` };
|
|
2697
4175
|
}
|
|
2698
|
-
const
|
|
4176
|
+
const menuEntry = entry === "export" ? exportMenu() : entry;
|
|
4177
|
+
const resolved = resolveMenuEntry(menuEntry, index, {
|
|
2699
4178
|
commands,
|
|
2700
4179
|
context: contextFor({
|
|
2701
4180
|
area: "toolbar",
|
|
2702
|
-
itemId: typeof
|
|
4181
|
+
itemId: typeof menuEntry === "string" ? menuEntry : menuEntry.id
|
|
2703
4182
|
})
|
|
2704
4183
|
});
|
|
2705
4184
|
if (resolved === null || resolved.type === "separator") {
|
|
@@ -2893,558 +4372,218 @@ function nextFocusForKey(key, modifiers, focus, rowCount, columnCount2, pageSize
|
|
|
2893
4372
|
return null;
|
|
2894
4373
|
}
|
|
2895
4374
|
}
|
|
2896
|
-
|
|
2897
|
-
// src/util/paginationWindow.ts
|
|
2898
|
-
function paginationWindow(currentPage, pageCount, options) {
|
|
2899
|
-
if (pageCount <= 0) {
|
|
2900
|
-
return [];
|
|
2901
|
-
}
|
|
2902
|
-
const boundaryCount = Math.max(0, options?.boundaryCount ?? 1);
|
|
2903
|
-
const siblingCount = Math.max(0, options?.siblingCount ?? 1);
|
|
2904
|
-
const current = Math.min(Math.max(currentPage, 1), pageCount);
|
|
2905
|
-
const pages = /* @__PURE__ */ new Set();
|
|
2906
|
-
for (let page = 1; page <= Math.min(boundaryCount, pageCount); page++) {
|
|
2907
|
-
pages.add(page);
|
|
2908
|
-
}
|
|
2909
|
-
for (let page = Math.max(pageCount - boundaryCount + 1, 1); page <= pageCount; page++) {
|
|
2910
|
-
pages.add(page);
|
|
2911
|
-
}
|
|
2912
|
-
for (let page = Math.max(current - siblingCount, 1); page <= Math.min(current + siblingCount, pageCount); page++) {
|
|
2913
|
-
pages.add(page);
|
|
2914
|
-
}
|
|
2915
|
-
const sorted = Array.from(pages).sort((a, b) => a - b);
|
|
2916
|
-
const entries = [];
|
|
2917
|
-
let previous;
|
|
2918
|
-
for (const page of sorted) {
|
|
2919
|
-
if (previous !== void 0) {
|
|
2920
|
-
if (page - previous === 2) {
|
|
2921
|
-
entries.push(previous + 1);
|
|
2922
|
-
} else if (page - previous > 2) {
|
|
2923
|
-
entries.push("ellipsis");
|
|
2924
|
-
}
|
|
2925
|
-
}
|
|
2926
|
-
entries.push(page);
|
|
2927
|
-
previous = page;
|
|
2928
|
-
}
|
|
2929
|
-
return entries;
|
|
2930
|
-
}
|
|
2931
|
-
|
|
2932
|
-
// src/util/columnChooser.ts
|
|
2933
|
-
function isHideable(column) {
|
|
2934
|
-
return column.column.hideable !== false;
|
|
2935
|
-
}
|
|
2936
|
-
function matchesSearch(label, search) {
|
|
2937
|
-
return label.toLowerCase().includes(search.toLowerCase());
|
|
2938
|
-
}
|
|
2939
|
-
function selectAllStateOf(states) {
|
|
2940
|
-
if (states.length > 0 && states.every(Boolean)) {
|
|
2941
|
-
return "checked";
|
|
2942
|
-
}
|
|
2943
|
-
return states.some(Boolean) ? "mixed" : "unchecked";
|
|
2944
|
-
}
|
|
2945
|
-
function resolveColumnChooser({
|
|
2946
|
-
columns,
|
|
2947
|
-
visibility,
|
|
2948
|
-
search = ""
|
|
2949
|
-
}) {
|
|
2950
|
-
const all = columns.map((column) => ({
|
|
2951
|
-
column,
|
|
2952
|
-
label: resolveColumnHeaderText(column.column),
|
|
2953
|
-
visible: isColumnVisible(column.column, visibility)
|
|
2954
|
-
}));
|
|
2955
|
-
const shownCount = all.filter(({ visible }) => visible).length;
|
|
2956
|
-
const matched = all.filter(({ label }) => matchesSearch(label, search));
|
|
2957
|
-
const entries = matched.map(
|
|
2958
|
-
({ column, label, visible }) => ({
|
|
2959
|
-
columnId: column.id,
|
|
2960
|
-
label,
|
|
2961
|
-
visible,
|
|
2962
|
-
disabled: visible && (!isHideable(column) || shownCount === 1)
|
|
2963
|
-
})
|
|
2964
|
-
);
|
|
2965
|
-
const covered = matched.filter(({ column }) => isHideable(column));
|
|
2966
|
-
const selectAll2 = selectAllStateOf(covered.map(({ visible }) => visible));
|
|
2967
|
-
return {
|
|
2968
|
-
entries,
|
|
2969
|
-
selectAll: selectAll2,
|
|
2970
|
-
toggleAll: toggleAllOf(covered, selectAll2, shownCount)
|
|
2971
|
-
};
|
|
2972
|
-
}
|
|
2973
|
-
function toggleAllOf(covered, selectAll2, shownCount) {
|
|
2974
|
-
const show = selectAll2 !== "checked";
|
|
2975
|
-
const changing = covered.filter(({ visible }) => visible !== show).map(({ column }) => column.id);
|
|
2976
|
-
const columnIds = !show && changing.length === shownCount ? changing.slice(1) : changing;
|
|
2977
|
-
return columnIds.length === 0 ? null : { visible: show, columnIds };
|
|
2978
|
-
}
|
|
2979
|
-
|
|
2980
|
-
// src/messages.ts
|
|
2981
|
-
function columnCount(count, change) {
|
|
2982
|
-
return count === 1 ? `1 column ${change}` : `${String(count)} columns ${change}`;
|
|
2983
|
-
}
|
|
2984
|
-
function searchResults(count) {
|
|
2985
|
-
if (count === 0) {
|
|
2986
|
-
return "No rows found";
|
|
2987
|
-
}
|
|
2988
|
-
return count === 1 ? "1 row found" : `${String(count)} rows found`;
|
|
2989
|
-
}
|
|
2990
|
-
function selectedCount(count, target) {
|
|
2991
|
-
const noun = target === "rows" ? "row" : "column";
|
|
2992
|
-
if (count === 0) {
|
|
2993
|
-
return `No ${noun}s selected`;
|
|
2994
|
-
}
|
|
2995
|
-
return count === 1 ? `1 ${noun} selected` : `${String(count)} ${noun}s selected`;
|
|
2996
|
-
}
|
|
2997
|
-
var defaultMessages = {
|
|
2998
|
-
pagerLabel: "Pagination",
|
|
2999
|
-
previousPage: "Previous",
|
|
3000
|
-
nextPage: "Next",
|
|
3001
|
-
pageSizeLabel: "Rows per page",
|
|
3002
|
-
pageButtonLabel: (page) => `Page ${String(page)}`,
|
|
3003
|
-
pageStatus: (page, pageCount) => `Page ${String(page)} of ${String(pageCount)}`,
|
|
3004
|
-
loadingMore: "Loading more\u2026",
|
|
3005
|
-
booleanTrue: "true",
|
|
3006
|
-
booleanFalse: "false",
|
|
3007
|
-
blankGroupValue: "(blank)",
|
|
3008
|
-
groupByBarLabel: "Grouped by",
|
|
3009
|
-
groupByBarPlaceholder: "Drag a column here to group by it",
|
|
3010
|
-
groupByChipLabel: (columnName2, level, levelCount) => levelCount > 1 ? `${columnName2}, level ${String(level)} of ${String(levelCount)}` : columnName2,
|
|
3011
|
-
removeGroupBy: (columnName2) => `Stop grouping by ${columnName2}`,
|
|
3012
|
-
columnResized: (columnName2, width) => `${columnName2}, ${String(width)} pixels wide`,
|
|
3013
|
-
columnMoved: (columnName2, position, columnCount2) => `${columnName2}, column ${String(position)} of ${String(columnCount2)}`,
|
|
3014
|
-
columnSorted: (columnName2, direction, key, keyCount) => {
|
|
3015
|
-
const sorted = `${columnName2} sorted ${direction === "asc" ? "ascending" : "descending"}`;
|
|
3016
|
-
return keyCount > 1 ? `${sorted}, key ${String(key)} of ${String(keyCount)}` : sorted;
|
|
3017
|
-
},
|
|
3018
|
-
sortCleared: (columnName2) => `${columnName2}, sort cleared`,
|
|
3019
|
-
groupedBy: (columnName2, level, levelCount) => levelCount > 1 ? `Grouped by ${columnName2}, level ${String(level)} of ${String(levelCount)}` : `Grouped by ${columnName2}`,
|
|
3020
|
-
groupingRemoved: (columnName2) => `${columnName2}, grouping removed`,
|
|
3021
|
-
groupExpanded: "Group expanded",
|
|
3022
|
-
groupCollapsed: "Group collapsed",
|
|
3023
|
-
allGroupsExpanded: "All groups expanded",
|
|
3024
|
-
allGroupsCollapsed: "All groups collapsed",
|
|
3025
|
-
selectedCount,
|
|
3026
|
-
cellSelected: (columnName2, rowNumber) => `${columnName2}, row ${String(rowNumber)}, selected`,
|
|
3027
|
-
columnHidden: (columnName2) => `${columnName2}, column hidden`,
|
|
3028
|
-
columnShown: (columnName2) => `${columnName2}, column shown`,
|
|
3029
|
-
columnsHidden: (count) => columnCount(count, "hidden"),
|
|
3030
|
-
columnsShown: (count) => columnCount(count, "shown"),
|
|
3031
|
-
columnsAutoFitted: (count) => columnCount(count, "autofitted"),
|
|
3032
|
-
headerMenuLabel: (columnName2) => `${columnName2} column menu`,
|
|
3033
|
-
cellMenuLabel: "Row menu",
|
|
3034
|
-
groupMenuLabel: "Group menu",
|
|
3035
|
-
bodyMenuLabel: "Grid menu",
|
|
3036
|
-
sortAscending: "Sort ascending",
|
|
3037
|
-
sortDescending: "Sort descending",
|
|
3038
|
-
clearSort: "Clear sort",
|
|
3039
|
-
clearAllSorting: "Clear all sorting",
|
|
3040
|
-
groupByColumn: (columnName2) => `Group by ${columnName2}`,
|
|
3041
|
-
ungroupAll: "Ungroup all",
|
|
3042
|
-
expandAllGroups: "Expand all groups",
|
|
3043
|
-
collapseAllGroups: "Collapse all groups",
|
|
3044
|
-
hideColumn: "Hide column",
|
|
3045
|
-
autoFitColumn: "Autofit column",
|
|
3046
|
-
autoFitAllColumns: "Autofit all columns",
|
|
3047
|
-
selectAllRows: "Select all rows",
|
|
3048
|
-
clearSelection: "Clear selection",
|
|
3049
|
-
clearFilters: "Clear filters",
|
|
3050
|
-
chooseColumns: "Choose columns",
|
|
3051
|
-
toolbarLabel: "Grid toolbar",
|
|
3052
|
-
searchLabel: "Search",
|
|
3053
|
-
searchPlaceholder: "Search\u2026",
|
|
3054
|
-
moreToolbarItems: "More",
|
|
3055
|
-
searchResults,
|
|
3056
|
-
columnChooserLabel: "Columns",
|
|
3057
|
-
columnChooserSearchLabel: "Search columns",
|
|
3058
|
-
showAllColumns: "Show all",
|
|
3059
|
-
noMatchingColumns: "No matching columns"
|
|
3060
|
-
};
|
|
3061
|
-
function resolveMessages(messages) {
|
|
3062
|
-
return messages === void 0 ? defaultMessages : { ...defaultMessages, ...messages };
|
|
3063
|
-
}
|
|
3064
|
-
|
|
3065
|
-
// src/util/format.ts
|
|
3066
|
-
var DATE_FIELDS = {
|
|
3067
|
-
year: "numeric",
|
|
3068
|
-
month: "numeric",
|
|
3069
|
-
day: "numeric"
|
|
3070
|
-
};
|
|
3071
|
-
var TIME_FIELDS = {
|
|
3072
|
-
hour: "numeric",
|
|
3073
|
-
minute: "numeric",
|
|
3074
|
-
second: "numeric"
|
|
3075
|
-
};
|
|
3076
|
-
var DATE_TIME_FIELDS = {
|
|
3077
|
-
...DATE_FIELDS,
|
|
3078
|
-
...TIME_FIELDS
|
|
3079
|
-
};
|
|
3080
|
-
var CURRENCY_DIGITS = {
|
|
3081
|
-
minimumFractionDigits: 2,
|
|
3082
|
-
maximumFractionDigits: 2
|
|
3083
|
-
};
|
|
3084
|
-
var NO_FORMAT = {};
|
|
3085
|
-
var formatters = /* @__PURE__ */ new WeakMap();
|
|
3086
|
-
function cached(format, key, create) {
|
|
3087
|
-
const owner = format ?? NO_FORMAT;
|
|
3088
|
-
let byKey = formatters.get(owner);
|
|
3089
|
-
if (byKey === void 0) {
|
|
3090
|
-
byKey = /* @__PURE__ */ new Map();
|
|
3091
|
-
formatters.set(owner, byKey);
|
|
3092
|
-
}
|
|
3093
|
-
const existing = byKey.get(key);
|
|
3094
|
-
if (existing !== void 0) {
|
|
3095
|
-
return existing;
|
|
3096
|
-
}
|
|
3097
|
-
const formatter = create();
|
|
3098
|
-
byKey.set(key, formatter);
|
|
3099
|
-
return formatter;
|
|
3100
|
-
}
|
|
3101
|
-
function localeKey(locale) {
|
|
3102
|
-
return typeof locale === "string" ? locale : locale?.join(",") ?? "";
|
|
3103
|
-
}
|
|
3104
|
-
function isNumericType(type) {
|
|
3105
|
-
return type === "number" || type === "decimal" || type === "currency" || type === "percent";
|
|
3106
|
-
}
|
|
3107
|
-
function numberOptions(type, format) {
|
|
3108
|
-
switch (type) {
|
|
3109
|
-
case "currency":
|
|
3110
|
-
return format?.currency === void 0 ? { ...CURRENCY_DIGITS, ...format } : { style: "currency", ...format };
|
|
3111
|
-
case "percent":
|
|
3112
|
-
return { style: "percent", ...format };
|
|
3113
|
-
default:
|
|
3114
|
-
return format ?? {};
|
|
3115
|
-
}
|
|
3116
|
-
}
|
|
3117
|
-
function dateOptions(type, format) {
|
|
3118
|
-
if (format !== void 0) {
|
|
3119
|
-
return format;
|
|
3120
|
-
}
|
|
3121
|
-
if (type === "date") return DATE_FIELDS;
|
|
3122
|
-
if (type === "time") return TIME_FIELDS;
|
|
3123
|
-
return DATE_TIME_FIELDS;
|
|
3124
|
-
}
|
|
3125
|
-
function formatNumber(value, type, format, locale) {
|
|
3126
|
-
const formatter = cached(
|
|
3127
|
-
format,
|
|
3128
|
-
`number|${type ?? ""}|${localeKey(locale)}`,
|
|
3129
|
-
() => new Intl.NumberFormat(
|
|
3130
|
-
locale,
|
|
3131
|
-
numberOptions(type, format)
|
|
3132
|
-
)
|
|
3133
|
-
);
|
|
3134
|
-
return formatter.format(value);
|
|
3135
|
-
}
|
|
3136
|
-
function formatDate(value, type, format, locale) {
|
|
3137
|
-
if (Number.isNaN(value.getTime())) {
|
|
3138
|
-
return String(value);
|
|
3139
|
-
}
|
|
3140
|
-
const formatter = cached(
|
|
3141
|
-
format,
|
|
3142
|
-
`date|${type ?? ""}|${localeKey(locale)}`,
|
|
3143
|
-
() => new Intl.DateTimeFormat(
|
|
3144
|
-
locale,
|
|
3145
|
-
dateOptions(type, format)
|
|
3146
|
-
)
|
|
3147
|
-
);
|
|
3148
|
-
return formatter.format(value);
|
|
3149
|
-
}
|
|
3150
|
-
function formatOther(value) {
|
|
3151
|
-
if (typeof value === "function") {
|
|
3152
|
-
return "(function)";
|
|
3153
|
-
}
|
|
3154
|
-
if (typeof value === "object" && value !== null) {
|
|
3155
|
-
try {
|
|
3156
|
-
return JSON.stringify(value);
|
|
3157
|
-
} catch {
|
|
3158
|
-
return Object.prototype.toString.call(value);
|
|
3159
|
-
}
|
|
3160
|
-
}
|
|
3161
|
-
return String(value);
|
|
3162
|
-
}
|
|
3163
|
-
function formatCellValue(value, column, locale, row, messages) {
|
|
3164
|
-
if (column.valueFormatter !== void 0) {
|
|
3165
|
-
return column.valueFormatter(value, row);
|
|
3166
|
-
}
|
|
3167
|
-
if (value === null || value === void 0) {
|
|
3168
|
-
return "";
|
|
3169
|
-
}
|
|
3170
|
-
if (typeof value === "boolean" && messages !== void 0) {
|
|
3171
|
-
return value ? messages.booleanTrue : messages.booleanFalse;
|
|
3172
|
-
}
|
|
3173
|
-
const { type, format } = column;
|
|
3174
|
-
const formatted = format !== void 0 || locale !== void 0;
|
|
3175
|
-
if (value instanceof Date) {
|
|
3176
|
-
return formatted ? formatDate(value, type, format, locale) : value.toLocaleString();
|
|
3177
|
-
}
|
|
3178
|
-
if (formatted && (typeof value === "number" || typeof value === "bigint") && isNumericType(type)) {
|
|
3179
|
-
return formatNumber(value, type, format, locale);
|
|
3180
|
-
}
|
|
3181
|
-
if (typeof value === "string") {
|
|
3182
|
-
return value;
|
|
3183
|
-
}
|
|
3184
|
-
return formatOther(value);
|
|
3185
|
-
}
|
|
3186
|
-
function aggregateFormatColumn(value, spec, column) {
|
|
3187
|
-
const plain = {
|
|
3188
|
-
field: spec.columnId,
|
|
3189
|
-
type: "number"
|
|
3190
|
-
};
|
|
3191
|
-
if (column === void 0 || spec.fn === "count" || spec.fn === "countDistinct") {
|
|
3192
|
-
return plain;
|
|
3193
|
-
}
|
|
3194
|
-
const numeric = typeof value === "number" || typeof value === "bigint";
|
|
3195
|
-
return column.valueFormatter === void 0 && numeric && !isNumericType(column.type) ? plain : column;
|
|
3196
|
-
}
|
|
3197
|
-
function formatAggregateValue(value, spec, column, locale) {
|
|
3198
|
-
const target = aggregateFormatColumn(value, spec, column);
|
|
3199
|
-
if (typeof value === "number" && target.valueFormatter === void 0 && target.format === void 0 && locale === void 0) {
|
|
3200
|
-
return value.toLocaleString();
|
|
3201
|
-
}
|
|
3202
|
-
return formatCellValue(value, target, locale);
|
|
3203
|
-
}
|
|
3204
|
-
|
|
3205
|
-
// src/util/filterEditor.ts
|
|
3206
|
-
function touchesColumn(entry, columnId) {
|
|
3207
|
-
return "combinator" in entry ? entry.entries.some((nested) => touchesColumn(nested, columnId)) : entry.columnId === columnId;
|
|
3208
|
-
}
|
|
3209
|
-
function isOperatorOn(entry, columnId) {
|
|
3210
|
-
return "operator" in entry && entry.columnId === columnId;
|
|
3211
|
-
}
|
|
3212
|
-
function isConditionOn(entry, columnId) {
|
|
3213
|
-
return isOperatorOn(entry, columnId) && entry.operator !== "in";
|
|
3214
|
-
}
|
|
3215
|
-
function valuesShape(entry, columnId) {
|
|
3216
|
-
const values = (candidate) => candidate !== void 0 && isOperatorOn(candidate, columnId) && candidate.operator === "in" && isScalarList(candidate.value) ? candidate.value : void 0;
|
|
3217
|
-
const blanks = (candidate) => candidate !== void 0 && isOperatorOn(candidate, columnId) && candidate.operator === "isEmpty";
|
|
3218
|
-
const alone = values(entry);
|
|
3219
|
-
if (alone !== void 0) {
|
|
3220
|
-
return { kind: "values", values: alone, includeBlanks: false };
|
|
3221
|
-
}
|
|
3222
|
-
if (!("combinator" in entry) || entry.combinator !== "or" || entry.entries.length !== 2) {
|
|
3223
|
-
return void 0;
|
|
3224
|
-
}
|
|
3225
|
-
const [first, second] = entry.entries;
|
|
3226
|
-
const listed = blanks(first) ? values(second) : values(first);
|
|
3227
|
-
return listed !== void 0 && (blanks(first) || blanks(second)) ? { kind: "values", values: listed, includeBlanks: true } : void 0;
|
|
3228
|
-
}
|
|
3229
|
-
function conditionsShape(touching, columnId) {
|
|
3230
|
-
const [only] = touching;
|
|
3231
|
-
const grouped = touching.length === 1 && only !== void 0 && "combinator" in only;
|
|
3232
|
-
const entries = grouped ? only.entries : touching;
|
|
3233
|
-
const combinator = grouped ? only.combinator : "and";
|
|
3234
|
-
if (entries.length === 0 || entries.length > 2) {
|
|
3235
|
-
return void 0;
|
|
3236
|
-
}
|
|
3237
|
-
const conditions = entries.filter((entry) => isConditionOn(entry, columnId));
|
|
3238
|
-
return conditions.length === entries.length ? { kind: "conditions", conditions, combinator } : void 0;
|
|
3239
|
-
}
|
|
3240
|
-
function describeColumnFilter(filter, columnId) {
|
|
3241
|
-
const touching = filter.filter((entry) => touchesColumn(entry, columnId));
|
|
3242
|
-
const [only] = touching;
|
|
3243
|
-
if (only === void 0) {
|
|
3244
|
-
return { kind: "none" };
|
|
4375
|
+
|
|
4376
|
+
// src/util/paginationWindow.ts
|
|
4377
|
+
function paginationWindow(currentPage, pageCount, options) {
|
|
4378
|
+
if (pageCount <= 0) {
|
|
4379
|
+
return [];
|
|
3245
4380
|
}
|
|
3246
|
-
|
|
4381
|
+
const boundaryCount = Math.max(0, Math.floor(options?.boundaryCount ?? 1));
|
|
4382
|
+
const siblingCount = Math.max(0, Math.floor(options?.siblingCount ?? 1));
|
|
4383
|
+
const slotCount = 2 * boundaryCount + 2 * siblingCount + 3;
|
|
4384
|
+
if (pageCount <= slotCount) {
|
|
4385
|
+
return Array.from({ length: pageCount }, (_, index) => index + 1);
|
|
4386
|
+
}
|
|
4387
|
+
const current = Math.min(Math.max(currentPage, 1), pageCount);
|
|
4388
|
+
const runStart = Math.min(
|
|
4389
|
+
Math.max(current - siblingCount, boundaryCount + 2),
|
|
4390
|
+
pageCount - boundaryCount - 1 - 2 * siblingCount
|
|
4391
|
+
);
|
|
4392
|
+
const runEnd = runStart + 2 * siblingCount;
|
|
4393
|
+
const entries = [];
|
|
4394
|
+
for (let page = 1; page <= boundaryCount; page++) {
|
|
4395
|
+
entries.push(page);
|
|
4396
|
+
}
|
|
4397
|
+
entries.push(runStart === boundaryCount + 2 ? boundaryCount + 1 : "ellipsis");
|
|
4398
|
+
for (let page = runStart; page <= runEnd; page++) {
|
|
4399
|
+
entries.push(page);
|
|
4400
|
+
}
|
|
4401
|
+
entries.push(
|
|
4402
|
+
runEnd === pageCount - boundaryCount - 1 ? pageCount - boundaryCount : "ellipsis"
|
|
4403
|
+
);
|
|
4404
|
+
for (let page = pageCount - boundaryCount + 1; page <= pageCount; page++) {
|
|
4405
|
+
entries.push(page);
|
|
4406
|
+
}
|
|
4407
|
+
return entries;
|
|
3247
4408
|
}
|
|
3248
|
-
|
|
3249
|
-
|
|
4409
|
+
|
|
4410
|
+
// src/util/columnChooser.ts
|
|
4411
|
+
function isHideable(column) {
|
|
4412
|
+
return column.column.hideable !== false;
|
|
3250
4413
|
}
|
|
3251
4414
|
function matchesSearch2(label, search) {
|
|
3252
4415
|
return label.toLowerCase().includes(search.toLowerCase());
|
|
3253
4416
|
}
|
|
3254
|
-
function
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
return { options: [], total: 0, truncated: false, blanks: 0 };
|
|
4417
|
+
function selectAllStateOf(states) {
|
|
4418
|
+
if (states.length > 0 && states.every(Boolean)) {
|
|
4419
|
+
return "checked";
|
|
3258
4420
|
}
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
4421
|
+
return states.some(Boolean) ? "mixed" : "unchecked";
|
|
4422
|
+
}
|
|
4423
|
+
function resolveColumnChooser({
|
|
4424
|
+
columns,
|
|
4425
|
+
visibility,
|
|
4426
|
+
search = ""
|
|
4427
|
+
}) {
|
|
4428
|
+
const all = columns.map((column) => ({
|
|
4429
|
+
column,
|
|
4430
|
+
label: resolveColumnHeaderText(column.column),
|
|
4431
|
+
visible: isColumnVisible(column.column, visibility)
|
|
4432
|
+
}));
|
|
4433
|
+
const shownCount = all.filter(({ visible }) => visible).length;
|
|
4434
|
+
const matched = all.filter(({ label }) => matchesSearch2(label, search));
|
|
4435
|
+
const entries = matched.map(
|
|
4436
|
+
({ column, label, visible }) => ({
|
|
4437
|
+
columnId: column.id,
|
|
4438
|
+
label,
|
|
4439
|
+
visible,
|
|
4440
|
+
disabled: visible && (!isHideable(column) || shownCount === 1)
|
|
4441
|
+
})
|
|
3262
4442
|
);
|
|
3263
|
-
const
|
|
3264
|
-
|
|
3265
|
-
for (const row of rows) {
|
|
3266
|
-
if (keep !== void 0 && !keep(row)) {
|
|
3267
|
-
continue;
|
|
3268
|
-
}
|
|
3269
|
-
const value = accessDotted(row, column.field);
|
|
3270
|
-
if (isEmptyCell(value)) {
|
|
3271
|
-
blanks++;
|
|
3272
|
-
} else if (isOfferable(value)) {
|
|
3273
|
-
const key = filterValueKey(value, column.type);
|
|
3274
|
-
const bucket = buckets.get(key);
|
|
3275
|
-
if (bucket === void 0) {
|
|
3276
|
-
buckets.set(key, { value, row, count: 1 });
|
|
3277
|
-
} else {
|
|
3278
|
-
bucket.count++;
|
|
3279
|
-
}
|
|
3280
|
-
}
|
|
3281
|
-
}
|
|
3282
|
-
const { search = "", limit, locale } = query;
|
|
3283
|
-
const messages = resolveMessages(query.messages);
|
|
3284
|
-
const options = [...buckets.values()].sort((a, b) => compareValues(a.value, b.value, column.type)).map(({ value, row, count }) => ({
|
|
3285
|
-
value,
|
|
3286
|
-
label: formatCellValue(value, column, locale, row, messages),
|
|
3287
|
-
count
|
|
3288
|
-
})).filter((option) => matchesSearch2(option.label, search));
|
|
3289
|
-
const shown = limit === void 0 ? options : options.slice(0, limit);
|
|
4443
|
+
const covered = matched.filter(({ column }) => isHideable(column));
|
|
4444
|
+
const selectAll2 = selectAllStateOf(covered.map(({ visible }) => visible));
|
|
3290
4445
|
return {
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
blanks,
|
|
3295
|
-
columnType: column.type
|
|
4446
|
+
entries,
|
|
4447
|
+
selectAll: selectAll2,
|
|
4448
|
+
toggleAll: toggleAllOf(covered, selectAll2, shownCount)
|
|
3296
4449
|
};
|
|
3297
4450
|
}
|
|
3298
|
-
function
|
|
3299
|
-
|
|
3300
|
-
}
|
|
3301
|
-
|
|
3302
|
-
return
|
|
3303
|
-
draft.options.map((option) => [keyOf2(draft, option.value), option.value])
|
|
3304
|
-
);
|
|
4451
|
+
function toggleAllOf(covered, selectAll2, shownCount) {
|
|
4452
|
+
const show = selectAll2 !== "checked";
|
|
4453
|
+
const changing = covered.filter(({ visible }) => visible !== show).map(({ column }) => column.id);
|
|
4454
|
+
const columnIds = !show && changing.length === shownCount ? changing.slice(1) : changing;
|
|
4455
|
+
return columnIds.length === 0 ? null : { visible: show, columnIds };
|
|
3305
4456
|
}
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
switch (shape.kind) {
|
|
3319
|
-
case "values":
|
|
3320
|
-
return {
|
|
3321
|
-
...draft,
|
|
3322
|
-
checked: new Map(
|
|
3323
|
-
shape.values.filter((value) => !isEmptyCell(value)).map((value) => [keyOf2(draft, value), value])
|
|
3324
|
-
),
|
|
3325
|
-
includeBlanks: shape.includeBlanks
|
|
3326
|
-
};
|
|
3327
|
-
case "conditions":
|
|
3328
|
-
return {
|
|
3329
|
-
...draft,
|
|
3330
|
-
mode: "conditions",
|
|
3331
|
-
conditions: shape.conditions,
|
|
3332
|
-
combinator: shape.combinator
|
|
3333
|
-
};
|
|
3334
|
-
case "none":
|
|
3335
|
-
case "custom":
|
|
3336
|
-
return draft;
|
|
4457
|
+
|
|
4458
|
+
// src/filterMenu/conditions.ts
|
|
4459
|
+
var ROW_COUNT = 2;
|
|
4460
|
+
function rowOf(condition, type) {
|
|
4461
|
+
const { operator, value } = condition;
|
|
4462
|
+
if (isScalarList(value)) {
|
|
4463
|
+
const [low, high] = value;
|
|
4464
|
+
return {
|
|
4465
|
+
operator,
|
|
4466
|
+
text: formatFilterOperand(low, type),
|
|
4467
|
+
textTo: formatFilterOperand(high, type)
|
|
4468
|
+
};
|
|
3337
4469
|
}
|
|
4470
|
+
return { operator, text: formatFilterOperand(value, type), textTo: "" };
|
|
3338
4471
|
}
|
|
3339
|
-
function
|
|
3340
|
-
|
|
3341
|
-
|
|
4472
|
+
function conditionRowsFrom(shape, operators, type) {
|
|
4473
|
+
const filled = shape.kind === "conditions" ? shape.conditions.map((condition) => rowOf(condition, type)) : [];
|
|
4474
|
+
const [first] = operators;
|
|
4475
|
+
if (first === void 0) {
|
|
4476
|
+
return filled;
|
|
4477
|
+
}
|
|
4478
|
+
const blank = { operator: first, text: "", textTo: "" };
|
|
4479
|
+
return Array.from(
|
|
4480
|
+
{ length: ROW_COUNT },
|
|
4481
|
+
(_, index) => filled[index] ?? blank
|
|
3342
4482
|
);
|
|
3343
4483
|
}
|
|
3344
|
-
function
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
4484
|
+
function isEmptyRow(row) {
|
|
4485
|
+
switch (filterOperandArity(row.operator)) {
|
|
4486
|
+
case 0:
|
|
4487
|
+
return false;
|
|
4488
|
+
case 1:
|
|
4489
|
+
return row.text === "";
|
|
4490
|
+
case 2:
|
|
4491
|
+
return row.text === "" && row.textTo === "";
|
|
4492
|
+
}
|
|
4493
|
+
}
|
|
4494
|
+
function conditionOf(row, columnId, type) {
|
|
4495
|
+
const { operator } = row;
|
|
4496
|
+
switch (filterOperandArity(operator)) {
|
|
4497
|
+
case 0:
|
|
4498
|
+
return { columnId, operator };
|
|
4499
|
+
case 1: {
|
|
4500
|
+
const value = parseFilterOperand(row.text, type);
|
|
4501
|
+
return value === void 0 ? void 0 : { columnId, operator, value };
|
|
4502
|
+
}
|
|
4503
|
+
case 2: {
|
|
4504
|
+
const low = parseFilterOperand(row.text, type);
|
|
4505
|
+
const high = parseFilterOperand(row.textTo, type);
|
|
4506
|
+
return low === void 0 || high === void 0 ? void 0 : { columnId, operator, value: [low, high] };
|
|
4507
|
+
}
|
|
3356
4508
|
}
|
|
3357
|
-
return states.some(Boolean) ? "mixed" : "unchecked";
|
|
3358
4509
|
}
|
|
3359
|
-
function
|
|
3360
|
-
const
|
|
3361
|
-
const
|
|
3362
|
-
for (const
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
4510
|
+
function conditionsFromRows(rows, columnId, type) {
|
|
4511
|
+
const conditions = [];
|
|
4512
|
+
const invalid = [];
|
|
4513
|
+
for (const [index, row] of rows.entries()) {
|
|
4514
|
+
if (index > 0 && isEmptyRow(row)) {
|
|
4515
|
+
continue;
|
|
4516
|
+
}
|
|
4517
|
+
const condition = conditionOf(row, columnId, type);
|
|
4518
|
+
if (condition === void 0) {
|
|
4519
|
+
invalid.push(index);
|
|
3366
4520
|
} else {
|
|
3367
|
-
|
|
4521
|
+
conditions.push(condition);
|
|
3368
4522
|
}
|
|
3369
4523
|
}
|
|
3370
|
-
return {
|
|
3371
|
-
...draft,
|
|
3372
|
-
mode: "values",
|
|
3373
|
-
checked,
|
|
3374
|
-
includeBlanks: selectAllCoversBlanks(draft) ? check : draft.includeBlanks
|
|
3375
|
-
};
|
|
4524
|
+
return { conditions, invalid };
|
|
3376
4525
|
}
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
case "toggleValue": {
|
|
3382
|
-
const key = keyOf2(draft, action.value);
|
|
3383
|
-
const checked = new Map(draft.checked);
|
|
3384
|
-
if (checked.has(key)) {
|
|
3385
|
-
checked.delete(key);
|
|
3386
|
-
} else {
|
|
3387
|
-
checked.set(key, action.value);
|
|
3388
|
-
}
|
|
3389
|
-
return { ...draft, mode: "values", checked };
|
|
3390
|
-
}
|
|
3391
|
-
case "toggleAll":
|
|
3392
|
-
return toggleAll(draft);
|
|
3393
|
-
case "setIncludeBlanks":
|
|
3394
|
-
return { ...draft, mode: "values", includeBlanks: action.includeBlanks };
|
|
3395
|
-
case "setConditions":
|
|
3396
|
-
return {
|
|
3397
|
-
...draft,
|
|
3398
|
-
mode: "conditions",
|
|
3399
|
-
conditions: action.conditions,
|
|
3400
|
-
combinator: action.combinator ?? draft.combinator
|
|
3401
|
-
};
|
|
3402
|
-
case "clear":
|
|
3403
|
-
return {
|
|
3404
|
-
...draft,
|
|
3405
|
-
search: "",
|
|
3406
|
-
checked: everyOption(draft),
|
|
3407
|
-
includeBlanks: draft.blanks > 0,
|
|
3408
|
-
conditions: []
|
|
3409
|
-
};
|
|
3410
|
-
}
|
|
4526
|
+
|
|
4527
|
+
// src/filterMenu/valueCache.ts
|
|
4528
|
+
function sameSource(a, b) {
|
|
4529
|
+
return a.rows === b.rows && a.dataColumns === b.dataColumns && a.locale === b.locale && a.messages === b.messages;
|
|
3411
4530
|
}
|
|
3412
|
-
function
|
|
3413
|
-
return
|
|
3414
|
-
(option) => draft.checked.has(keyOf2(draft, option.value))
|
|
3415
|
-
) && (draft.includeBlanks || draft.blanks === 0);
|
|
4531
|
+
function sameEntries(a, b) {
|
|
4532
|
+
return a.length === b.length && a.every((entry, index) => entry === b[index]);
|
|
3416
4533
|
}
|
|
3417
|
-
function
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
4534
|
+
function createColumnValueOptionsCache() {
|
|
4535
|
+
let source;
|
|
4536
|
+
const lists = /* @__PURE__ */ new Map();
|
|
4537
|
+
return {
|
|
4538
|
+
get: (rows, dataColumns, filter, columnId, query = {}) => {
|
|
4539
|
+
const { locale, messages } = query;
|
|
4540
|
+
const current = { rows, dataColumns, locale, messages };
|
|
4541
|
+
if (source === void 0 || !sameSource(source, current)) {
|
|
4542
|
+
lists.clear();
|
|
4543
|
+
source = current;
|
|
4544
|
+
}
|
|
4545
|
+
const others = filter.filter((entry) => !touchesColumn(entry, columnId));
|
|
4546
|
+
const cached2 = lists.get(columnId);
|
|
4547
|
+
if (cached2 !== void 0 && sameEntries(cached2.others, others)) {
|
|
4548
|
+
return cached2.values;
|
|
4549
|
+
}
|
|
4550
|
+
const values = columnValueOptions(
|
|
4551
|
+
rows,
|
|
4552
|
+
dataColumns,
|
|
4553
|
+
filter,
|
|
4554
|
+
columnId,
|
|
4555
|
+
messages === void 0 ? { locale } : { locale, messages }
|
|
4556
|
+
);
|
|
4557
|
+
lists.set(columnId, { others, values });
|
|
4558
|
+
return values;
|
|
3437
4559
|
}
|
|
3438
|
-
|
|
4560
|
+
};
|
|
3439
4561
|
}
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
4562
|
+
|
|
4563
|
+
// src/filterMenu/checklist.ts
|
|
4564
|
+
function filterChecklist(draft, { valueLimit, blanksLabel }) {
|
|
4565
|
+
const visible = visibleFilterOptions(draft);
|
|
4566
|
+
const total = visible.length;
|
|
4567
|
+
if (draft.search === "" && total > valueLimit) {
|
|
4568
|
+
return { items: [], needsSearch: true, hiddenCount: 0, total };
|
|
4569
|
+
}
|
|
4570
|
+
const items = visible.slice(0, valueLimit).map(({ value, label, count }) => {
|
|
4571
|
+
const key = keyOf2(draft, value);
|
|
4572
|
+
const checked = draft.checked.has(key);
|
|
4573
|
+
return { kind: "value", key, value, label, count, checked };
|
|
4574
|
+
});
|
|
4575
|
+
const hiddenCount = total - items.length;
|
|
4576
|
+
if (selectAllCoversBlanks(draft)) {
|
|
4577
|
+
items.push({
|
|
4578
|
+
kind: "blanks",
|
|
4579
|
+
// Blank cells' own key, which no offered value has.
|
|
4580
|
+
key: keyOf2(draft, null),
|
|
4581
|
+
label: blanksLabel,
|
|
4582
|
+
count: draft.blanks,
|
|
4583
|
+
checked: draft.includeBlanks
|
|
4584
|
+
});
|
|
3445
4585
|
}
|
|
3446
|
-
|
|
3447
|
-
return [...kept.slice(0, first), ...replacement, ...kept.slice(first)];
|
|
4586
|
+
return { items, needsSearch: false, hiddenCount, total };
|
|
3448
4587
|
}
|
|
3449
4588
|
|
|
3450
4589
|
// src/util/virtualization.ts
|
|
@@ -3487,8 +4626,15 @@ function visibleRange(heights, estimatedHeight, scrollTop, viewportHeight, overs
|
|
|
3487
4626
|
offsetAfter
|
|
3488
4627
|
};
|
|
3489
4628
|
}
|
|
4629
|
+
|
|
4630
|
+
// src/presets.ts
|
|
4631
|
+
var excelFilter = {
|
|
4632
|
+
filterableColumns: true,
|
|
4633
|
+
filterMenu: { ui: "excel", showCounts: true }
|
|
4634
|
+
};
|
|
3490
4635
|
export {
|
|
3491
4636
|
DEFAULT_COLUMN_SIZES,
|
|
4637
|
+
DEFAULT_FILTER_VALUE_LIMIT,
|
|
3492
4638
|
HEADER_ROW,
|
|
3493
4639
|
KEYBOARD_STEP,
|
|
3494
4640
|
accessDotted,
|
|
@@ -3498,7 +4644,9 @@ export {
|
|
|
3498
4644
|
applyColumnVisibility,
|
|
3499
4645
|
applySelectionIntent,
|
|
3500
4646
|
beginColumnResize,
|
|
4647
|
+
buildExportTable,
|
|
3501
4648
|
buildKeyShortcuts,
|
|
4649
|
+
buildPrintDocument,
|
|
3502
4650
|
builtInCommands,
|
|
3503
4651
|
clampColumnWidth,
|
|
3504
4652
|
clampFocus,
|
|
@@ -3508,34 +4656,51 @@ export {
|
|
|
3508
4656
|
columnValueOptions,
|
|
3509
4657
|
compareValues,
|
|
3510
4658
|
computeAggregates,
|
|
4659
|
+
conditionRowsFrom,
|
|
4660
|
+
conditionsFromRows,
|
|
3511
4661
|
contextMenuEntries,
|
|
4662
|
+
copyContent,
|
|
4663
|
+
createColumnValueOptionsCache,
|
|
3512
4664
|
createCommandContext,
|
|
4665
|
+
createDefaultMessages,
|
|
3513
4666
|
createGridController,
|
|
3514
4667
|
createGridViewResolver,
|
|
4668
|
+
csvWriter,
|
|
3515
4669
|
defaultContextMenu,
|
|
4670
|
+
defaultFilterOperators,
|
|
3516
4671
|
defaultMessages,
|
|
3517
4672
|
defaultToolbar,
|
|
3518
4673
|
defineColumnsFromRows,
|
|
3519
4674
|
describeColumnFilter,
|
|
3520
4675
|
diffSelection,
|
|
3521
4676
|
draftToFilter,
|
|
4677
|
+
excelFilter,
|
|
3522
4678
|
expandAllGroups,
|
|
4679
|
+
exportFile,
|
|
4680
|
+
exportPrintDocument,
|
|
4681
|
+
filterChecklist,
|
|
3523
4682
|
filterEditorReducer,
|
|
4683
|
+
filterOperandArity,
|
|
4684
|
+
filterOperatorFamily,
|
|
3524
4685
|
filterQueryFor,
|
|
3525
4686
|
filterRows,
|
|
3526
4687
|
fitColumnsToWidth,
|
|
3527
4688
|
fitToolbarItems,
|
|
3528
4689
|
formatAggregateValue,
|
|
3529
4690
|
formatCellValue,
|
|
4691
|
+
formatFilterOperand,
|
|
4692
|
+
formatGroupValue,
|
|
3530
4693
|
getColumnId,
|
|
3531
4694
|
groupRowId,
|
|
3532
4695
|
groupRows,
|
|
3533
4696
|
hasContextMenu,
|
|
3534
4697
|
initialFilterEditorDraft,
|
|
3535
4698
|
intentOf,
|
|
4699
|
+
isColumnFiltered,
|
|
3536
4700
|
isColumnVisible,
|
|
3537
4701
|
isPinnedToolbarItem,
|
|
3538
4702
|
isSameCell,
|
|
4703
|
+
jsonWriter,
|
|
3539
4704
|
matchesQuery,
|
|
3540
4705
|
moveColumnBefore,
|
|
3541
4706
|
moveGroupByBefore,
|
|
@@ -3545,9 +4710,11 @@ export {
|
|
|
3545
4710
|
nextMenuIndex,
|
|
3546
4711
|
paginateRows,
|
|
3547
4712
|
paginationWindow,
|
|
4713
|
+
parseFilterOperand,
|
|
3548
4714
|
resolveCell,
|
|
3549
4715
|
resolveColumnChooser,
|
|
3550
4716
|
resolveColumnConstraints,
|
|
4717
|
+
resolveColumnFilterMenu,
|
|
3551
4718
|
resolveColumnHeaderText,
|
|
3552
4719
|
resolveColumnLabel,
|
|
3553
4720
|
resolveColumnWidths,
|
|
@@ -3555,6 +4722,7 @@ export {
|
|
|
3555
4722
|
resolveCommands,
|
|
3556
4723
|
resolveDataColumns,
|
|
3557
4724
|
resolveDropBefore,
|
|
4725
|
+
resolveExportWriters,
|
|
3558
4726
|
resolveGridView,
|
|
3559
4727
|
resolveKeyboardDropTarget,
|
|
3560
4728
|
resolveMenu,
|
|
@@ -3580,6 +4748,10 @@ export {
|
|
|
3580
4748
|
sortPriorityFor,
|
|
3581
4749
|
sortRows,
|
|
3582
4750
|
splitToolbarItems,
|
|
4751
|
+
toCsv,
|
|
4752
|
+
toHtmlTable,
|
|
4753
|
+
toJson,
|
|
4754
|
+
toTsv,
|
|
3583
4755
|
toggleCellSelection,
|
|
3584
4756
|
toggleColumnSort,
|
|
3585
4757
|
toggleGroupExpansion,
|