@ai-matrx/design-system 0.25.0 → 0.27.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/CHANGELOG.md +94 -0
- package/dist/data-table/copy-helpers.cjs.map +1 -1
- package/dist/data-table/copy-helpers.d.cts +3 -1
- package/dist/data-table/copy-helpers.d.ts +3 -1
- package/dist/data-table/copy-helpers.js.map +1 -1
- package/dist/data-table/data-row-inspector.cjs.map +1 -1
- package/dist/data-table/data-row-inspector.js.map +1 -1
- package/dist/data-table/data-row-window.cjs.map +1 -1
- package/dist/data-table/data-row-window.js.map +1 -1
- package/dist/data-table/date-filter.cjs +145 -0
- package/dist/data-table/date-filter.cjs.map +1 -0
- package/dist/data-table/date-filter.d.cts +31 -0
- package/dist/data-table/date-filter.d.ts +31 -0
- package/dist/data-table/date-filter.js +125 -0
- package/dist/data-table/date-filter.js.map +1 -0
- package/dist/data-table/facets.cjs +118 -0
- package/dist/data-table/facets.cjs.map +1 -0
- package/dist/data-table/facets.d.cts +100 -0
- package/dist/data-table/facets.d.ts +100 -0
- package/dist/data-table/facets.js +98 -0
- package/dist/data-table/facets.js.map +1 -0
- package/dist/data-table/filter-engine.cjs +88 -0
- package/dist/data-table/filter-engine.cjs.map +1 -1
- package/dist/data-table/filter-engine.d.cts +3 -1
- package/dist/data-table/filter-engine.d.ts +3 -1
- package/dist/data-table/filter-engine.js +88 -0
- package/dist/data-table/filter-engine.js.map +1 -1
- package/dist/data-table/host.cjs.map +1 -1
- package/dist/data-table/host.d.cts +14 -3
- package/dist/data-table/host.d.ts +14 -3
- package/dist/data-table/host.js.map +1 -1
- package/dist/data-table/index.cjs +918 -152
- package/dist/data-table/index.cjs.map +1 -1
- package/dist/data-table/index.d.cts +5 -2
- package/dist/data-table/index.d.ts +5 -2
- package/dist/data-table/index.js +956 -189
- package/dist/data-table/index.js.map +1 -1
- package/dist/data-table/infer-filter.cjs +2 -0
- package/dist/data-table/infer-filter.cjs.map +1 -1
- package/dist/data-table/infer-filter.d.cts +4 -2
- package/dist/data-table/infer-filter.d.ts +4 -2
- package/dist/data-table/infer-filter.js +2 -0
- package/dist/data-table/infer-filter.js.map +1 -1
- package/dist/data-table/layered-filters.d.cts +3 -1
- package/dist/data-table/layered-filters.d.ts +3 -1
- package/dist/data-table/menu-targets.cjs +77 -0
- package/dist/data-table/menu-targets.cjs.map +1 -0
- package/dist/data-table/menu-targets.d.cts +108 -0
- package/dist/data-table/menu-targets.d.ts +108 -0
- package/dist/data-table/menu-targets.js +57 -0
- package/dist/data-table/menu-targets.js.map +1 -0
- package/dist/data-table/pagination.cjs.map +1 -1
- package/dist/data-table/pagination.js.map +1 -1
- package/dist/data-table/query-control.cjs.map +1 -1
- package/dist/data-table/query-control.d.cts +3 -1
- package/dist/data-table/query-control.d.ts +3 -1
- package/dist/data-table/query-control.js.map +1 -1
- package/dist/data-table/spreadsheet.cjs +61 -13
- package/dist/data-table/spreadsheet.cjs.map +1 -1
- package/dist/data-table/spreadsheet.d.cts +36 -1
- package/dist/data-table/spreadsheet.d.ts +36 -1
- package/dist/data-table/spreadsheet.js +61 -13
- package/dist/data-table/spreadsheet.js.map +1 -1
- package/dist/data-table/types.cjs.map +1 -1
- package/dist/data-table/types.d.cts +3 -1
- package/dist/data-table/types.d.ts +3 -1
- package/dist/data-table/url-state.d.cts +3 -1
- package/dist/data-table/url-state.d.ts +3 -1
- package/dist/data-table/uuid-cell.cjs.map +1 -1
- package/dist/data-table/uuid-cell.js.map +1 -1
- package/dist/data-table/xlsx.cjs.map +1 -1
- package/dist/data-table/xlsx.d.cts +3 -1
- package/dist/data-table/xlsx.d.ts +3 -1
- package/dist/data-table/xlsx.js.map +1 -1
- package/dist/field-formats/index.cjs +15 -0
- package/dist/field-formats/index.cjs.map +1 -1
- package/dist/field-formats/index.js +15 -0
- package/dist/field-formats/index.js.map +1 -1
- package/dist/{types-nlLCMiqd.d.ts → types-D9JBR6ZU.d.ts} +118 -5
- package/dist/{types-CmQrOz-T.d.cts → types-jQddSUnj.d.cts} +118 -5
- package/package.json +31 -1
package/dist/data-table/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
useId as useId2,
|
|
11
11
|
useLayoutEffect as useLayoutEffect2,
|
|
12
12
|
useMemo as useMemo8,
|
|
13
|
-
useRef as
|
|
13
|
+
useRef as useRef15,
|
|
14
14
|
useState as useState22
|
|
15
15
|
} from "react";
|
|
16
16
|
import {
|
|
@@ -5043,6 +5043,124 @@ function layeredFilterRuleSummary(rule, fields) {
|
|
|
5043
5043
|
return rule.operator === "between" ? `${fieldLabel} ${operator} ${value} and ${rule.valueTo ?? ""}` : `${fieldLabel} ${operator} ${value}`;
|
|
5044
5044
|
}
|
|
5045
5045
|
|
|
5046
|
+
// src/data-table/date-filter.ts
|
|
5047
|
+
var TIME_RANGE_PRESET_VALUES = [
|
|
5048
|
+
"all",
|
|
5049
|
+
"1m",
|
|
5050
|
+
"15m",
|
|
5051
|
+
"30m",
|
|
5052
|
+
"1h",
|
|
5053
|
+
"2h",
|
|
5054
|
+
"6h",
|
|
5055
|
+
"12h",
|
|
5056
|
+
"today",
|
|
5057
|
+
"yesterday",
|
|
5058
|
+
"this_week",
|
|
5059
|
+
"this_month",
|
|
5060
|
+
"this_year",
|
|
5061
|
+
"older_1m",
|
|
5062
|
+
"older_15m",
|
|
5063
|
+
"older_30m",
|
|
5064
|
+
"older_1h",
|
|
5065
|
+
"older_2h",
|
|
5066
|
+
"older_6h",
|
|
5067
|
+
"older_12h",
|
|
5068
|
+
"older_today",
|
|
5069
|
+
"older_this_week",
|
|
5070
|
+
"older_this_month",
|
|
5071
|
+
"older_this_year"
|
|
5072
|
+
];
|
|
5073
|
+
var TIME_RANGE_PRESETS = [
|
|
5074
|
+
{ value: "all", label: "All time", group: "all" },
|
|
5075
|
+
{ value: "1m", label: "Last minute", group: "recent" },
|
|
5076
|
+
{ value: "15m", label: "Last 15 minutes", group: "recent" },
|
|
5077
|
+
{ value: "30m", label: "Last 30 minutes", group: "recent" },
|
|
5078
|
+
{ value: "1h", label: "Last hour", group: "recent" },
|
|
5079
|
+
{ value: "2h", label: "Last 2 hours", group: "recent" },
|
|
5080
|
+
{ value: "6h", label: "Last 6 hours", group: "recent" },
|
|
5081
|
+
{ value: "12h", label: "Last 12 hours", group: "recent" },
|
|
5082
|
+
{ value: "today", label: "Today", group: "calendar" },
|
|
5083
|
+
{ value: "yesterday", label: "Yesterday", group: "calendar" },
|
|
5084
|
+
{ value: "this_week", label: "This week", group: "calendar" },
|
|
5085
|
+
{ value: "this_month", label: "This month", group: "calendar" },
|
|
5086
|
+
{ value: "this_year", label: "This year", group: "calendar" },
|
|
5087
|
+
{ value: "older_1m", label: "Older than 1 minute", group: "older" },
|
|
5088
|
+
{ value: "older_15m", label: "Older than 15 minutes", group: "older" },
|
|
5089
|
+
{ value: "older_30m", label: "Older than 30 minutes", group: "older" },
|
|
5090
|
+
{ value: "older_1h", label: "Older than 1 hour", group: "older" },
|
|
5091
|
+
{ value: "older_2h", label: "Older than 2 hours", group: "older" },
|
|
5092
|
+
{ value: "older_6h", label: "Older than 6 hours", group: "older" },
|
|
5093
|
+
{ value: "older_12h", label: "Older than 12 hours", group: "older" },
|
|
5094
|
+
{ value: "older_today", label: "Before today", group: "older" },
|
|
5095
|
+
{ value: "older_this_week", label: "Before this week", group: "older" },
|
|
5096
|
+
{ value: "older_this_month", label: "Before this month", group: "older" },
|
|
5097
|
+
{ value: "older_this_year", label: "Before this year", group: "older" }
|
|
5098
|
+
];
|
|
5099
|
+
function startOfDay(date) {
|
|
5100
|
+
const next = new Date(date);
|
|
5101
|
+
next.setHours(0, 0, 0, 0);
|
|
5102
|
+
return next;
|
|
5103
|
+
}
|
|
5104
|
+
function startOfWeek(date) {
|
|
5105
|
+
const next = startOfDay(date);
|
|
5106
|
+
next.setDate(next.getDate() - (next.getDay() === 0 ? 6 : next.getDay() - 1));
|
|
5107
|
+
return next;
|
|
5108
|
+
}
|
|
5109
|
+
function startOfMonth(date) {
|
|
5110
|
+
return new Date(date.getFullYear(), date.getMonth(), 1);
|
|
5111
|
+
}
|
|
5112
|
+
function startOfYear(date) {
|
|
5113
|
+
return new Date(date.getFullYear(), 0, 1);
|
|
5114
|
+
}
|
|
5115
|
+
function validDate(value) {
|
|
5116
|
+
if (value === void 0) return void 0;
|
|
5117
|
+
const date = value instanceof Date ? new Date(value) : new Date(value);
|
|
5118
|
+
return Number.isNaN(date.valueOf()) ? void 0 : date;
|
|
5119
|
+
}
|
|
5120
|
+
function dateFilterBounds(filter, now = /* @__PURE__ */ new Date()) {
|
|
5121
|
+
if (!filter.preset) {
|
|
5122
|
+
return {
|
|
5123
|
+
...filter.since === void 0 ? {} : { since: filter.since },
|
|
5124
|
+
...filter.until === void 0 ? {} : { until: filter.until }
|
|
5125
|
+
};
|
|
5126
|
+
}
|
|
5127
|
+
if (filter.preset === "all") return {};
|
|
5128
|
+
const anchor = validDate(filter.anchor) ?? validDate(now) ?? /* @__PURE__ */ new Date();
|
|
5129
|
+
const ago = (milliseconds) => new Date(anchor.valueOf() - milliseconds).toISOString();
|
|
5130
|
+
const recent = {
|
|
5131
|
+
"1m": 6e4,
|
|
5132
|
+
"15m": 15 * 6e4,
|
|
5133
|
+
"30m": 30 * 6e4,
|
|
5134
|
+
"1h": 60 * 6e4,
|
|
5135
|
+
"2h": 2 * 60 * 6e4,
|
|
5136
|
+
"6h": 6 * 60 * 6e4,
|
|
5137
|
+
"12h": 12 * 60 * 6e4
|
|
5138
|
+
};
|
|
5139
|
+
const duration = recent[filter.preset.replace("older_", "")];
|
|
5140
|
+
if (duration !== void 0) {
|
|
5141
|
+
return filter.preset.startsWith("older_") ? { until: ago(duration) } : { since: ago(duration) };
|
|
5142
|
+
}
|
|
5143
|
+
const starts = {
|
|
5144
|
+
today: startOfDay(anchor),
|
|
5145
|
+
this_week: startOfWeek(anchor),
|
|
5146
|
+
this_month: startOfMonth(anchor),
|
|
5147
|
+
this_year: startOfYear(anchor),
|
|
5148
|
+
older_today: startOfDay(anchor),
|
|
5149
|
+
older_this_week: startOfWeek(anchor),
|
|
5150
|
+
older_this_month: startOfMonth(anchor),
|
|
5151
|
+
older_this_year: startOfYear(anchor)
|
|
5152
|
+
};
|
|
5153
|
+
if (filter.preset === "yesterday") {
|
|
5154
|
+
const until = startOfDay(anchor);
|
|
5155
|
+
const since = new Date(until);
|
|
5156
|
+
since.setDate(since.getDate() - 1);
|
|
5157
|
+
return { since: since.toISOString(), until: until.toISOString() };
|
|
5158
|
+
}
|
|
5159
|
+
const start = starts[filter.preset];
|
|
5160
|
+
if (!start) return {};
|
|
5161
|
+
return filter.preset.startsWith("older_") ? { until: start.toISOString() } : { since: start.toISOString() };
|
|
5162
|
+
}
|
|
5163
|
+
|
|
5046
5164
|
// src/data-table/filter-engine.ts
|
|
5047
5165
|
var SELECT_EMPTY_VALUE = "__empty__";
|
|
5048
5166
|
var SELECT_NOT_EMPTY_VALUE = "__not_empty__";
|
|
@@ -5139,10 +5257,25 @@ function passesColumnFilter(value, filter) {
|
|
|
5139
5257
|
if (raw === "") return false;
|
|
5140
5258
|
const normalized = raw.replace(/[^0-9.-]/g, "");
|
|
5141
5259
|
if (normalized === "") return false;
|
|
5142
|
-
const
|
|
5143
|
-
if (!Number.isFinite(
|
|
5144
|
-
if (filter.min !== void 0 &&
|
|
5145
|
-
if (filter.max !== void 0 &&
|
|
5260
|
+
const n2 = typeof value === "number" ? value : Number(normalized);
|
|
5261
|
+
if (!Number.isFinite(n2)) return false;
|
|
5262
|
+
if (filter.min !== void 0 && n2 < filter.min) return false;
|
|
5263
|
+
if (filter.max !== void 0 && n2 > filter.max) return false;
|
|
5264
|
+
return true;
|
|
5265
|
+
}
|
|
5266
|
+
case "date": {
|
|
5267
|
+
const raw = value instanceof Date ? value : new Date(stringifyCellValue(value));
|
|
5268
|
+
if (Number.isNaN(raw.valueOf())) return false;
|
|
5269
|
+
const { since, until } = dateFilterBounds(filter);
|
|
5270
|
+
const timestamp = raw.valueOf();
|
|
5271
|
+
if (since !== void 0) {
|
|
5272
|
+
const sinceTimestamp = new Date(since).valueOf();
|
|
5273
|
+
if (Number.isNaN(sinceTimestamp) || timestamp < sinceTimestamp) return false;
|
|
5274
|
+
}
|
|
5275
|
+
if (until !== void 0) {
|
|
5276
|
+
const untilTimestamp = new Date(until).valueOf();
|
|
5277
|
+
if (Number.isNaN(untilTimestamp) || timestamp >= untilTimestamp) return false;
|
|
5278
|
+
}
|
|
5146
5279
|
return true;
|
|
5147
5280
|
}
|
|
5148
5281
|
}
|
|
@@ -5205,26 +5338,29 @@ function filterAndSortRows(rows, columns, columnFilters, sort, globalSearch, any
|
|
|
5205
5338
|
return result;
|
|
5206
5339
|
}
|
|
5207
5340
|
function countActiveColumnFilters(filters) {
|
|
5208
|
-
let
|
|
5341
|
+
let n2 = 0;
|
|
5209
5342
|
for (const f of Object.values(filters)) {
|
|
5210
5343
|
if (!f) continue;
|
|
5211
5344
|
switch (f.kind) {
|
|
5212
5345
|
case "text":
|
|
5213
|
-
if (f.value.trim() || f.mode && f.mode !== "contains")
|
|
5346
|
+
if (f.value.trim() || f.mode && f.mode !== "contains") n2 += 1;
|
|
5214
5347
|
break;
|
|
5215
5348
|
case "select":
|
|
5216
5349
|
if (f.values !== void 0 || f.value && f.value !== "__all__")
|
|
5217
|
-
|
|
5350
|
+
n2 += 1;
|
|
5218
5351
|
break;
|
|
5219
5352
|
case "boolean":
|
|
5220
|
-
|
|
5353
|
+
n2 += 1;
|
|
5221
5354
|
break;
|
|
5222
5355
|
case "number":
|
|
5223
|
-
if (f.min !== void 0 || f.max !== void 0)
|
|
5356
|
+
if (f.min !== void 0 || f.max !== void 0) n2 += 1;
|
|
5357
|
+
break;
|
|
5358
|
+
case "date":
|
|
5359
|
+
if (isColumnFilterActive(f)) n2 += 1;
|
|
5224
5360
|
break;
|
|
5225
5361
|
}
|
|
5226
5362
|
}
|
|
5227
|
-
return
|
|
5363
|
+
return n2;
|
|
5228
5364
|
}
|
|
5229
5365
|
function isColumnFilterActive(filter) {
|
|
5230
5366
|
if (!filter) return false;
|
|
@@ -5237,6 +5373,10 @@ function isColumnFilterActive(filter) {
|
|
|
5237
5373
|
return true;
|
|
5238
5374
|
case "number":
|
|
5239
5375
|
return filter.min !== void 0 || filter.max !== void 0;
|
|
5376
|
+
case "date": {
|
|
5377
|
+
const bounds = dateFilterBounds(filter);
|
|
5378
|
+
return bounds.since !== void 0 || bounds.until !== void 0;
|
|
5379
|
+
}
|
|
5240
5380
|
}
|
|
5241
5381
|
}
|
|
5242
5382
|
function applyRowEdits(row, edits) {
|
|
@@ -5506,8 +5646,8 @@ function parseLayeredFilters(raw) {
|
|
|
5506
5646
|
}
|
|
5507
5647
|
}
|
|
5508
5648
|
function positiveInt(raw, fallback) {
|
|
5509
|
-
const
|
|
5510
|
-
return Number.isFinite(
|
|
5649
|
+
const n2 = raw ? Number.parseInt(raw, 10) : Number.NaN;
|
|
5650
|
+
return Number.isFinite(n2) && n2 > 0 ? n2 : fallback;
|
|
5511
5651
|
}
|
|
5512
5652
|
function tableUrlParamPrefix(tableId) {
|
|
5513
5653
|
if (!/^[a-z][a-z0-9-]{0,63}$/.test(tableId)) {
|
|
@@ -5708,6 +5848,7 @@ import {
|
|
|
5708
5848
|
forwardRef as forwardRef12,
|
|
5709
5849
|
useEffect as useEffect9,
|
|
5710
5850
|
useMemo as useMemo5,
|
|
5851
|
+
useRef as useRef10,
|
|
5711
5852
|
useState as useState14
|
|
5712
5853
|
} from "react";
|
|
5713
5854
|
import { useDraggable } from "@dnd-kit/core";
|
|
@@ -5855,6 +5996,95 @@ var CommandShortcut = ({
|
|
|
5855
5996
|
};
|
|
5856
5997
|
CommandShortcut.displayName = "CommandShortcut";
|
|
5857
5998
|
|
|
5999
|
+
// src/data-table/facets.ts
|
|
6000
|
+
var MAX_LISTABLE_FACET_LENGTH = 300;
|
|
6001
|
+
var DEFAULT_FACET_LIMIT = 200;
|
|
6002
|
+
var MAX_FACET_LIMIT = 500;
|
|
6003
|
+
function facetText(raw) {
|
|
6004
|
+
if (raw === null || raw === void 0) return "";
|
|
6005
|
+
if (typeof raw === "object") {
|
|
6006
|
+
try {
|
|
6007
|
+
return JSON.stringify(raw);
|
|
6008
|
+
} catch {
|
|
6009
|
+
return String(raw);
|
|
6010
|
+
}
|
|
6011
|
+
}
|
|
6012
|
+
return String(raw);
|
|
6013
|
+
}
|
|
6014
|
+
function computeColumnFacets(args) {
|
|
6015
|
+
const { columnId: columnId2, rows, readValue: readValue2 } = args;
|
|
6016
|
+
const limit = Math.min(Math.max(args.limit ?? DEFAULT_FACET_LIMIT, 1), MAX_FACET_LIMIT);
|
|
6017
|
+
const counts = /* @__PURE__ */ new Map();
|
|
6018
|
+
const longValues = /* @__PURE__ */ new Set();
|
|
6019
|
+
let blank = 0;
|
|
6020
|
+
let maxLength = 0;
|
|
6021
|
+
for (const row of rows) {
|
|
6022
|
+
let raw;
|
|
6023
|
+
try {
|
|
6024
|
+
raw = readValue2(row, columnId2);
|
|
6025
|
+
} catch {
|
|
6026
|
+
raw = void 0;
|
|
6027
|
+
}
|
|
6028
|
+
const trimmed = facetText(raw).trim();
|
|
6029
|
+
if (trimmed === "") {
|
|
6030
|
+
blank += 1;
|
|
6031
|
+
continue;
|
|
6032
|
+
}
|
|
6033
|
+
if (trimmed.length > maxLength) maxLength = trimmed.length;
|
|
6034
|
+
if (trimmed.length > MAX_LISTABLE_FACET_LENGTH) {
|
|
6035
|
+
longValues.add(trimmed);
|
|
6036
|
+
continue;
|
|
6037
|
+
}
|
|
6038
|
+
counts.set(trimmed, (counts.get(trimmed) ?? 0) + 1);
|
|
6039
|
+
}
|
|
6040
|
+
const values = [...counts.entries()].map(([value, count]) => ({ value, count })).sort((a, b) => b.count - a.count || a.value.localeCompare(b.value)).slice(0, limit);
|
|
6041
|
+
return {
|
|
6042
|
+
columnId: columnId2,
|
|
6043
|
+
totalRows: rows.length,
|
|
6044
|
+
filled: rows.length - blank,
|
|
6045
|
+
blank,
|
|
6046
|
+
distinctCount: counts.size + longValues.size,
|
|
6047
|
+
maxLength,
|
|
6048
|
+
unlistable: longValues.size,
|
|
6049
|
+
limit,
|
|
6050
|
+
truncated: counts.size > limit,
|
|
6051
|
+
values,
|
|
6052
|
+
answeredBy: "local",
|
|
6053
|
+
complete: args.complete ?? true
|
|
6054
|
+
};
|
|
6055
|
+
}
|
|
6056
|
+
function localFacetsAreComplete(loadedRowCount, total) {
|
|
6057
|
+
if (total === void 0 || !Number.isFinite(total) || total < 0) return false;
|
|
6058
|
+
return loadedRowCount >= total;
|
|
6059
|
+
}
|
|
6060
|
+
var NUMBERS = new Intl.NumberFormat("en-US");
|
|
6061
|
+
function n(value) {
|
|
6062
|
+
try {
|
|
6063
|
+
return NUMBERS.format(value);
|
|
6064
|
+
} catch {
|
|
6065
|
+
return String(value);
|
|
6066
|
+
}
|
|
6067
|
+
}
|
|
6068
|
+
function describeFacetSource(facets, noun = "row") {
|
|
6069
|
+
if (!facets) return "";
|
|
6070
|
+
const plural2 = `${noun}s`;
|
|
6071
|
+
if (!facets.complete) {
|
|
6072
|
+
return `These counts cover the ${n(facets.totalRows)} ${plural2} loaded here, not the whole table.`;
|
|
6073
|
+
}
|
|
6074
|
+
if (facets.truncated) {
|
|
6075
|
+
return `Showing the ${n(facets.values.length)} most common of ${n(facets.distinctCount)} values.`;
|
|
6076
|
+
}
|
|
6077
|
+
if (facets.unlistable > 0) {
|
|
6078
|
+
return `${n(facets.unlistable)} ${facets.unlistable === 1 ? "value is" : "values are"} too long to list. Match text instead to reach ${facets.unlistable === 1 ? "it" : "them"}.`;
|
|
6079
|
+
}
|
|
6080
|
+
return "";
|
|
6081
|
+
}
|
|
6082
|
+
var FACETS_LOADING_NOTICE = "Counting values\u2026";
|
|
6083
|
+
function describeFacetFailure(error) {
|
|
6084
|
+
const detail = error instanceof Error ? error.message : String(error ?? "");
|
|
6085
|
+
return detail ? `The values in this column could not be counted: ${detail} Match text instead.` : "The values in this column could not be counted. Match text instead.";
|
|
6086
|
+
}
|
|
6087
|
+
|
|
5858
6088
|
// src/data-table/column-marker.ts
|
|
5859
6089
|
var MARKER_ACCESSORS = {
|
|
5860
6090
|
favorite: "favorite",
|
|
@@ -5922,6 +6152,10 @@ function ColumnHeaderCell({
|
|
|
5922
6152
|
filterFooterHint,
|
|
5923
6153
|
allowNegation = false,
|
|
5924
6154
|
allowNullModes = false,
|
|
6155
|
+
facets,
|
|
6156
|
+
facetsLoading = false,
|
|
6157
|
+
facetsError,
|
|
6158
|
+
onFilterOpen,
|
|
5925
6159
|
reorderColumn
|
|
5926
6160
|
}) {
|
|
5927
6161
|
const reorderEnabled = reorderColumn !== void 0;
|
|
@@ -5956,6 +6190,11 @@ function ColumnHeaderCell({
|
|
|
5956
6190
|
setPendingNegation(filterValue?.negated ?? false);
|
|
5957
6191
|
}
|
|
5958
6192
|
}, [filterOpen, filterValue]);
|
|
6193
|
+
const notifyOpen = useRef10(onFilterOpen);
|
|
6194
|
+
notifyOpen.current = onFilterOpen;
|
|
6195
|
+
useEffect9(() => {
|
|
6196
|
+
if (filterOpen) notifyOpen.current?.();
|
|
6197
|
+
}, [filterOpen]);
|
|
5959
6198
|
const applyFilter = () => {
|
|
5960
6199
|
onFilterChange(draftFilter);
|
|
5961
6200
|
setFilterOpen(false);
|
|
@@ -5967,7 +6206,7 @@ function ColumnHeaderCell({
|
|
|
5967
6206
|
const visibleFilter = deferredFilter ? draftFilter : filterValue;
|
|
5968
6207
|
const setNegated = (negated) => {
|
|
5969
6208
|
setPendingNegation(negated);
|
|
5970
|
-
if (!visibleFilter) return;
|
|
6209
|
+
if (!visibleFilter || visibleFilter.kind === "date") return;
|
|
5971
6210
|
const next = { ...visibleFilter, ...negated ? { negated: true } : {} };
|
|
5972
6211
|
if (!negated) delete next.negated;
|
|
5973
6212
|
if (deferredFilter) setDraftFilter(next);
|
|
@@ -5975,7 +6214,7 @@ function ColumnHeaderCell({
|
|
|
5975
6214
|
};
|
|
5976
6215
|
const markerLabels = marker ? markerCopy(marker) : void 0;
|
|
5977
6216
|
const accessibleLabel = markerLabels?.label ?? labelText;
|
|
5978
|
-
const menuLabel = accessibleLabel ? `Sort or filter ${accessibleLabel}` : "Sort or filter column";
|
|
6217
|
+
const menuLabel = filterKind ? accessibleLabel ? `Sort or filter ${accessibleLabel}` : "Sort or filter column" : accessibleLabel ? `Sort ${accessibleLabel}` : "Sort column";
|
|
5979
6218
|
const menuContent = /* @__PURE__ */ jsxs22(
|
|
5980
6219
|
PopoverContent,
|
|
5981
6220
|
{
|
|
@@ -6043,13 +6282,16 @@ function ColumnHeaderCell({
|
|
|
6043
6282
|
kind: filterKind,
|
|
6044
6283
|
value: visibleFilter,
|
|
6045
6284
|
onChange: (next) => {
|
|
6046
|
-
const preservingNegation = next && (visibleFilter?.negated ?? pendingNegation) ? { ...next, negated: true } : next;
|
|
6285
|
+
const preservingNegation = next && next.kind !== "date" && (visibleFilter?.negated ?? pendingNegation) ? { ...next, negated: true } : next;
|
|
6047
6286
|
if (deferredFilter) setDraftFilter(preservingNegation);
|
|
6048
6287
|
else onFilterChange(preservingNegation);
|
|
6049
6288
|
},
|
|
6050
6289
|
selectOptions,
|
|
6051
6290
|
selectSingle,
|
|
6052
6291
|
selectAllowCustom,
|
|
6292
|
+
facets: facets ?? null,
|
|
6293
|
+
facetsLoading,
|
|
6294
|
+
...facetsError === void 0 ? {} : { facetsError },
|
|
6053
6295
|
...markerLabels ? {
|
|
6054
6296
|
booleanLabels: {
|
|
6055
6297
|
all: "All",
|
|
@@ -6060,7 +6302,7 @@ function ColumnHeaderCell({
|
|
|
6060
6302
|
allowNullModes
|
|
6061
6303
|
}
|
|
6062
6304
|
) : null,
|
|
6063
|
-
filterKind && allowNegation ? /* @__PURE__ */ jsxs22("div", { className: "mt-2 border-t border-border pt-2", children: [
|
|
6305
|
+
filterKind && filterKind !== "date" && allowNegation ? /* @__PURE__ */ jsxs22("div", { className: "mt-2 border-t border-border pt-2", children: [
|
|
6064
6306
|
/* @__PURE__ */ jsx31("p", { className: "mb-1 text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: "Match mode" }),
|
|
6065
6307
|
/* @__PURE__ */ jsxs22("div", { className: "grid grid-cols-2 gap-1 rounded-md border p-0.5", children: [
|
|
6066
6308
|
/* @__PURE__ */ jsx31(
|
|
@@ -6274,8 +6516,43 @@ function FilterBody({
|
|
|
6274
6516
|
selectSingle = false,
|
|
6275
6517
|
selectAllowCustom = false,
|
|
6276
6518
|
allowNullModes = false,
|
|
6277
|
-
booleanLabels
|
|
6519
|
+
booleanLabels,
|
|
6520
|
+
facets = null,
|
|
6521
|
+
facetsLoading = false,
|
|
6522
|
+
facetsError
|
|
6278
6523
|
}) {
|
|
6524
|
+
const checklist = facetsLoading || facetsError || facets && (facets.values.length > 0 || facets.blank > 0) ? /* @__PURE__ */ jsx31(
|
|
6525
|
+
FacetChecklist,
|
|
6526
|
+
{
|
|
6527
|
+
facets,
|
|
6528
|
+
loading: facetsLoading,
|
|
6529
|
+
...facetsError === void 0 ? {} : { error: facetsError },
|
|
6530
|
+
value,
|
|
6531
|
+
onChange
|
|
6532
|
+
}
|
|
6533
|
+
) : null;
|
|
6534
|
+
if (checklist && kind === "select" && facets && facets.values.length > 0) {
|
|
6535
|
+
return /* @__PURE__ */ jsx31("div", { className: "space-y-2", children: checklist });
|
|
6536
|
+
}
|
|
6537
|
+
if (checklist) {
|
|
6538
|
+
return /* @__PURE__ */ jsxs22("div", { className: "space-y-2", children: [
|
|
6539
|
+
checklist,
|
|
6540
|
+
/* @__PURE__ */ jsx31("div", { className: "h-px bg-border" }),
|
|
6541
|
+
/* @__PURE__ */ jsx31(
|
|
6542
|
+
FilterBody,
|
|
6543
|
+
{
|
|
6544
|
+
kind,
|
|
6545
|
+
value,
|
|
6546
|
+
onChange,
|
|
6547
|
+
selectOptions,
|
|
6548
|
+
selectSingle,
|
|
6549
|
+
selectAllowCustom,
|
|
6550
|
+
allowNullModes,
|
|
6551
|
+
...booleanLabels === void 0 ? {} : { booleanLabels }
|
|
6552
|
+
}
|
|
6553
|
+
)
|
|
6554
|
+
] });
|
|
6555
|
+
}
|
|
6279
6556
|
if (kind === "text") {
|
|
6280
6557
|
const text = value?.kind === "text" ? value.value : "";
|
|
6281
6558
|
const mode = (value?.kind === "text" ? value.mode : void 0) ?? "contains";
|
|
@@ -6384,8 +6661,183 @@ function FilterBody({
|
|
|
6384
6661
|
)
|
|
6385
6662
|
] });
|
|
6386
6663
|
}
|
|
6664
|
+
if (kind === "date") {
|
|
6665
|
+
return /* @__PURE__ */ jsx31(DateFilterBody, { value, onChange });
|
|
6666
|
+
}
|
|
6387
6667
|
return /* @__PURE__ */ jsx31(NumberFilterBody, { value, onChange });
|
|
6388
6668
|
}
|
|
6669
|
+
function FacetChecklist({
|
|
6670
|
+
facets,
|
|
6671
|
+
loading,
|
|
6672
|
+
error,
|
|
6673
|
+
value,
|
|
6674
|
+
onChange
|
|
6675
|
+
}) {
|
|
6676
|
+
const [query, setQuery] = useState14("");
|
|
6677
|
+
const selected = value?.kind === "select" ? value.values ?? (value.value && value.value !== "__all__" ? [value.value] : []) : [];
|
|
6678
|
+
const selectedSet = new Set(selected);
|
|
6679
|
+
const rows = useMemo5(() => {
|
|
6680
|
+
if (!facets) return [];
|
|
6681
|
+
const listed = facets.values.map((entry) => ({
|
|
6682
|
+
value: entry.value,
|
|
6683
|
+
label: entry.value,
|
|
6684
|
+
count: entry.count
|
|
6685
|
+
}));
|
|
6686
|
+
const withBlank = facets.blank > 0 ? [{ value: "", label: "(empty)", count: facets.blank }, ...listed] : listed;
|
|
6687
|
+
const q = query.trim().toLowerCase();
|
|
6688
|
+
if (!q) return withBlank;
|
|
6689
|
+
return withBlank.filter((row) => row.label.toLowerCase().includes(q));
|
|
6690
|
+
}, [facets, query]);
|
|
6691
|
+
const toggle = (candidate) => {
|
|
6692
|
+
const next = new Set(selectedSet);
|
|
6693
|
+
if (next.has(candidate)) next.delete(candidate);
|
|
6694
|
+
else next.add(candidate);
|
|
6695
|
+
const values = [...next];
|
|
6696
|
+
onChange(
|
|
6697
|
+
values.length === 0 ? void 0 : { kind: "select", value: values[0] ?? "", values }
|
|
6698
|
+
);
|
|
6699
|
+
};
|
|
6700
|
+
const notice = error ?? (loading ? FACETS_LOADING_NOTICE : describeFacetSource(facets));
|
|
6701
|
+
return /* @__PURE__ */ jsxs22("div", { className: "space-y-1.5", children: [
|
|
6702
|
+
/* @__PURE__ */ jsx31("p", { className: "px-1 text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: "Values" }),
|
|
6703
|
+
facets && facets.values.length + (facets.blank > 0 ? 1 : 0) > 8 ? /* @__PURE__ */ jsx31(
|
|
6704
|
+
Input,
|
|
6705
|
+
{
|
|
6706
|
+
"data-matrx-filter-autofocus": true,
|
|
6707
|
+
value: query,
|
|
6708
|
+
onChange: (event) => setQuery(event.target.value),
|
|
6709
|
+
placeholder: "Find a value\u2026",
|
|
6710
|
+
className: "h-7 text-sm",
|
|
6711
|
+
style: { fontSize: "16px" }
|
|
6712
|
+
}
|
|
6713
|
+
) : null,
|
|
6714
|
+
rows.length > 0 ? /* @__PURE__ */ jsx31("ul", { className: "max-h-56 space-y-0.5 overflow-y-auto", "data-matrx-facet-list": "true", children: rows.map((row) => {
|
|
6715
|
+
const checked = selectedSet.has(row.value);
|
|
6716
|
+
return /* @__PURE__ */ jsx31("li", { children: /* @__PURE__ */ jsxs22(
|
|
6717
|
+
"button",
|
|
6718
|
+
{
|
|
6719
|
+
type: "button",
|
|
6720
|
+
role: "checkbox",
|
|
6721
|
+
"aria-checked": checked,
|
|
6722
|
+
"data-matrx-facet-value": row.value === "" ? "__blank__" : row.value,
|
|
6723
|
+
onClick: () => toggle(row.value),
|
|
6724
|
+
className: cn(
|
|
6725
|
+
"flex w-full items-center gap-2 rounded px-1.5 py-1 text-left text-xs hover:bg-muted",
|
|
6726
|
+
checked && "bg-primary/10"
|
|
6727
|
+
),
|
|
6728
|
+
children: [
|
|
6729
|
+
/* @__PURE__ */ jsx31(
|
|
6730
|
+
"span",
|
|
6731
|
+
{
|
|
6732
|
+
"aria-hidden": true,
|
|
6733
|
+
className: cn(
|
|
6734
|
+
"flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-[3px] border",
|
|
6735
|
+
checked ? "border-primary bg-primary text-primary-foreground" : "border-border"
|
|
6736
|
+
),
|
|
6737
|
+
children: checked ? /* @__PURE__ */ jsx31(Check, { className: "h-2.5 w-2.5" }) : null
|
|
6738
|
+
}
|
|
6739
|
+
),
|
|
6740
|
+
/* @__PURE__ */ jsx31("span", { className: cn("min-w-0 flex-1 truncate", row.value === "" && "italic text-muted-foreground"), children: row.label }),
|
|
6741
|
+
/* @__PURE__ */ jsx31(
|
|
6742
|
+
"span",
|
|
6743
|
+
{
|
|
6744
|
+
"data-matrx-facet-count": String(row.count),
|
|
6745
|
+
className: "shrink-0 tabular-nums text-[11px] text-muted-foreground",
|
|
6746
|
+
children: row.count.toLocaleString("en-US")
|
|
6747
|
+
}
|
|
6748
|
+
)
|
|
6749
|
+
]
|
|
6750
|
+
}
|
|
6751
|
+
) }, row.value === "" ? "__blank__" : row.value);
|
|
6752
|
+
}) }) : loading ? null : /* @__PURE__ */ jsx31("p", { className: "px-1 text-[11px] text-muted-foreground", children: query.trim() ? "No value matches that." : "This column has no values yet." }),
|
|
6753
|
+
notice ? /* @__PURE__ */ jsx31(
|
|
6754
|
+
"p",
|
|
6755
|
+
{
|
|
6756
|
+
"data-matrx-facet-notice": "true",
|
|
6757
|
+
className: cn(
|
|
6758
|
+
"px-1 text-[11px] leading-snug",
|
|
6759
|
+
error ? "text-amber-700 dark:text-amber-400" : "text-muted-foreground"
|
|
6760
|
+
),
|
|
6761
|
+
children: notice
|
|
6762
|
+
}
|
|
6763
|
+
) : null,
|
|
6764
|
+
selected.length > 0 ? /* @__PURE__ */ jsx31(
|
|
6765
|
+
"button",
|
|
6766
|
+
{
|
|
6767
|
+
type: "button",
|
|
6768
|
+
onClick: () => onChange(void 0),
|
|
6769
|
+
className: "px-1 text-[11px] text-muted-foreground underline-offset-2 hover:underline",
|
|
6770
|
+
children: "Clear selection"
|
|
6771
|
+
}
|
|
6772
|
+
) : null
|
|
6773
|
+
] });
|
|
6774
|
+
}
|
|
6775
|
+
function DateFilterBody({
|
|
6776
|
+
value,
|
|
6777
|
+
onChange
|
|
6778
|
+
}) {
|
|
6779
|
+
const dateValue = value?.kind === "date" ? value : void 0;
|
|
6780
|
+
const isCustom = dateValue !== void 0 && dateValue.preset === void 0;
|
|
6781
|
+
const selected = dateValue?.preset ?? (isCustom ? "__custom__" : "all");
|
|
6782
|
+
const setBound = (bound, raw) => {
|
|
6783
|
+
const next = raw ? new Date(raw) : void 0;
|
|
6784
|
+
const iso = next && !Number.isNaN(next.valueOf()) ? next.toISOString() : void 0;
|
|
6785
|
+
const current = dateValue && dateValue.preset === void 0 ? dateValue : { kind: "date" };
|
|
6786
|
+
const updated = { ...current, [bound]: iso };
|
|
6787
|
+
if (updated.since === void 0 && updated.until === void 0) onChange(void 0);
|
|
6788
|
+
else onChange(updated);
|
|
6789
|
+
};
|
|
6790
|
+
return /* @__PURE__ */ jsxs22("div", { className: "space-y-2 px-1", children: [
|
|
6791
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex items-center justify-between", children: [
|
|
6792
|
+
/* @__PURE__ */ jsx31("p", { className: "text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: "Date range" }),
|
|
6793
|
+
dateValue ? /* @__PURE__ */ jsx31("button", { type: "button", className: "text-[11px] text-muted-foreground hover:text-foreground", onClick: () => onChange(void 0), children: "clear" }) : null
|
|
6794
|
+
] }),
|
|
6795
|
+
/* @__PURE__ */ jsxs22(
|
|
6796
|
+
Select,
|
|
6797
|
+
{
|
|
6798
|
+
value: selected,
|
|
6799
|
+
onValueChange: (next) => {
|
|
6800
|
+
if (next === "all") {
|
|
6801
|
+
onChange(void 0);
|
|
6802
|
+
return;
|
|
6803
|
+
}
|
|
6804
|
+
if (next === "__custom__") {
|
|
6805
|
+
onChange({ kind: "date" });
|
|
6806
|
+
return;
|
|
6807
|
+
}
|
|
6808
|
+
onChange({ kind: "date", preset: next, anchor: (/* @__PURE__ */ new Date()).toISOString() });
|
|
6809
|
+
},
|
|
6810
|
+
children: [
|
|
6811
|
+
/* @__PURE__ */ jsx31(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx31(SelectValue, {}) }),
|
|
6812
|
+
/* @__PURE__ */ jsxs22(SelectContent, { children: [
|
|
6813
|
+
["all", "recent", "calendar", "older"].map((group) => /* @__PURE__ */ jsxs22("div", { children: [
|
|
6814
|
+
group !== "all" ? /* @__PURE__ */ jsx31("p", { className: "px-2 py-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground", children: group }) : null,
|
|
6815
|
+
TIME_RANGE_PRESETS.filter((option) => option.group === group).map((option) => /* @__PURE__ */ jsx31(SelectItem, { value: option.value, children: option.label }, option.value))
|
|
6816
|
+
] }, group)),
|
|
6817
|
+
/* @__PURE__ */ jsx31(SelectItem, { value: "__custom__", children: "Custom range" })
|
|
6818
|
+
] })
|
|
6819
|
+
]
|
|
6820
|
+
}
|
|
6821
|
+
),
|
|
6822
|
+
isCustom ? /* @__PURE__ */ jsxs22("div", { className: "grid gap-1.5", children: [
|
|
6823
|
+
/* @__PURE__ */ jsxs22("label", { className: "grid gap-0.5 text-[11px] text-muted-foreground", children: [
|
|
6824
|
+
"On or after",
|
|
6825
|
+
/* @__PURE__ */ jsx31(Input, { type: "datetime-local", value: dateTimeLocal(dateValue?.since), onChange: (event) => setBound("since", event.target.value), className: "h-8 text-xs" })
|
|
6826
|
+
] }),
|
|
6827
|
+
/* @__PURE__ */ jsxs22("label", { className: "grid gap-0.5 text-[11px] text-muted-foreground", children: [
|
|
6828
|
+
"Before",
|
|
6829
|
+
/* @__PURE__ */ jsx31(Input, { type: "datetime-local", value: dateTimeLocal(dateValue?.until), onChange: (event) => setBound("until", event.target.value), className: "h-8 text-xs" })
|
|
6830
|
+
] })
|
|
6831
|
+
] }) : null
|
|
6832
|
+
] });
|
|
6833
|
+
}
|
|
6834
|
+
function dateTimeLocal(value) {
|
|
6835
|
+
if (!value) return "";
|
|
6836
|
+
const date = new Date(value);
|
|
6837
|
+
if (Number.isNaN(date.valueOf())) return "";
|
|
6838
|
+
const offset = date.getTimezoneOffset() * 6e4;
|
|
6839
|
+
return new Date(date.valueOf() - offset).toISOString().slice(0, 16);
|
|
6840
|
+
}
|
|
6389
6841
|
function SearchableSelectFilter({
|
|
6390
6842
|
selected,
|
|
6391
6843
|
options,
|
|
@@ -6572,15 +7024,15 @@ function NumberFilterBody({
|
|
|
6572
7024
|
}
|
|
6573
7025
|
function parseOptionalNumber(raw) {
|
|
6574
7026
|
if (raw.trim() === "") return void 0;
|
|
6575
|
-
const
|
|
6576
|
-
return Number.isFinite(
|
|
7027
|
+
const n2 = Number(raw.replace(/[^0-9.-]/g, ""));
|
|
7028
|
+
return Number.isFinite(n2) ? n2 : void 0;
|
|
6577
7029
|
}
|
|
6578
7030
|
|
|
6579
7031
|
// src/data-table/ColumnResizeHandle.tsx
|
|
6580
7032
|
import {
|
|
6581
7033
|
useCallback as useCallback6,
|
|
6582
7034
|
useEffect as useEffect10,
|
|
6583
|
-
useRef as
|
|
7035
|
+
useRef as useRef11,
|
|
6584
7036
|
useState as useState15
|
|
6585
7037
|
} from "react";
|
|
6586
7038
|
|
|
@@ -6624,11 +7076,11 @@ function ColumnResizeHandle({
|
|
|
6624
7076
|
onResizeCancel,
|
|
6625
7077
|
onResizeCommit
|
|
6626
7078
|
}) {
|
|
6627
|
-
const handleRef =
|
|
6628
|
-
const activeResizeRef =
|
|
6629
|
-
const previewRafRef =
|
|
6630
|
-
const queuedWidthRef =
|
|
6631
|
-
const keyboardWidthRef =
|
|
7079
|
+
const handleRef = useRef11(null);
|
|
7080
|
+
const activeResizeRef = useRef11(null);
|
|
7081
|
+
const previewRafRef = useRef11(null);
|
|
7082
|
+
const queuedWidthRef = useRef11(null);
|
|
7083
|
+
const keyboardWidthRef = useRef11(null);
|
|
6632
7084
|
const [announcedWidth, setAnnouncedWidth] = useState15(null);
|
|
6633
7085
|
const bounds = resolveColumnResizeBounds(minWidth, maxWidth);
|
|
6634
7086
|
const cssVar = columnResizeCssVar(columnId2);
|
|
@@ -6890,16 +7342,16 @@ function computeAggregate(rows, column) {
|
|
|
6890
7342
|
value = total;
|
|
6891
7343
|
break;
|
|
6892
7344
|
case "sum":
|
|
6893
|
-
value = numbers.length === 0 ? null : numbers.reduce((acc,
|
|
7345
|
+
value = numbers.length === 0 ? null : numbers.reduce((acc, n2) => acc + n2, 0);
|
|
6894
7346
|
break;
|
|
6895
7347
|
case "average":
|
|
6896
|
-
value = numbers.length === 0 ? null : numbers.reduce((acc,
|
|
7348
|
+
value = numbers.length === 0 ? null : numbers.reduce((acc, n2) => acc + n2, 0) / numbers.length;
|
|
6897
7349
|
break;
|
|
6898
7350
|
case "min":
|
|
6899
|
-
value = numbers.length === 0 ? null : numbers.reduce((acc,
|
|
7351
|
+
value = numbers.length === 0 ? null : numbers.reduce((acc, n2) => n2 < acc ? n2 : acc);
|
|
6900
7352
|
break;
|
|
6901
7353
|
case "max":
|
|
6902
|
-
value = numbers.length === 0 ? null : numbers.reduce((acc,
|
|
7354
|
+
value = numbers.length === 0 ? null : numbers.reduce((acc, n2) => n2 > acc ? n2 : acc);
|
|
6903
7355
|
break;
|
|
6904
7356
|
case "empty":
|
|
6905
7357
|
value = total - filled.length;
|
|
@@ -7217,7 +7669,7 @@ function scrollOffsetForIndex(input) {
|
|
|
7217
7669
|
}
|
|
7218
7670
|
|
|
7219
7671
|
// src/data-table/useSpreadsheetGrid.ts
|
|
7220
|
-
import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo6, useRef as
|
|
7672
|
+
import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo6, useRef as useRef12, useState as useState16 } from "react";
|
|
7221
7673
|
|
|
7222
7674
|
// src/data-table/grid-selection.ts
|
|
7223
7675
|
function rangeBounds(range, rowIds, fieldNames) {
|
|
@@ -7323,7 +7775,7 @@ function moveSelection(current, move, rowIds, fieldNames) {
|
|
|
7323
7775
|
if (r === -1 || c === -1) return first;
|
|
7324
7776
|
const lastRow = rowIds.length - 1;
|
|
7325
7777
|
const lastCol = fieldNames.length - 1;
|
|
7326
|
-
const clamp = (
|
|
7778
|
+
const clamp = (n2, max) => Math.min(Math.max(n2, 0), max);
|
|
7327
7779
|
switch (move) {
|
|
7328
7780
|
case "up":
|
|
7329
7781
|
r = clamp(r - 1, lastRow);
|
|
@@ -7455,14 +7907,14 @@ function parseClipboardGrid(text) {
|
|
|
7455
7907
|
let row = [];
|
|
7456
7908
|
let cell = "";
|
|
7457
7909
|
let i = 0;
|
|
7458
|
-
const
|
|
7459
|
-
while (i <
|
|
7910
|
+
const n2 = text.length;
|
|
7911
|
+
while (i < n2) {
|
|
7460
7912
|
const ch = text[i];
|
|
7461
7913
|
if (cell === "" && ch === '"') {
|
|
7462
7914
|
let j = i + 1;
|
|
7463
7915
|
let out = "";
|
|
7464
7916
|
let closed = false;
|
|
7465
|
-
while (j <
|
|
7917
|
+
while (j < n2) {
|
|
7466
7918
|
const c = text[j];
|
|
7467
7919
|
if (c === '"') {
|
|
7468
7920
|
if (text[j + 1] === '"') {
|
|
@@ -7477,10 +7929,10 @@ function parseClipboardGrid(text) {
|
|
|
7477
7929
|
out += c;
|
|
7478
7930
|
j += 1;
|
|
7479
7931
|
}
|
|
7480
|
-
if (closed && (j >=
|
|
7932
|
+
if (closed && (j >= n2 || text[j] === " " || text[j] === "\n" || text[j] === "\r")) {
|
|
7481
7933
|
cell = out;
|
|
7482
7934
|
i = j;
|
|
7483
|
-
if (i >=
|
|
7935
|
+
if (i >= n2) break;
|
|
7484
7936
|
const d = text[i];
|
|
7485
7937
|
if (d === " ") {
|
|
7486
7938
|
row.push(cell);
|
|
@@ -7516,7 +7968,7 @@ function parseClipboardGrid(text) {
|
|
|
7516
7968
|
cell += ch;
|
|
7517
7969
|
i += 1;
|
|
7518
7970
|
}
|
|
7519
|
-
const endedOnBreak =
|
|
7971
|
+
const endedOnBreak = n2 > 0 && (text[n2 - 1] === "\n" || text[n2 - 1] === "\r");
|
|
7520
7972
|
if (!endedOnBreak) {
|
|
7521
7973
|
row.push(cell);
|
|
7522
7974
|
rows.push(row);
|
|
@@ -7595,11 +8047,11 @@ function directionOf(source, target) {
|
|
|
7595
8047
|
return null;
|
|
7596
8048
|
}
|
|
7597
8049
|
function tileIndex(i, a, b) {
|
|
7598
|
-
const
|
|
7599
|
-
if (
|
|
8050
|
+
const n2 = b - a + 1;
|
|
8051
|
+
if (n2 <= 0) return a;
|
|
7600
8052
|
if (i >= a && i <= b) return i;
|
|
7601
|
-
if (i > b) return a + (i - a) %
|
|
7602
|
-
return b - (a - 1 - i) %
|
|
8053
|
+
if (i > b) return a + (i - a) % n2;
|
|
8054
|
+
return b - (a - 1 - i) % n2;
|
|
7603
8055
|
}
|
|
7604
8056
|
function isFiniteNumber(v) {
|
|
7605
8057
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -7915,8 +8367,8 @@ function useSpreadsheetGrid(options) {
|
|
|
7915
8367
|
const [range, setRange] = useState16(null);
|
|
7916
8368
|
const [fillTarget, setFillTarget] = useState16(null);
|
|
7917
8369
|
const [stack, setStack] = useState16(() => createUndoStack(options?.undoDepth ?? 100));
|
|
7918
|
-
const draggingRef =
|
|
7919
|
-
const optionsRef =
|
|
8370
|
+
const draggingRef = useRef12(null);
|
|
8371
|
+
const optionsRef = useRef12(options);
|
|
7920
8372
|
optionsRef.current = options;
|
|
7921
8373
|
const rowIds = options?.rowIds ?? [];
|
|
7922
8374
|
const columnIds = useMemo6(
|
|
@@ -7944,6 +8396,26 @@ function useSpreadsheetGrid(options) {
|
|
|
7944
8396
|
for (let i = 0; i < columnIds.length; i += 1) map.set(columnIds[i], i);
|
|
7945
8397
|
return map;
|
|
7946
8398
|
}, [columnIds]);
|
|
8399
|
+
const screenPatches = useCallback7(
|
|
8400
|
+
(patches) => {
|
|
8401
|
+
const validate = optionsRef.current?.validateCell;
|
|
8402
|
+
if (!validate) return { accepted: patches, refusals: [] };
|
|
8403
|
+
const accepted = [];
|
|
8404
|
+
const refusals = [];
|
|
8405
|
+
for (const patch of patches) {
|
|
8406
|
+
let reason;
|
|
8407
|
+
try {
|
|
8408
|
+
reason = validate({ rowId: patch.rowId, columnId: patch.columnId, value: patch.value });
|
|
8409
|
+
} catch {
|
|
8410
|
+
reason = void 0;
|
|
8411
|
+
}
|
|
8412
|
+
if (reason) refusals.push({ columnId: patch.columnId, reason });
|
|
8413
|
+
else accepted.push(patch);
|
|
8414
|
+
}
|
|
8415
|
+
return { accepted, refusals };
|
|
8416
|
+
},
|
|
8417
|
+
[]
|
|
8418
|
+
);
|
|
7947
8419
|
const applyPatches = useCallback7(
|
|
7948
8420
|
async (patches, intent, label) => {
|
|
7949
8421
|
const current = optionsRef.current;
|
|
@@ -8000,9 +8472,10 @@ function useSpreadsheetGrid(options) {
|
|
|
8000
8472
|
...base,
|
|
8001
8473
|
range: { top: bounds.r0, left: bounds.c0, bottom: bounds.r1, right: bounds.c1 }
|
|
8002
8474
|
});
|
|
8003
|
-
|
|
8004
|
-
|
|
8005
|
-
|
|
8475
|
+
const screened = screenPatches(result.patches);
|
|
8476
|
+
await applyPatches(screened.accepted, "fill-down", "Filled down");
|
|
8477
|
+
announceSkips([...result.skipped, ...screened.refusals], result.summary);
|
|
8478
|
+
}, [fillRequestBase, bounds, applyPatches, announceSkips, screenPatches]);
|
|
8006
8479
|
const doClear = useCallback7(async () => {
|
|
8007
8480
|
const current = optionsRef.current;
|
|
8008
8481
|
if (!current || !bounds) return;
|
|
@@ -8023,9 +8496,13 @@ function useSpreadsheetGrid(options) {
|
|
|
8023
8496
|
patches.push({ rowId, columnId: columnId2, value: null });
|
|
8024
8497
|
}
|
|
8025
8498
|
}
|
|
8026
|
-
|
|
8027
|
-
|
|
8028
|
-
|
|
8499
|
+
const screened = screenPatches(patches);
|
|
8500
|
+
await applyPatches(screened.accepted, "clear", "Cleared");
|
|
8501
|
+
announceSkips(
|
|
8502
|
+
[...skipped, ...screened.refusals],
|
|
8503
|
+
`Cleared ${screened.accepted.length} cells.`
|
|
8504
|
+
);
|
|
8505
|
+
}, [bounds, applyPatches, announceSkips, screenPatches]);
|
|
8029
8506
|
const doUndo = useCallback7(async () => {
|
|
8030
8507
|
const taken = popUndo(stack);
|
|
8031
8508
|
if (!taken.entry) return;
|
|
@@ -8110,6 +8587,14 @@ function useSpreadsheetGrid(options) {
|
|
|
8110
8587
|
case "escape":
|
|
8111
8588
|
setRange(null);
|
|
8112
8589
|
return;
|
|
8590
|
+
case "edit":
|
|
8591
|
+
case "editSeeded": {
|
|
8592
|
+
const focused = range?.focus;
|
|
8593
|
+
if (!focused || !current.onEditRequest) return;
|
|
8594
|
+
const seed = action.kind === "editSeeded" ? action.seed : null;
|
|
8595
|
+
if (current.onEditRequest(focused, seed)) event.preventDefault();
|
|
8596
|
+
return;
|
|
8597
|
+
}
|
|
8113
8598
|
default:
|
|
8114
8599
|
return;
|
|
8115
8600
|
}
|
|
@@ -8124,6 +8609,13 @@ function useSpreadsheetGrid(options) {
|
|
|
8124
8609
|
);
|
|
8125
8610
|
return gridToTsv(grid);
|
|
8126
8611
|
}, [range, rowIds, columnIds]);
|
|
8612
|
+
const selectionAddresses = useCallback7(() => {
|
|
8613
|
+
if (!range || !bounds) return { rowIds: [], columnIds: [] };
|
|
8614
|
+
return {
|
|
8615
|
+
rowIds: rowIds.slice(bounds.r0, bounds.r1 + 1),
|
|
8616
|
+
columnIds: columnIds.slice(bounds.c0, bounds.c1 + 1)
|
|
8617
|
+
};
|
|
8618
|
+
}, [range, bounds, rowIds, columnIds]);
|
|
8127
8619
|
const onCopy = useCallback7(
|
|
8128
8620
|
(event) => {
|
|
8129
8621
|
if (!optionsRef.current || !range || targetsAnEditor(event.target)) return;
|
|
@@ -8179,11 +8671,12 @@ function useSpreadsheetGrid(options) {
|
|
|
8179
8671
|
patches.push({ rowId, columnId: columnId2, value: line[c] ?? null });
|
|
8180
8672
|
}
|
|
8181
8673
|
}
|
|
8182
|
-
|
|
8674
|
+
const screened = screenPatches(patches);
|
|
8675
|
+
void applyPatches(screened.accepted, "paste", "Pasted");
|
|
8183
8676
|
const tail = outside > 0 ? ` ${outside} landed past the edge of the table and were ignored.` : "";
|
|
8184
|
-
announceSkips(skipped, `Pasted ${
|
|
8677
|
+
announceSkips([...skipped, ...screened.refusals], `Pasted ${screened.accepted.length} cells.${tail}`);
|
|
8185
8678
|
},
|
|
8186
|
-
[range, rowIds, columnIds, applyPatches, announceSkips]
|
|
8679
|
+
[range, rowIds, columnIds, applyPatches, announceSkips, screenPatches]
|
|
8187
8680
|
);
|
|
8188
8681
|
const cellProps = useCallback7(
|
|
8189
8682
|
(rowId, columnId2) => {
|
|
@@ -8202,6 +8695,10 @@ function useSpreadsheetGrid(options) {
|
|
|
8202
8695
|
onMouseDown: (event) => {
|
|
8203
8696
|
if (event.button !== 0) return;
|
|
8204
8697
|
event.preventDefault();
|
|
8698
|
+
const origin = event.currentTarget;
|
|
8699
|
+
if (typeof HTMLElement !== "undefined" && origin instanceof HTMLElement) {
|
|
8700
|
+
origin.closest('[data-matrx-table-spreadsheet="true"]')?.focus({ preventScroll: true });
|
|
8701
|
+
}
|
|
8205
8702
|
setRange(
|
|
8206
8703
|
(previous) => event.shiftKey && previous ? { anchor: previous.anchor, focus: address } : { anchor: address, focus: address }
|
|
8207
8704
|
);
|
|
@@ -8242,9 +8739,9 @@ function useSpreadsheetGrid(options) {
|
|
|
8242
8739
|
},
|
|
8243
8740
|
[]
|
|
8244
8741
|
);
|
|
8245
|
-
const fillTargetRef =
|
|
8742
|
+
const fillTargetRef = useRef12(null);
|
|
8246
8743
|
fillTargetRef.current = fillTarget;
|
|
8247
|
-
const boundsRef =
|
|
8744
|
+
const boundsRef = useRef12(null);
|
|
8248
8745
|
boundsRef.current = bounds;
|
|
8249
8746
|
useEffect11(() => {
|
|
8250
8747
|
if (!options) return;
|
|
@@ -8263,12 +8760,13 @@ function useSpreadsheetGrid(options) {
|
|
|
8263
8760
|
source: { top: source.r0, left: source.c0, bottom: source.r1, right: source.c1 },
|
|
8264
8761
|
target
|
|
8265
8762
|
});
|
|
8266
|
-
|
|
8267
|
-
|
|
8763
|
+
const screened = screenPatches(result.patches);
|
|
8764
|
+
void applyPatches(screened.accepted, "fill", "Filled");
|
|
8765
|
+
announceSkips([...result.skipped, ...screened.refusals], result.summary);
|
|
8268
8766
|
};
|
|
8269
8767
|
window.addEventListener("mouseup", commit);
|
|
8270
8768
|
return () => window.removeEventListener("mouseup", commit);
|
|
8271
|
-
}, [options, fillRequestBase, applyPatches, announceSkips]);
|
|
8769
|
+
}, [options, fillRequestBase, applyPatches, announceSkips, screenPatches]);
|
|
8272
8770
|
return {
|
|
8273
8771
|
range,
|
|
8274
8772
|
bounds,
|
|
@@ -8284,17 +8782,19 @@ function useSpreadsheetGrid(options) {
|
|
|
8284
8782
|
isFillHandleCell,
|
|
8285
8783
|
startFillDrag,
|
|
8286
8784
|
canUndo: stack.past.length > 0,
|
|
8287
|
-
canRedo: stack.future.length > 0
|
|
8785
|
+
canRedo: stack.future.length > 0,
|
|
8786
|
+
selectionTsv: selectionAsTsv,
|
|
8787
|
+
selectionAddresses
|
|
8288
8788
|
};
|
|
8289
8789
|
}
|
|
8290
8790
|
|
|
8291
8791
|
// src/data-table/coverage.ts
|
|
8292
8792
|
var PARTIAL_BADGE = "Partial";
|
|
8293
8793
|
var UNKNOWN_TOTAL_BADGE = "Unknown total";
|
|
8294
|
-
var
|
|
8794
|
+
var NUMBERS2 = new Intl.NumberFormat("en-US");
|
|
8295
8795
|
function formatNumber(value) {
|
|
8296
8796
|
try {
|
|
8297
|
-
return
|
|
8797
|
+
return NUMBERS2.format(value);
|
|
8298
8798
|
} catch {
|
|
8299
8799
|
return String(value);
|
|
8300
8800
|
}
|
|
@@ -8925,7 +9425,8 @@ var filterSchema = z2.union([
|
|
|
8925
9425
|
z2.object({ kind: z2.literal("text"), value: z2.string(), mode: z2.enum(["contains", "empty", "not_empty", "null", "not_null"]).optional(), negated: z2.boolean().optional() }),
|
|
8926
9426
|
z2.object({ kind: z2.literal("select"), value: z2.string(), values: z2.array(z2.string()).optional(), negated: z2.boolean().optional() }),
|
|
8927
9427
|
z2.object({ kind: z2.literal("boolean"), value: z2.boolean(), negated: z2.boolean().optional() }),
|
|
8928
|
-
z2.object({ kind: z2.literal("number"), min: z2.number().optional(), max: z2.number().optional(), negated: z2.boolean().optional() })
|
|
9428
|
+
z2.object({ kind: z2.literal("number"), min: z2.number().optional(), max: z2.number().optional(), negated: z2.boolean().optional() }),
|
|
9429
|
+
z2.object({ kind: z2.literal("date"), preset: z2.enum(TIME_RANGE_PRESET_VALUES).optional(), since: z2.string().datetime({ offset: true }).optional(), until: z2.string().datetime({ offset: true }).optional(), anchor: z2.string().datetime({ offset: true }).optional() })
|
|
8929
9430
|
]);
|
|
8930
9431
|
var layeredRuleSchema = z2.object({ id: z2.string().min(1), field: z2.string().min(1), operator: z2.enum(LAYERED_FILTER_OPERATORS), value: z2.string(), valueTo: z2.string().optional() });
|
|
8931
9432
|
var snapshotSchema = z2.object({
|
|
@@ -8953,7 +9454,8 @@ function normalizeFilters(raw) {
|
|
|
8953
9454
|
if (value.kind === "text") filters[id] = { kind: "text", value: value.value, ...value.mode === void 0 ? {} : { mode: value.mode }, ...value.negated === void 0 ? {} : { negated: value.negated } };
|
|
8954
9455
|
else if (value.kind === "select") filters[id] = { kind: "select", value: value.value, ...value.values === void 0 ? {} : { values: value.values }, ...value.negated === void 0 ? {} : { negated: value.negated } };
|
|
8955
9456
|
else if (value.kind === "boolean") filters[id] = { kind: "boolean", value: value.value, ...value.negated === void 0 ? {} : { negated: value.negated } };
|
|
8956
|
-
else filters[id] = { kind: "number", ...value.min === void 0 ? {} : { min: value.min }, ...value.max === void 0 ? {} : { max: value.max }, ...value.negated === void 0 ? {} : { negated: value.negated } };
|
|
9457
|
+
else if (value.kind === "number") filters[id] = { kind: "number", ...value.min === void 0 ? {} : { min: value.min }, ...value.max === void 0 ? {} : { max: value.max }, ...value.negated === void 0 ? {} : { negated: value.negated } };
|
|
9458
|
+
else filters[id] = { kind: "date", ...value.preset === void 0 ? {} : { preset: value.preset }, ...value.since === void 0 ? {} : { since: value.since }, ...value.until === void 0 ? {} : { until: value.until }, ...value.anchor === void 0 ? {} : { anchor: value.anchor } };
|
|
8957
9459
|
}
|
|
8958
9460
|
return filters;
|
|
8959
9461
|
}
|
|
@@ -8987,7 +9489,7 @@ function parseTableViewSnapshot(raw) {
|
|
|
8987
9489
|
// src/data-table/MatrxUuidCell.tsx
|
|
8988
9490
|
import {
|
|
8989
9491
|
useEffect as useEffect13,
|
|
8990
|
-
useRef as
|
|
9492
|
+
useRef as useRef13,
|
|
8991
9493
|
useState as useState18
|
|
8992
9494
|
} from "react";
|
|
8993
9495
|
import { jsx as jsx34, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
@@ -9032,7 +9534,7 @@ function MatrxUuidCell({
|
|
|
9032
9534
|
const [copied, setCopied] = useState18(false);
|
|
9033
9535
|
const [opening, setOpening] = useState18(false);
|
|
9034
9536
|
const [peekOpen, setPeekOpen] = useState18(false);
|
|
9035
|
-
const timer =
|
|
9537
|
+
const timer = useRef13(null);
|
|
9036
9538
|
useEffect13(
|
|
9037
9539
|
() => () => {
|
|
9038
9540
|
if (timer.current) clearTimeout(timer.current);
|
|
@@ -9500,8 +10002,8 @@ function toNumber(value) {
|
|
|
9500
10002
|
if (typeof value === "string") {
|
|
9501
10003
|
const cleaned = value.replace(/[,\s$€£¥%]/g, "");
|
|
9502
10004
|
if (cleaned === "") return null;
|
|
9503
|
-
const
|
|
9504
|
-
return Number.isFinite(
|
|
10005
|
+
const n2 = Number(cleaned);
|
|
10006
|
+
return Number.isFinite(n2) ? n2 : null;
|
|
9505
10007
|
}
|
|
9506
10008
|
return null;
|
|
9507
10009
|
}
|
|
@@ -9511,6 +10013,7 @@ function toText(value) {
|
|
|
9511
10013
|
return String(value);
|
|
9512
10014
|
return null;
|
|
9513
10015
|
}
|
|
10016
|
+
var BARE_CALENDAR_DATE = /^(\d{4})-(\d{2})-(\d{2})(?:[T ]00:00(?::00(?:\.0+)?)?)?$/;
|
|
9514
10017
|
function toDate(value) {
|
|
9515
10018
|
if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;
|
|
9516
10019
|
if (typeof value === "number") {
|
|
@@ -9518,6 +10021,20 @@ function toDate(value) {
|
|
|
9518
10021
|
return Number.isNaN(d.getTime()) ? null : d;
|
|
9519
10022
|
}
|
|
9520
10023
|
if (typeof value === "string" && value.trim()) {
|
|
10024
|
+
const bare = BARE_CALENDAR_DATE.exec(value.trim());
|
|
10025
|
+
if (bare) {
|
|
10026
|
+
const [year, month, day] = [
|
|
10027
|
+
Number(bare[1]),
|
|
10028
|
+
Number(bare[2]),
|
|
10029
|
+
Number(bare[3])
|
|
10030
|
+
];
|
|
10031
|
+
const d2 = new Date(year, month - 1, day);
|
|
10032
|
+
d2.setFullYear(year);
|
|
10033
|
+
if (d2.getFullYear() !== year || d2.getMonth() !== month - 1 || d2.getDate() !== day) {
|
|
10034
|
+
return null;
|
|
10035
|
+
}
|
|
10036
|
+
return d2;
|
|
10037
|
+
}
|
|
9521
10038
|
const d = new Date(value);
|
|
9522
10039
|
return Number.isNaN(d.getTime()) ? null : d;
|
|
9523
10040
|
}
|
|
@@ -9539,14 +10056,14 @@ function toList(value) {
|
|
|
9539
10056
|
}
|
|
9540
10057
|
return null;
|
|
9541
10058
|
}
|
|
9542
|
-
function groupedNumber(
|
|
10059
|
+
function groupedNumber(n2, options) {
|
|
9543
10060
|
return new Intl.NumberFormat(void 0, {
|
|
9544
10061
|
useGrouping: options.useGrouping !== false,
|
|
9545
10062
|
...options.precision != null ? {
|
|
9546
10063
|
minimumFractionDigits: options.precision,
|
|
9547
10064
|
maximumFractionDigits: options.precision
|
|
9548
10065
|
} : { maximumFractionDigits: 10 }
|
|
9549
|
-
}).format(
|
|
10066
|
+
}).format(n2);
|
|
9550
10067
|
}
|
|
9551
10068
|
function affix(text, options) {
|
|
9552
10069
|
return `${options.prefix ?? ""}${text}${options.suffix ?? ""}`;
|
|
@@ -9680,8 +10197,8 @@ var DEFS = [
|
|
|
9680
10197
|
numericAlign: true,
|
|
9681
10198
|
optionKeys: ["useGrouping", "precision", "prefix", "suffix"],
|
|
9682
10199
|
format: (v, o) => {
|
|
9683
|
-
const
|
|
9684
|
-
return
|
|
10200
|
+
const n2 = toNumber(v);
|
|
10201
|
+
return n2 === null ? null : affix(groupedNumber(n2, o), o);
|
|
9685
10202
|
},
|
|
9686
10203
|
parse: (raw) => toNumber(raw)
|
|
9687
10204
|
},
|
|
@@ -9696,9 +10213,9 @@ var DEFS = [
|
|
|
9696
10213
|
numericAlign: true,
|
|
9697
10214
|
optionKeys: ["precision", "useGrouping", "prefix", "suffix"],
|
|
9698
10215
|
format: (v, o) => {
|
|
9699
|
-
const
|
|
9700
|
-
if (
|
|
9701
|
-
return affix(groupedNumber(
|
|
10216
|
+
const n2 = toNumber(v);
|
|
10217
|
+
if (n2 === null) return null;
|
|
10218
|
+
return affix(groupedNumber(n2, { ...o, precision: o.precision ?? 2 }), o);
|
|
9702
10219
|
},
|
|
9703
10220
|
parse: (raw) => toNumber(raw)
|
|
9704
10221
|
},
|
|
@@ -9713,8 +10230,8 @@ var DEFS = [
|
|
|
9713
10230
|
numericAlign: true,
|
|
9714
10231
|
optionKeys: ["currency", "precision"],
|
|
9715
10232
|
format: (v, o) => {
|
|
9716
|
-
const
|
|
9717
|
-
if (
|
|
10233
|
+
const n2 = toNumber(v);
|
|
10234
|
+
if (n2 === null) return null;
|
|
9718
10235
|
const currency = (o.currency || "USD").toUpperCase();
|
|
9719
10236
|
try {
|
|
9720
10237
|
return new Intl.NumberFormat(void 0, {
|
|
@@ -9724,9 +10241,9 @@ var DEFS = [
|
|
|
9724
10241
|
minimumFractionDigits: o.precision,
|
|
9725
10242
|
maximumFractionDigits: o.precision
|
|
9726
10243
|
} : {}
|
|
9727
|
-
}).format(
|
|
10244
|
+
}).format(n2);
|
|
9728
10245
|
} catch {
|
|
9729
|
-
return `${groupedNumber(
|
|
10246
|
+
return `${groupedNumber(n2, { precision: o.precision ?? 2 })} ${currency}`;
|
|
9730
10247
|
}
|
|
9731
10248
|
},
|
|
9732
10249
|
parse: (raw) => toNumber(raw)
|
|
@@ -9742,9 +10259,9 @@ var DEFS = [
|
|
|
9742
10259
|
numericAlign: true,
|
|
9743
10260
|
optionKeys: ["percentScale", "precision"],
|
|
9744
10261
|
format: (v, o) => {
|
|
9745
|
-
const
|
|
9746
|
-
if (
|
|
9747
|
-
const shown = o.percentScale === "fraction" ?
|
|
10262
|
+
const n2 = toNumber(v);
|
|
10263
|
+
if (n2 === null) return null;
|
|
10264
|
+
const shown = o.percentScale === "fraction" ? n2 * 100 : n2;
|
|
9748
10265
|
return `${groupedNumber(shown, o.precision === void 0 ? {} : { precision: o.precision })}%`;
|
|
9749
10266
|
},
|
|
9750
10267
|
parse: (raw) => toNumber(raw)
|
|
@@ -9760,9 +10277,9 @@ var DEFS = [
|
|
|
9760
10277
|
numericAlign: true,
|
|
9761
10278
|
optionKeys: ["durationUnit"],
|
|
9762
10279
|
format: (v, o) => {
|
|
9763
|
-
const
|
|
9764
|
-
if (
|
|
9765
|
-
return formatSignedDuration(
|
|
10280
|
+
const n2 = toNumber(v);
|
|
10281
|
+
if (n2 === null) return null;
|
|
10282
|
+
return formatSignedDuration(n2 * DURATION_TO_SECONDS[o.durationUnit ?? "seconds"]);
|
|
9766
10283
|
},
|
|
9767
10284
|
parse: (raw) => toNumber(raw)
|
|
9768
10285
|
},
|
|
@@ -9777,13 +10294,13 @@ var DEFS = [
|
|
|
9777
10294
|
numericAlign: true,
|
|
9778
10295
|
optionKeys: ["useGrouping", "prefix", "suffix"],
|
|
9779
10296
|
format: (v, o) => {
|
|
9780
|
-
const
|
|
9781
|
-
if (
|
|
9782
|
-
return affix(groupedNumber(Math.trunc(
|
|
10297
|
+
const n2 = toNumber(v);
|
|
10298
|
+
if (n2 === null) return null;
|
|
10299
|
+
return affix(groupedNumber(Math.trunc(n2), { ...o, precision: 0 }), o);
|
|
9783
10300
|
},
|
|
9784
10301
|
parse: (raw) => {
|
|
9785
|
-
const
|
|
9786
|
-
return
|
|
10302
|
+
const n2 = toNumber(raw);
|
|
10303
|
+
return n2 === null ? null : Math.trunc(n2);
|
|
9787
10304
|
}
|
|
9788
10305
|
},
|
|
9789
10306
|
{
|
|
@@ -9797,15 +10314,15 @@ var DEFS = [
|
|
|
9797
10314
|
rich: true,
|
|
9798
10315
|
optionKeys: ["ratingMax"],
|
|
9799
10316
|
format: (v, o) => {
|
|
9800
|
-
const
|
|
9801
|
-
if (
|
|
10317
|
+
const n2 = toNumber(v);
|
|
10318
|
+
if (n2 === null) return null;
|
|
9802
10319
|
const max = o.ratingMax ?? 5;
|
|
9803
|
-
if (
|
|
9804
|
-
return `${
|
|
10320
|
+
if (n2 < 0 || n2 > max) return null;
|
|
10321
|
+
return `${n2} / ${max}`;
|
|
9805
10322
|
},
|
|
9806
10323
|
parse: (raw) => {
|
|
9807
|
-
const
|
|
9808
|
-
return
|
|
10324
|
+
const n2 = toNumber(raw);
|
|
10325
|
+
return n2 === null ? null : Math.round(n2);
|
|
9809
10326
|
}
|
|
9810
10327
|
},
|
|
9811
10328
|
{
|
|
@@ -9818,12 +10335,12 @@ var DEFS = [
|
|
|
9818
10335
|
editor: "number",
|
|
9819
10336
|
numericAlign: true,
|
|
9820
10337
|
format: (v) => {
|
|
9821
|
-
const
|
|
9822
|
-
return
|
|
10338
|
+
const n2 = toNumber(v);
|
|
10339
|
+
return n2 === null ? null : formatFileSize(n2);
|
|
9823
10340
|
},
|
|
9824
10341
|
parse: (raw) => {
|
|
9825
|
-
const
|
|
9826
|
-
return
|
|
10342
|
+
const n2 = toNumber(raw);
|
|
10343
|
+
return n2 === null ? null : Math.trunc(n2);
|
|
9827
10344
|
}
|
|
9828
10345
|
},
|
|
9829
10346
|
// ── Choice ────────────────────────────────────────────────────────────────
|
|
@@ -10233,8 +10750,19 @@ function DirtySavePill({
|
|
|
10233
10750
|
}
|
|
10234
10751
|
|
|
10235
10752
|
// src/data-table/EditableTableCell.tsx
|
|
10236
|
-
import { useEffect as useEffect15, useRef as
|
|
10753
|
+
import { useEffect as useEffect15, useRef as useRef14, useState as useState20 } from "react";
|
|
10237
10754
|
import { jsx as jsx39, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
10755
|
+
function CellRefusal({ reason }) {
|
|
10756
|
+
return /* @__PURE__ */ jsx39(
|
|
10757
|
+
"p",
|
|
10758
|
+
{
|
|
10759
|
+
role: "alert",
|
|
10760
|
+
"data-matrx-cell-refusal": "true",
|
|
10761
|
+
className: "mt-1 text-[11px] leading-snug text-amber-700 dark:text-amber-400",
|
|
10762
|
+
children: reason
|
|
10763
|
+
}
|
|
10764
|
+
);
|
|
10765
|
+
}
|
|
10238
10766
|
function CellEditShell({
|
|
10239
10767
|
href,
|
|
10240
10768
|
display,
|
|
@@ -10281,12 +10809,17 @@ function EditableTableCell({
|
|
|
10281
10809
|
className,
|
|
10282
10810
|
href,
|
|
10283
10811
|
editTrigger = "click",
|
|
10284
|
-
editRequest
|
|
10812
|
+
editRequest,
|
|
10813
|
+
editSeed
|
|
10285
10814
|
}) {
|
|
10286
10815
|
const [open, setOpen] = useState20(false);
|
|
10816
|
+
const [refusal, setRefusal] = useState20(null);
|
|
10287
10817
|
useEffect15(() => {
|
|
10288
10818
|
if (editRequest !== void 0) setOpen(true);
|
|
10289
10819
|
}, [editRequest]);
|
|
10820
|
+
useEffect15(() => {
|
|
10821
|
+
if (!open) setRefusal(null);
|
|
10822
|
+
}, [open]);
|
|
10290
10823
|
const usePencil = Boolean(href) || editTrigger === "pencil";
|
|
10291
10824
|
if (editType === "string") {
|
|
10292
10825
|
return /* @__PURE__ */ jsx39(
|
|
@@ -10299,7 +10832,8 @@ function EditableTableCell({
|
|
|
10299
10832
|
...className === void 0 ? {} : { className },
|
|
10300
10833
|
...href === void 0 ? {} : { href },
|
|
10301
10834
|
usePencil,
|
|
10302
|
-
...editRequest === void 0 ? {} : { editRequest }
|
|
10835
|
+
...editRequest === void 0 ? {} : { editRequest },
|
|
10836
|
+
...editSeed === void 0 || editSeed === null ? {} : { editSeed }
|
|
10303
10837
|
}
|
|
10304
10838
|
);
|
|
10305
10839
|
}
|
|
@@ -10344,25 +10878,33 @@ function EditableTableCell({
|
|
|
10344
10878
|
) }) }),
|
|
10345
10879
|
/* @__PURE__ */ jsx39(TooltipContent, { children: "Edit value" })
|
|
10346
10880
|
] }),
|
|
10347
|
-
/* @__PURE__ */
|
|
10881
|
+
/* @__PURE__ */ jsxs29(
|
|
10348
10882
|
PopoverContent,
|
|
10349
10883
|
{
|
|
10350
10884
|
align: "start",
|
|
10351
10885
|
className: "w-56 p-2",
|
|
10352
10886
|
onClick: (e) => e.stopPropagation(),
|
|
10353
|
-
children:
|
|
10354
|
-
|
|
10355
|
-
|
|
10356
|
-
|
|
10357
|
-
|
|
10358
|
-
|
|
10359
|
-
|
|
10360
|
-
onCommit(next)
|
|
10361
|
-
|
|
10362
|
-
|
|
10363
|
-
|
|
10364
|
-
|
|
10365
|
-
|
|
10887
|
+
children: [
|
|
10888
|
+
/* @__PURE__ */ jsx39(
|
|
10889
|
+
TypedEditor,
|
|
10890
|
+
{
|
|
10891
|
+
editType,
|
|
10892
|
+
value,
|
|
10893
|
+
editOptions,
|
|
10894
|
+
onCommit: (next) => {
|
|
10895
|
+
const refused = onCommit(next);
|
|
10896
|
+
if (typeof refused === "string" && refused) {
|
|
10897
|
+
setRefusal(refused);
|
|
10898
|
+
return;
|
|
10899
|
+
}
|
|
10900
|
+
setRefusal(null);
|
|
10901
|
+
setOpen(false);
|
|
10902
|
+
},
|
|
10903
|
+
onCancel: () => setOpen(false)
|
|
10904
|
+
}
|
|
10905
|
+
),
|
|
10906
|
+
refusal ? /* @__PURE__ */ jsx39(CellRefusal, { reason: refusal }) : null
|
|
10907
|
+
]
|
|
10366
10908
|
}
|
|
10367
10909
|
)
|
|
10368
10910
|
] });
|
|
@@ -10375,17 +10917,31 @@ function InlineStringEditor({
|
|
|
10375
10917
|
className,
|
|
10376
10918
|
href,
|
|
10377
10919
|
usePencil,
|
|
10378
|
-
editRequest
|
|
10920
|
+
editRequest,
|
|
10921
|
+
editSeed
|
|
10379
10922
|
}) {
|
|
10380
10923
|
const [editing, setEditing] = useState20(false);
|
|
10381
10924
|
const [draft, setDraft] = useState20(value);
|
|
10382
|
-
const
|
|
10925
|
+
const [refusal, setRefusal] = useState20(null);
|
|
10926
|
+
const handledEditRequest = useRef14(void 0);
|
|
10927
|
+
const seedRef = useRef14(editSeed);
|
|
10928
|
+
seedRef.current = editSeed;
|
|
10383
10929
|
useEffect15(() => {
|
|
10384
10930
|
if (editRequest === void 0 || handledEditRequest.current === editRequest) return;
|
|
10385
10931
|
handledEditRequest.current = editRequest;
|
|
10386
|
-
setDraft(value);
|
|
10932
|
+
setDraft(seedRef.current ?? value);
|
|
10933
|
+
setRefusal(null);
|
|
10387
10934
|
setEditing(true);
|
|
10388
10935
|
}, [editRequest, value]);
|
|
10936
|
+
const commit = (next) => {
|
|
10937
|
+
const refused = onCommit(next);
|
|
10938
|
+
if (typeof refused === "string" && refused) {
|
|
10939
|
+
setRefusal(refused);
|
|
10940
|
+
return false;
|
|
10941
|
+
}
|
|
10942
|
+
setRefusal(null);
|
|
10943
|
+
return true;
|
|
10944
|
+
};
|
|
10389
10945
|
if (!editing) {
|
|
10390
10946
|
if (usePencil) {
|
|
10391
10947
|
return /* @__PURE__ */ jsx39(
|
|
@@ -10436,32 +10992,38 @@ function InlineStringEditor({
|
|
|
10436
10992
|
/* @__PURE__ */ jsx39(TooltipContent, { children: "Click to edit" })
|
|
10437
10993
|
] });
|
|
10438
10994
|
}
|
|
10439
|
-
return /* @__PURE__ */
|
|
10440
|
-
|
|
10441
|
-
|
|
10442
|
-
|
|
10443
|
-
|
|
10444
|
-
|
|
10445
|
-
|
|
10446
|
-
|
|
10447
|
-
|
|
10448
|
-
|
|
10449
|
-
|
|
10450
|
-
|
|
10451
|
-
|
|
10452
|
-
|
|
10453
|
-
|
|
10454
|
-
|
|
10455
|
-
|
|
10456
|
-
|
|
10457
|
-
|
|
10458
|
-
|
|
10459
|
-
|
|
10460
|
-
|
|
10461
|
-
|
|
10462
|
-
|
|
10463
|
-
|
|
10464
|
-
|
|
10995
|
+
return /* @__PURE__ */ jsxs29("span", { className: "block w-full", children: [
|
|
10996
|
+
/* @__PURE__ */ jsx39(
|
|
10997
|
+
Input,
|
|
10998
|
+
{
|
|
10999
|
+
autoFocus: true,
|
|
11000
|
+
value: draft,
|
|
11001
|
+
onClick: (e) => e.stopPropagation(),
|
|
11002
|
+
onChange: (e) => {
|
|
11003
|
+
setDraft(e.target.value);
|
|
11004
|
+
if (refusal) setRefusal(null);
|
|
11005
|
+
},
|
|
11006
|
+
onBlur: () => {
|
|
11007
|
+
if (commit(draft)) setEditing(false);
|
|
11008
|
+
},
|
|
11009
|
+
onKeyDown: (e) => {
|
|
11010
|
+
if (e.key === "Enter") {
|
|
11011
|
+
e.preventDefault();
|
|
11012
|
+
if (commit(draft)) setEditing(false);
|
|
11013
|
+
}
|
|
11014
|
+
if (e.key === "Escape") {
|
|
11015
|
+
e.preventDefault();
|
|
11016
|
+
setRefusal(null);
|
|
11017
|
+
setEditing(false);
|
|
11018
|
+
}
|
|
11019
|
+
},
|
|
11020
|
+
"aria-invalid": refusal ? true : void 0,
|
|
11021
|
+
className: cn("h-7 text-sm", refusal && "border-amber-500 focus-visible:ring-amber-500"),
|
|
11022
|
+
style: { fontSize: "16px" }
|
|
11023
|
+
}
|
|
11024
|
+
),
|
|
11025
|
+
refusal ? /* @__PURE__ */ jsx39(CellRefusal, { reason: refusal }) : null
|
|
11026
|
+
] });
|
|
10465
11027
|
}
|
|
10466
11028
|
function TypedEditor({
|
|
10467
11029
|
editType,
|
|
@@ -10646,8 +11208,8 @@ function NumberEditor({
|
|
|
10646
11208
|
style: { fontSize: "16px" },
|
|
10647
11209
|
onKeyDown: (e) => {
|
|
10648
11210
|
if (e.key === "Enter") {
|
|
10649
|
-
const
|
|
10650
|
-
if (Number.isFinite(
|
|
11211
|
+
const n2 = Number(draft);
|
|
11212
|
+
if (Number.isFinite(n2)) onCommit(n2);
|
|
10651
11213
|
}
|
|
10652
11214
|
if (e.key === "Escape") onCancel();
|
|
10653
11215
|
}
|
|
@@ -10674,8 +11236,8 @@ function NumberEditor({
|
|
|
10674
11236
|
className: "h-7",
|
|
10675
11237
|
"aria-label": "Apply value",
|
|
10676
11238
|
onClick: () => {
|
|
10677
|
-
const
|
|
10678
|
-
if (Number.isFinite(
|
|
11239
|
+
const n2 = Number(draft);
|
|
11240
|
+
if (Number.isFinite(n2)) onCommit(n2);
|
|
10679
11241
|
},
|
|
10680
11242
|
children: /* @__PURE__ */ jsx39(Check, { className: "h-3.5 w-3.5" })
|
|
10681
11243
|
}
|
|
@@ -11195,6 +11757,8 @@ function filterKindLabel(kind) {
|
|
|
11195
11757
|
return "Boolean";
|
|
11196
11758
|
case "number":
|
|
11197
11759
|
return "Number";
|
|
11760
|
+
case "date":
|
|
11761
|
+
return "Date";
|
|
11198
11762
|
case "auto":
|
|
11199
11763
|
return "Auto";
|
|
11200
11764
|
case false:
|
|
@@ -11483,11 +12047,12 @@ function MatrxDataTableCore({
|
|
|
11483
12047
|
virtualize,
|
|
11484
12048
|
coverage,
|
|
11485
12049
|
spreadsheet,
|
|
12050
|
+
facets,
|
|
11486
12051
|
rowHeight: explicitRowHeight
|
|
11487
12052
|
}) {
|
|
11488
12053
|
const appendQuery = query?.mode === "controlled-append" ? query : null;
|
|
11489
12054
|
const appendQueryKey = appendQuery?.pagination.queryKey ?? null;
|
|
11490
|
-
const committedAppendQueryKey =
|
|
12055
|
+
const committedAppendQueryKey = useRef15(appendQueryKey);
|
|
11491
12056
|
const appendSourceChanged = appendQuery !== null && committedAppendQueryKey.current !== appendQueryKey;
|
|
11492
12057
|
const data = (appendQuery ? appendQuery.pagination.rows : suppliedData) ?? [];
|
|
11493
12058
|
const isLoading = appendQuery ? appendQuery.pagination.loading : suppliedLoading;
|
|
@@ -11502,7 +12067,7 @@ function MatrxDataTableCore({
|
|
|
11502
12067
|
const [savedViewError, setSavedViewError] = useState22(null);
|
|
11503
12068
|
const [toolbarActionError, setToolbarActionError] = useState22(null);
|
|
11504
12069
|
const [toolbarActionPending, setToolbarActionPending] = useState22({ refresh: false, add: false });
|
|
11505
|
-
const toolbarActionPendingRef =
|
|
12070
|
+
const toolbarActionPendingRef = useRef15({ refresh: false, add: false });
|
|
11506
12071
|
const CHECKBOX_TAP_AREA = "h-4 w-4 touch-manipulation";
|
|
11507
12072
|
const mobileCardsClass = mobileCardsBreakpoint === "lg" ? "lg:hidden" : "sm:hidden";
|
|
11508
12073
|
const tableWithCardsClass = mobileCardsBreakpoint === "lg" ? "max-lg:hidden" : "max-sm:hidden";
|
|
@@ -11640,9 +12205,9 @@ function MatrxDataTableCore({
|
|
|
11640
12205
|
const [windowRowSnapshot, setWindowRowSnapshot] = useState22(null);
|
|
11641
12206
|
const editScopeKey = appendQueryKey === null ? "\0local" : `append:${appendQueryKey}`;
|
|
11642
12207
|
const [editsByScope, setEditsByScope] = useState22({});
|
|
11643
|
-
const editRevisionRef =
|
|
12208
|
+
const editRevisionRef = useRef15({});
|
|
11644
12209
|
const [savingByScope, setSavingByScope] = useState22({});
|
|
11645
|
-
const savingScopesRef =
|
|
12210
|
+
const savingScopesRef = useRef15(/* @__PURE__ */ new Set());
|
|
11646
12211
|
const [editRequest, setEditRequest] = useState22(null);
|
|
11647
12212
|
const [confirmForeignDraftDiscard, setConfirmForeignDraftDiscard] = useState22(false);
|
|
11648
12213
|
const edits = editsByScope[editScopeKey]?.values ?? {};
|
|
@@ -11729,13 +12294,13 @@ function MatrxDataTableCore({
|
|
|
11729
12294
|
onWindowRowIdChange,
|
|
11730
12295
|
selectionConfig
|
|
11731
12296
|
]);
|
|
11732
|
-
const scrollRef =
|
|
11733
|
-
const tableRef =
|
|
11734
|
-
const tableHeaderRef =
|
|
11735
|
-
const cardsScrollRef =
|
|
12297
|
+
const scrollRef = useRef15(null);
|
|
12298
|
+
const tableRef = useRef15(null);
|
|
12299
|
+
const tableHeaderRef = useRef15(null);
|
|
12300
|
+
const cardsScrollRef = useRef15(null);
|
|
11736
12301
|
const [documentStickyHeader, setDocumentStickyHeader] = useState22(false);
|
|
11737
|
-
const documentStickyHeaderRef =
|
|
11738
|
-
const previousAppendKeyForScrollReset =
|
|
12302
|
+
const documentStickyHeaderRef = useRef15(false);
|
|
12303
|
+
const previousAppendKeyForScrollReset = useRef15(appendQueryKey);
|
|
11739
12304
|
useLayoutEffect2(() => {
|
|
11740
12305
|
const previous = previousAppendKeyForScrollReset.current;
|
|
11741
12306
|
previousAppendKeyForScrollReset.current = appendQueryKey;
|
|
@@ -11761,7 +12326,7 @@ function MatrxDataTableCore({
|
|
|
11761
12326
|
...appendScrollPolicy?.mode === "scroll" && appendScrollPolicy.thresholdPx !== void 0 ? { thresholdPx: appendScrollPolicy.thresholdPx } : {},
|
|
11762
12327
|
...appendScrollPolicy?.mode === "scroll" && appendScrollPolicy.intentTimeoutMs !== void 0 ? { intentTimeoutMs: appendScrollPolicy.intentTimeoutMs } : {}
|
|
11763
12328
|
});
|
|
11764
|
-
const rootRef =
|
|
12329
|
+
const rootRef = useRef15(null);
|
|
11765
12330
|
useClippedContentGuard(rootRef, {
|
|
11766
12331
|
label: typeof copy === "object" && copy.listLabel ? `Table: ${copy.listLabel}` : "MatrxDataTable"
|
|
11767
12332
|
});
|
|
@@ -11863,11 +12428,11 @@ function MatrxDataTableCore({
|
|
|
11863
12428
|
() => normalizeColumnWidthsForColumns(columnState?.widths, columns)
|
|
11864
12429
|
);
|
|
11865
12430
|
const [fixedTableGeometry, setFixedTableGeometry] = useState22(null);
|
|
11866
|
-
const knownColumnIds =
|
|
11867
|
-
const draggedColumnId =
|
|
11868
|
-
const columnDragActive =
|
|
11869
|
-
const columnDragRaf =
|
|
11870
|
-
const columnDragScrollDirection =
|
|
12431
|
+
const knownColumnIds = useRef15(new Set(columns.map(columnId)));
|
|
12432
|
+
const draggedColumnId = useRef15(null);
|
|
12433
|
+
const columnDragActive = useRef15(false);
|
|
12434
|
+
const columnDragRaf = useRef15(null);
|
|
12435
|
+
const columnDragScrollDirection = useRef15(0);
|
|
11871
12436
|
const [columnDragPreview, setColumnDragPreview] = useState22(null);
|
|
11872
12437
|
const stopColumnDragScroll = useCallback8(() => {
|
|
11873
12438
|
if (columnDragRaf.current !== null) cancelAnimationFrame(columnDragRaf.current);
|
|
@@ -11922,7 +12487,7 @@ function MatrxDataTableCore({
|
|
|
11922
12487
|
() => normalizeColumnWidthsForColumns(columnState?.widths ?? columnWidths, columns),
|
|
11923
12488
|
[columns, columnState?.widths, columnWidths]
|
|
11924
12489
|
);
|
|
11925
|
-
const resizeGestureSnapshotRef =
|
|
12490
|
+
const resizeGestureSnapshotRef = useRef15(null);
|
|
11926
12491
|
const measureVisibleColumnWidths = useCallback8(() => {
|
|
11927
12492
|
const measured = {};
|
|
11928
12493
|
const headers = tableRef.current ? Array.from(tableRef.current.querySelectorAll(
|
|
@@ -12228,7 +12793,7 @@ function MatrxDataTableCore({
|
|
|
12228
12793
|
intelligentSearchEnabled,
|
|
12229
12794
|
searchScope
|
|
12230
12795
|
]);
|
|
12231
|
-
const lastNotifiedViewRows =
|
|
12796
|
+
const lastNotifiedViewRows = useRef15(null);
|
|
12232
12797
|
useEffect16(() => {
|
|
12233
12798
|
if (!onViewChange) {
|
|
12234
12799
|
lastNotifiedViewRows.current = null;
|
|
@@ -12348,7 +12913,7 @@ function MatrxDataTableCore({
|
|
|
12348
12913
|
const columnVirtualizeActive = virtualizeConfig !== null && virtualizeConfig.enabled !== false && virtualizeConfig.columns === true && visibleColumns.length - frozenRunLength > 30 && !hierarchy && mobileCards === void 0;
|
|
12349
12914
|
const [rowWindow, setRowWindow] = useState22(null);
|
|
12350
12915
|
const [columnWindow, setColumnWindow] = useState22(null);
|
|
12351
|
-
const windowInputs =
|
|
12916
|
+
const windowInputs = useRef15({
|
|
12352
12917
|
virtualizeActive: false,
|
|
12353
12918
|
bodyEntryCount: 0,
|
|
12354
12919
|
virtualRowHeight: 40,
|
|
@@ -12498,7 +13063,7 @@ function MatrxDataTableCore({
|
|
|
12498
13063
|
windowed.push({ kind: "spacer", height: effectiveRowWindow.padEnd, place: "end" });
|
|
12499
13064
|
return windowed;
|
|
12500
13065
|
}, [groupedRenderRows, collapsedGroups, paginated, effectiveRowWindow]);
|
|
12501
|
-
const getRowIdRef =
|
|
13066
|
+
const getRowIdRef = useRef15(getRowId);
|
|
12502
13067
|
getRowIdRef.current = getRowId;
|
|
12503
13068
|
const spreadsheetRowIds = useMemo8(
|
|
12504
13069
|
() => paginated.map((row) => getRowIdRef.current(row)),
|
|
@@ -12540,9 +13105,92 @@ function MatrxDataTableCore({
|
|
|
12540
13105
|
...spreadsheet.undoDepth === void 0 ? {} : { undoDepth: spreadsheet.undoDepth },
|
|
12541
13106
|
...spreadsheet.fillHandle === void 0 ? {} : { fillHandle: spreadsheet.fillHandle },
|
|
12542
13107
|
...spreadsheet.paste === void 0 ? {} : { paste: spreadsheet.paste },
|
|
12543
|
-
notify: spreadsheet.notify ?? ((message) => toast.success(message))
|
|
13108
|
+
notify: spreadsheet.notify ?? ((message) => toast.success(message)),
|
|
13109
|
+
onEditRequest: (address, seed) => requestCellEditRef.current(address, seed),
|
|
13110
|
+
...spreadsheet.validateCell ? { validateCell: spreadsheet.validateCell } : {}
|
|
12544
13111
|
} : null
|
|
12545
13112
|
);
|
|
13113
|
+
const sheetRef = useRef15(sheet);
|
|
13114
|
+
sheetRef.current = sheet;
|
|
13115
|
+
const searchValueRef = useRef15(searchValue);
|
|
13116
|
+
searchValueRef.current = searchValue;
|
|
13117
|
+
const facetsEnabled = Boolean(facets && facets.enabled !== false);
|
|
13118
|
+
const [facetState, setFacetState] = useState22({});
|
|
13119
|
+
const facetReadCell = useCallback8(
|
|
13120
|
+
(row, colId) => {
|
|
13121
|
+
if (facets?.readCell) return facets.readCell(row, colId);
|
|
13122
|
+
const col = visibleColumns.find((candidate) => columnId(candidate) === colId);
|
|
13123
|
+
return col ? getFilterValue(row, col) : void 0;
|
|
13124
|
+
},
|
|
13125
|
+
[facets, visibleColumns]
|
|
13126
|
+
);
|
|
13127
|
+
const facetInputsRef = useRef15({ data, facets, facetReadCell });
|
|
13128
|
+
facetInputsRef.current = { data, facets, facetReadCell };
|
|
13129
|
+
const facetRequestRef = useRef15(/* @__PURE__ */ new Map());
|
|
13130
|
+
const requestFacets = useCallback8((colId) => {
|
|
13131
|
+
const { data: rows, facets: config, facetReadCell: readCell } = facetInputsRef.current;
|
|
13132
|
+
if (!config || config.enabled === false) return;
|
|
13133
|
+
const complete = localFacetsAreComplete(rows.length, config.totalRows);
|
|
13134
|
+
const limit = config.limit;
|
|
13135
|
+
if (complete || !config.source) {
|
|
13136
|
+
setFacetState((current) => ({
|
|
13137
|
+
...current,
|
|
13138
|
+
[colId]: {
|
|
13139
|
+
loading: false,
|
|
13140
|
+
data: computeColumnFacets({
|
|
13141
|
+
columnId: colId,
|
|
13142
|
+
rows,
|
|
13143
|
+
readValue: readCell,
|
|
13144
|
+
...limit === void 0 ? {} : { limit },
|
|
13145
|
+
complete
|
|
13146
|
+
})
|
|
13147
|
+
}
|
|
13148
|
+
}));
|
|
13149
|
+
return;
|
|
13150
|
+
}
|
|
13151
|
+
const ticket = (facetRequestRef.current.get(colId) ?? 0) + 1;
|
|
13152
|
+
facetRequestRef.current.set(colId, ticket);
|
|
13153
|
+
setFacetState((current) => ({
|
|
13154
|
+
...current,
|
|
13155
|
+
[colId]: { loading: true, data: current[colId]?.data ?? null }
|
|
13156
|
+
}));
|
|
13157
|
+
void Promise.resolve().then(
|
|
13158
|
+
() => config.source?.({ columnId: colId, search: searchValueRef.current, limit: limit ?? 200 })
|
|
13159
|
+
).then((answer) => {
|
|
13160
|
+
if (facetRequestRef.current.get(colId) !== ticket) return;
|
|
13161
|
+
if (!answer) {
|
|
13162
|
+
setFacetState((current) => ({
|
|
13163
|
+
...current,
|
|
13164
|
+
[colId]: {
|
|
13165
|
+
loading: false,
|
|
13166
|
+
data: computeColumnFacets({
|
|
13167
|
+
columnId: colId,
|
|
13168
|
+
rows: facetInputsRef.current.data,
|
|
13169
|
+
readValue: facetInputsRef.current.facetReadCell,
|
|
13170
|
+
...limit === void 0 ? {} : { limit },
|
|
13171
|
+
complete: false
|
|
13172
|
+
})
|
|
13173
|
+
}
|
|
13174
|
+
}));
|
|
13175
|
+
return;
|
|
13176
|
+
}
|
|
13177
|
+
setFacetState((current) => ({
|
|
13178
|
+
...current,
|
|
13179
|
+
[colId]: { loading: false, data: { ...answer, answeredBy: "source", complete: true } }
|
|
13180
|
+
}));
|
|
13181
|
+
}).catch((error) => {
|
|
13182
|
+
if (facetRequestRef.current.get(colId) !== ticket) return;
|
|
13183
|
+
setFacetState((current) => ({
|
|
13184
|
+
...current,
|
|
13185
|
+
[colId]: { loading: false, data: null, error: describeFacetFailure(error) }
|
|
13186
|
+
}));
|
|
13187
|
+
});
|
|
13188
|
+
}, []);
|
|
13189
|
+
useEffect16(() => {
|
|
13190
|
+
if (!facetsEnabled) return;
|
|
13191
|
+
setFacetState({});
|
|
13192
|
+
facetRequestRef.current = /* @__PURE__ */ new Map();
|
|
13193
|
+
}, [facetsEnabled, data, searchValue]);
|
|
12546
13194
|
useEffect16(() => {
|
|
12547
13195
|
if (!controlledQuery || controlledQuery.state.page === safePage) return;
|
|
12548
13196
|
emitControlledQueryChange({ page: safePage });
|
|
@@ -12587,11 +13235,11 @@ function MatrxDataTableCore({
|
|
|
12587
13235
|
});
|
|
12588
13236
|
const hasActiveFilters = activeFilterCount > 0 || Boolean(searchValue.trim()) || intelligentSearchEnabled && searchScope !== "all" || Boolean(anyOfValue.trim()) || completeLayeredFilterRules(layeredFilters).length > 0 || facetActive;
|
|
12589
13237
|
const changeCount = useMemo8(() => {
|
|
12590
|
-
let
|
|
13238
|
+
let n2 = 0;
|
|
12591
13239
|
for (const fields of Object.values(edits)) {
|
|
12592
|
-
|
|
13240
|
+
n2 += Object.keys(fields).length;
|
|
12593
13241
|
}
|
|
12594
|
-
return
|
|
13242
|
+
return n2;
|
|
12595
13243
|
}, [edits]);
|
|
12596
13244
|
const showSearch = toolbar?.search !== false;
|
|
12597
13245
|
const openDetail = (row) => {
|
|
@@ -12670,6 +13318,23 @@ function MatrxDataTableCore({
|
|
|
12670
13318
|
icon: void 0
|
|
12671
13319
|
} : emptyState;
|
|
12672
13320
|
const commitCell = (rowId, field, next) => {
|
|
13321
|
+
if (edit?.validate) {
|
|
13322
|
+
const row = data.find((candidate) => getRowId(candidate) === rowId);
|
|
13323
|
+
if (row) {
|
|
13324
|
+
let refusal;
|
|
13325
|
+
try {
|
|
13326
|
+
refusal = edit.validate({
|
|
13327
|
+
row: applyRowEdits(row, edits[rowId]),
|
|
13328
|
+
rowId,
|
|
13329
|
+
columnId: field,
|
|
13330
|
+
value: next
|
|
13331
|
+
});
|
|
13332
|
+
} catch {
|
|
13333
|
+
refusal = void 0;
|
|
13334
|
+
}
|
|
13335
|
+
if (refusal) return refusal;
|
|
13336
|
+
}
|
|
13337
|
+
}
|
|
12673
13338
|
const scope = editScopeKey;
|
|
12674
13339
|
const nextEdits = { [rowId]: { [field]: next } };
|
|
12675
13340
|
const revision = setCellEdit(rowId, field, next);
|
|
@@ -12714,9 +13379,29 @@ function MatrxDataTableCore({
|
|
|
12714
13379
|
setEditRequest((current) => ({
|
|
12715
13380
|
rowId: getRowId(row),
|
|
12716
13381
|
field,
|
|
12717
|
-
nonce: (current?.nonce ?? 0) + 1
|
|
13382
|
+
nonce: (current?.nonce ?? 0) + 1,
|
|
13383
|
+
seed: null
|
|
13384
|
+
}));
|
|
13385
|
+
};
|
|
13386
|
+
const requestCellEdit = (address, seed) => {
|
|
13387
|
+
if (!editEnabled) return false;
|
|
13388
|
+
const row = data.find((candidate) => getRowId(candidate) === address.rowId);
|
|
13389
|
+
if (!row) return false;
|
|
13390
|
+
const column = visibleColumns.find(
|
|
13391
|
+
(candidate) => columnId(candidate) === address.fieldName
|
|
13392
|
+
);
|
|
13393
|
+
if (!column?.editable || !(column.editableIf?.(row) ?? true)) return false;
|
|
13394
|
+
const field = column.accessorKey ? String(column.accessorKey) : columnId(column);
|
|
13395
|
+
setEditRequest((current) => ({
|
|
13396
|
+
rowId: address.rowId,
|
|
13397
|
+
field,
|
|
13398
|
+
nonce: (current?.nonce ?? 0) + 1,
|
|
13399
|
+
seed
|
|
12718
13400
|
}));
|
|
13401
|
+
return true;
|
|
12719
13402
|
};
|
|
13403
|
+
const requestCellEditRef = useRef15(requestCellEdit);
|
|
13404
|
+
requestCellEditRef.current = requestCellEdit;
|
|
12720
13405
|
const buildRecordControls = (row) => {
|
|
12721
13406
|
const rowId = getRowId(row);
|
|
12722
13407
|
const pending = edits[rowId];
|
|
@@ -12957,17 +13642,78 @@ function MatrxDataTableCore({
|
|
|
12957
13642
|
setEdits({});
|
|
12958
13643
|
edit?.onCancel?.();
|
|
12959
13644
|
};
|
|
12960
|
-
|
|
12961
|
-
|
|
12962
|
-
return host.rowContextRegistry.register(tableContextMenuInstanceId, (rowId) => {
|
|
13645
|
+
const resolveMenuLevel = (target) => {
|
|
13646
|
+
const rowFor = (rowId) => {
|
|
12963
13647
|
const row = data.find((candidate) => getRowId(candidate) === rowId);
|
|
12964
13648
|
if (!row) return null;
|
|
12965
|
-
|
|
12966
|
-
|
|
12967
|
-
|
|
12968
|
-
|
|
12969
|
-
|
|
12970
|
-
|
|
13649
|
+
return applyRowEdits(row, edits[rowId]);
|
|
13650
|
+
};
|
|
13651
|
+
const columnFor = (id) => visibleColumns.find((col) => columnId(col) === id);
|
|
13652
|
+
const labelFor = (col, id) => col?.label ?? (typeof col?.header === "string" ? col.header : id);
|
|
13653
|
+
const fromHost = (payload) => host.createDefaultMenuContext?.(payload) ?? null;
|
|
13654
|
+
switch (target.level) {
|
|
13655
|
+
case "row": {
|
|
13656
|
+
if (!target.rowId) return null;
|
|
13657
|
+
const displayRow = rowFor(target.rowId);
|
|
13658
|
+
if (!displayRow) return null;
|
|
13659
|
+
const controls = buildRecordControls(displayRow);
|
|
13660
|
+
return contextMenu?.resolveRowContext?.(displayRow, controls) ?? fromHost({ level: "row", row: displayRow, rowId: target.rowId, controls });
|
|
13661
|
+
}
|
|
13662
|
+
case "cell": {
|
|
13663
|
+
if (!target.rowId || !target.columnId) return null;
|
|
13664
|
+
const displayRow = rowFor(target.rowId);
|
|
13665
|
+
const col = columnFor(target.columnId);
|
|
13666
|
+
if (!displayRow || !col) return null;
|
|
13667
|
+
const controls = buildRecordControls(displayRow);
|
|
13668
|
+
const value = spreadsheet?.readCell ? spreadsheet.readCell(displayRow, target.columnId) : getCellValue(displayRow, col);
|
|
13669
|
+
const args = {
|
|
13670
|
+
row: displayRow,
|
|
13671
|
+
rowId: target.rowId,
|
|
13672
|
+
columnId: target.columnId,
|
|
13673
|
+
columnLabel: labelFor(col, target.columnId),
|
|
13674
|
+
value,
|
|
13675
|
+
text: stringifyCellValue(value),
|
|
13676
|
+
controls
|
|
13677
|
+
};
|
|
13678
|
+
return contextMenu?.resolveCellContext?.(args) ?? fromHost({ level: "cell", ...args });
|
|
13679
|
+
}
|
|
13680
|
+
case "column": {
|
|
13681
|
+
if (!target.columnId) return null;
|
|
13682
|
+
const col = columnFor(target.columnId);
|
|
13683
|
+
if (!col) return null;
|
|
13684
|
+
const args = {
|
|
13685
|
+
columnId: target.columnId,
|
|
13686
|
+
columnLabel: labelFor(col, target.columnId),
|
|
13687
|
+
values: paginated.map(
|
|
13688
|
+
(row) => getCellValue(applyRowEdits(row, edits[getRowId(row)]), col)
|
|
13689
|
+
)
|
|
13690
|
+
};
|
|
13691
|
+
return contextMenu?.resolveColumnContext?.(args) ?? fromHost({ level: "column", ...args });
|
|
13692
|
+
}
|
|
13693
|
+
case "selection": {
|
|
13694
|
+
const addresses = sheetRef.current.selectionAddresses();
|
|
13695
|
+
const cellCount = addresses.rowIds.length * addresses.columnIds.length;
|
|
13696
|
+
if (cellCount <= 1) {
|
|
13697
|
+
return resolveMenuLevel({ ...target, level: "cell" });
|
|
13698
|
+
}
|
|
13699
|
+
const args = { ...addresses, tsv: sheetRef.current.selectionTsv(), cellCount };
|
|
13700
|
+
return contextMenu?.resolveSelectionContext?.(args) ?? fromHost({ level: "selection", ...args });
|
|
13701
|
+
}
|
|
13702
|
+
case "table": {
|
|
13703
|
+
const args = { rowCount: data.length, columnIds: visibleColumns.map((col) => columnId(col)) };
|
|
13704
|
+
return contextMenu?.resolveTableContext?.(args) ?? fromHost({ level: "table", ...args });
|
|
13705
|
+
}
|
|
13706
|
+
}
|
|
13707
|
+
};
|
|
13708
|
+
const resolveMenuLevelRef = useRef15(resolveMenuLevel);
|
|
13709
|
+
resolveMenuLevelRef.current = resolveMenuLevel;
|
|
13710
|
+
useEffect16(() => {
|
|
13711
|
+
if (!host.rowContextRegistry) return;
|
|
13712
|
+
return host.rowContextRegistry.register(
|
|
13713
|
+
tableContextMenuInstanceId,
|
|
13714
|
+
(target) => resolveMenuLevelRef.current(target)
|
|
13715
|
+
);
|
|
13716
|
+
}, [host.rowContextRegistry, tableContextMenuInstanceId]);
|
|
12971
13717
|
const showActionsCol = windowEnabled || Boolean(rowActions) || showInlineRowCopy;
|
|
12972
13718
|
const selectedIdSet = useMemo8(
|
|
12973
13719
|
() => new Set(selection?.selectedIds ?? []),
|
|
@@ -12985,7 +13731,7 @@ function MatrxDataTableCore({
|
|
|
12985
13731
|
() => data.filter((row) => selectedIdSet.has(getRowId(row))),
|
|
12986
13732
|
[data, selectedIdSet, getRowId]
|
|
12987
13733
|
);
|
|
12988
|
-
const lastToggledIndex =
|
|
13734
|
+
const lastToggledIndex = useRef15(null);
|
|
12989
13735
|
const setSelectedIds = (next) => selection?.onSelectedIdsChange([...next]);
|
|
12990
13736
|
const toggleRowSelected = (index, shiftKey) => {
|
|
12991
13737
|
if (!selection) return;
|
|
@@ -13049,8 +13795,19 @@ function MatrxDataTableCore({
|
|
|
13049
13795
|
dirty: Boolean(rowEdits && field in rowEdits),
|
|
13050
13796
|
onCommit: (next) => commitCell(id, field, next),
|
|
13051
13797
|
...href === void 0 ? {} : { href },
|
|
13052
|
-
...
|
|
13053
|
-
|
|
13798
|
+
...spreadsheetEnabled ? {
|
|
13799
|
+
// 🚨 THE CLICK LAW, enforced where the two paths meet. In a grid
|
|
13800
|
+
// with spreadsheet gestures a single click SELECTS a cell — it
|
|
13801
|
+
// may never drop a person into a free-text buffer, because the
|
|
13802
|
+
// same click is how they start a range, and an editor that opens
|
|
13803
|
+
// under the pointer eats the drag and the next keystroke. So the
|
|
13804
|
+
// editor opens the way it does in Excel: Enter, F2, the hover
|
|
13805
|
+
// pencil, or simply typing. An explicit `editTrigger: "click"`
|
|
13806
|
+
// does not override this; the law is the table's, not the
|
|
13807
|
+
// column's.
|
|
13808
|
+
editTrigger: "pencil"
|
|
13809
|
+
} : col.editTrigger === void 0 ? {} : { editTrigger: col.editTrigger },
|
|
13810
|
+
...editRequest?.rowId === id && editRequest.field === field ? { editRequest: editRequest.nonce, editSeed: editRequest.seed } : {}
|
|
13054
13811
|
}
|
|
13055
13812
|
);
|
|
13056
13813
|
}
|
|
@@ -13808,6 +14565,7 @@ function MatrxDataTableCore({
|
|
|
13808
14565
|
"th",
|
|
13809
14566
|
{
|
|
13810
14567
|
"data-matrx-table-column-id": id,
|
|
14568
|
+
"data-matrx-header-column-id": id,
|
|
13811
14569
|
"data-matrx-column-drag-shadow": isColumnDragShadow ? "true" : void 0,
|
|
13812
14570
|
"aria-sort": isSorted ? sort?.direction === "asc" ? "ascending" : "descending" : void 0,
|
|
13813
14571
|
className: cn(
|
|
@@ -13844,6 +14602,12 @@ function MatrxDataTableCore({
|
|
|
13844
14602
|
{
|
|
13845
14603
|
label: col.header,
|
|
13846
14604
|
labelText: headerLabel,
|
|
14605
|
+
...facetsEnabled ? {
|
|
14606
|
+
facets: facetState[id]?.data ?? null,
|
|
14607
|
+
facetsLoading: facetState[id]?.loading ?? false,
|
|
14608
|
+
...facetState[id]?.error === void 0 ? {} : { facetsError: facetState[id]?.error },
|
|
14609
|
+
onFilterOpen: () => requestFacets(id)
|
|
14610
|
+
} : {},
|
|
13847
14611
|
sortable: col.sortable !== false,
|
|
13848
14612
|
isSorted: Boolean(isSorted),
|
|
13849
14613
|
sortDirection: sort?.direction ?? defaultSortDirection,
|
|
@@ -14170,7 +14934,7 @@ function MatrxDataTableCore({
|
|
|
14170
14934
|
"div",
|
|
14171
14935
|
{
|
|
14172
14936
|
"data-matrx-cell-content": true,
|
|
14173
|
-
className: "min-w-0 max-w-full flex-1 whitespace-normal break-words [overflow-wrap:anywhere] sm:[&_*]:min-w-0 sm:[&_*]:whitespace-normal sm:[&_*]:[overflow-wrap:anywhere] sm:[&_.truncate]:whitespace-nowrap sm:[&_[data-slot=badge]]:whitespace-nowrap sm:[&_[data-slot=badge]]:[overflow-wrap:normal] sm:[&_[data-matrx-cell-control]]:w-max sm:[&_[data-matrx-cell-control]]:min-w-max sm:[&_[data-matrx-cell-control]]:max-w-none sm:[&_[data-matrx-cell-control]]:whitespace-nowrap sm:[&_[data-matrx-cell-control]]:[overflow-wrap:normal] sm:[&_[data-matrx-cell-control]_*]:whitespace-nowrap sm:[&_[data-matrx-cell-control]_*]:[overflow-wrap:normal]",
|
|
14937
|
+
className: "min-w-0 max-w-full flex-1 whitespace-normal break-words [overflow-wrap:anywhere] sm:[&_*]:min-w-0 sm:[&_*]:whitespace-normal sm:[&_*]:[overflow-wrap:anywhere] sm:[&_.truncate]:whitespace-nowrap sm:[&_[data-slot=badge]]:whitespace-nowrap sm:[&_[data-slot=badge]]:[overflow-wrap:normal] sm:[&_[data-matrx-cell-control]]:w-max sm:[&_[data-matrx-cell-control]]:min-w-max sm:[&_[data-matrx-cell-control]]:max-w-none sm:[&_[data-matrx-cell-control]]:whitespace-nowrap sm:[&_[data-matrx-cell-control]]:[overflow-wrap:normal] sm:[&_[data-matrx-cell-control]_*]:whitespace-nowrap sm:[&_[data-matrx-cell-control]_*]:[overflow-wrap:normal] [&_[data-matrx-cell-fill]]:!w-full [&_[data-matrx-cell-fill]]:!min-w-0 [&_[data-matrx-cell-fill]]:!max-w-full sm:[&_[data-matrx-cell-fill]]:!w-full sm:[&_[data-matrx-cell-fill]]:!min-w-0 sm:[&_[data-matrx-cell-fill]]:!max-w-full",
|
|
14174
14938
|
children: renderRecordCell(row, col, index)
|
|
14175
14939
|
}
|
|
14176
14940
|
)
|
|
@@ -14518,8 +15282,8 @@ function MatrxDataTableCore({
|
|
|
14518
15282
|
itemsPerPage: pageSize === 0 && allRowsAreLoaded ? 0 : effectivePageSize,
|
|
14519
15283
|
currentPage: safePage,
|
|
14520
15284
|
onPageChange: setPage,
|
|
14521
|
-
onItemsPerPageChange: (
|
|
14522
|
-
setPageSize(
|
|
15285
|
+
onItemsPerPageChange: (n2) => {
|
|
15286
|
+
setPageSize(n2);
|
|
14523
15287
|
if (!controlledQuery) setPage(1);
|
|
14524
15288
|
},
|
|
14525
15289
|
pageSizeOptions: pageSizeOptions.filter((size) => size > 0),
|
|
@@ -15478,6 +16242,8 @@ export {
|
|
|
15478
16242
|
SavedViewsControl,
|
|
15479
16243
|
TABLE_STYLE_METADATA_KEY,
|
|
15480
16244
|
TABLE_STYLE_VERSION,
|
|
16245
|
+
TIME_RANGE_PRESETS,
|
|
16246
|
+
TIME_RANGE_PRESET_VALUES,
|
|
15481
16247
|
TableTitleRow,
|
|
15482
16248
|
TableViewTabs,
|
|
15483
16249
|
UNKNOWN_TOTAL_BADGE,
|
|
@@ -15501,6 +16267,7 @@ export {
|
|
|
15501
16267
|
computeVariableWindow,
|
|
15502
16268
|
computeWindow,
|
|
15503
16269
|
createUndoStack,
|
|
16270
|
+
dateFilterBounds,
|
|
15504
16271
|
describeCoverage,
|
|
15505
16272
|
detectSeries,
|
|
15506
16273
|
directClickKinds,
|