@ai-matrx/design-system 0.25.0 → 0.26.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 +76 -0
- package/dist/data-table/copy-helpers.d.cts +2 -1
- package/dist/data-table/copy-helpers.d.ts +2 -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/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.d.cts +2 -1
- package/dist/data-table/filter-engine.d.ts +2 -1
- package/dist/data-table/host.cjs.map +1 -1
- package/dist/data-table/host.d.cts +13 -3
- package/dist/data-table/host.d.ts +13 -3
- package/dist/data-table/host.js.map +1 -1
- package/dist/data-table/index.cjs +680 -145
- package/dist/data-table/index.cjs.map +1 -1
- package/dist/data-table/index.d.cts +4 -2
- package/dist/data-table/index.d.ts +4 -2
- package/dist/data-table/index.js +718 -182
- package/dist/data-table/index.js.map +1 -1
- package/dist/data-table/infer-filter.d.cts +2 -1
- package/dist/data-table/infer-filter.d.ts +2 -1
- package/dist/data-table/layered-filters.d.cts +2 -1
- package/dist/data-table/layered-filters.d.ts +2 -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.d.cts +2 -1
- package/dist/data-table/query-control.d.ts +2 -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 +2 -1
- package/dist/data-table/types.d.ts +2 -1
- package/dist/data-table/url-state.d.cts +2 -1
- package/dist/data-table/url-state.d.ts +2 -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.d.cts +2 -1
- package/dist/data-table/xlsx.d.ts +2 -1
- package/dist/{types-nlLCMiqd.d.ts → types-Cu5_eUG1.d.ts} +115 -3
- package/dist/{types-CmQrOz-T.d.cts → types-DrJXAAoD.d.cts} +115 -3
- package/package.json +21 -1
|
@@ -5227,10 +5227,10 @@ function passesColumnFilter(value, filter) {
|
|
|
5227
5227
|
if (raw === "") return false;
|
|
5228
5228
|
const normalized = raw.replace(/[^0-9.-]/g, "");
|
|
5229
5229
|
if (normalized === "") return false;
|
|
5230
|
-
const
|
|
5231
|
-
if (!Number.isFinite(
|
|
5232
|
-
if (filter.min !== void 0 &&
|
|
5233
|
-
if (filter.max !== void 0 &&
|
|
5230
|
+
const n2 = typeof value === "number" ? value : Number(normalized);
|
|
5231
|
+
if (!Number.isFinite(n2)) return false;
|
|
5232
|
+
if (filter.min !== void 0 && n2 < filter.min) return false;
|
|
5233
|
+
if (filter.max !== void 0 && n2 > filter.max) return false;
|
|
5234
5234
|
return true;
|
|
5235
5235
|
}
|
|
5236
5236
|
}
|
|
@@ -5293,26 +5293,26 @@ function filterAndSortRows(rows, columns, columnFilters, sort, globalSearch, any
|
|
|
5293
5293
|
return result;
|
|
5294
5294
|
}
|
|
5295
5295
|
function countActiveColumnFilters(filters) {
|
|
5296
|
-
let
|
|
5296
|
+
let n2 = 0;
|
|
5297
5297
|
for (const f of Object.values(filters)) {
|
|
5298
5298
|
if (!f) continue;
|
|
5299
5299
|
switch (f.kind) {
|
|
5300
5300
|
case "text":
|
|
5301
|
-
if (f.value.trim() || f.mode && f.mode !== "contains")
|
|
5301
|
+
if (f.value.trim() || f.mode && f.mode !== "contains") n2 += 1;
|
|
5302
5302
|
break;
|
|
5303
5303
|
case "select":
|
|
5304
5304
|
if (f.values !== void 0 || f.value && f.value !== "__all__")
|
|
5305
|
-
|
|
5305
|
+
n2 += 1;
|
|
5306
5306
|
break;
|
|
5307
5307
|
case "boolean":
|
|
5308
|
-
|
|
5308
|
+
n2 += 1;
|
|
5309
5309
|
break;
|
|
5310
5310
|
case "number":
|
|
5311
|
-
if (f.min !== void 0 || f.max !== void 0)
|
|
5311
|
+
if (f.min !== void 0 || f.max !== void 0) n2 += 1;
|
|
5312
5312
|
break;
|
|
5313
5313
|
}
|
|
5314
5314
|
}
|
|
5315
|
-
return
|
|
5315
|
+
return n2;
|
|
5316
5316
|
}
|
|
5317
5317
|
function isColumnFilterActive(filter) {
|
|
5318
5318
|
if (!filter) return false;
|
|
@@ -5591,8 +5591,8 @@ function parseLayeredFilters(raw) {
|
|
|
5591
5591
|
}
|
|
5592
5592
|
}
|
|
5593
5593
|
function positiveInt(raw, fallback) {
|
|
5594
|
-
const
|
|
5595
|
-
return Number.isFinite(
|
|
5594
|
+
const n2 = raw ? Number.parseInt(raw, 10) : Number.NaN;
|
|
5595
|
+
return Number.isFinite(n2) && n2 > 0 ? n2 : fallback;
|
|
5596
5596
|
}
|
|
5597
5597
|
function tableUrlParamPrefix(tableId) {
|
|
5598
5598
|
if (!/^[a-z][a-z0-9-]{0,63}$/.test(tableId)) {
|
|
@@ -5931,6 +5931,95 @@ var CommandShortcut = ({
|
|
|
5931
5931
|
};
|
|
5932
5932
|
CommandShortcut.displayName = "CommandShortcut";
|
|
5933
5933
|
|
|
5934
|
+
// src/data-table/facets.ts
|
|
5935
|
+
var MAX_LISTABLE_FACET_LENGTH = 300;
|
|
5936
|
+
var DEFAULT_FACET_LIMIT = 200;
|
|
5937
|
+
var MAX_FACET_LIMIT = 500;
|
|
5938
|
+
function facetText(raw) {
|
|
5939
|
+
if (raw === null || raw === void 0) return "";
|
|
5940
|
+
if (typeof raw === "object") {
|
|
5941
|
+
try {
|
|
5942
|
+
return JSON.stringify(raw);
|
|
5943
|
+
} catch {
|
|
5944
|
+
return String(raw);
|
|
5945
|
+
}
|
|
5946
|
+
}
|
|
5947
|
+
return String(raw);
|
|
5948
|
+
}
|
|
5949
|
+
function computeColumnFacets(args) {
|
|
5950
|
+
const { columnId: columnId2, rows, readValue: readValue2 } = args;
|
|
5951
|
+
const limit = Math.min(Math.max(args.limit ?? DEFAULT_FACET_LIMIT, 1), MAX_FACET_LIMIT);
|
|
5952
|
+
const counts = /* @__PURE__ */ new Map();
|
|
5953
|
+
const longValues = /* @__PURE__ */ new Set();
|
|
5954
|
+
let blank = 0;
|
|
5955
|
+
let maxLength = 0;
|
|
5956
|
+
for (const row of rows) {
|
|
5957
|
+
let raw;
|
|
5958
|
+
try {
|
|
5959
|
+
raw = readValue2(row, columnId2);
|
|
5960
|
+
} catch {
|
|
5961
|
+
raw = void 0;
|
|
5962
|
+
}
|
|
5963
|
+
const trimmed = facetText(raw).trim();
|
|
5964
|
+
if (trimmed === "") {
|
|
5965
|
+
blank += 1;
|
|
5966
|
+
continue;
|
|
5967
|
+
}
|
|
5968
|
+
if (trimmed.length > maxLength) maxLength = trimmed.length;
|
|
5969
|
+
if (trimmed.length > MAX_LISTABLE_FACET_LENGTH) {
|
|
5970
|
+
longValues.add(trimmed);
|
|
5971
|
+
continue;
|
|
5972
|
+
}
|
|
5973
|
+
counts.set(trimmed, (counts.get(trimmed) ?? 0) + 1);
|
|
5974
|
+
}
|
|
5975
|
+
const values = [...counts.entries()].map(([value, count]) => ({ value, count })).sort((a, b) => b.count - a.count || a.value.localeCompare(b.value)).slice(0, limit);
|
|
5976
|
+
return {
|
|
5977
|
+
columnId: columnId2,
|
|
5978
|
+
totalRows: rows.length,
|
|
5979
|
+
filled: rows.length - blank,
|
|
5980
|
+
blank,
|
|
5981
|
+
distinctCount: counts.size + longValues.size,
|
|
5982
|
+
maxLength,
|
|
5983
|
+
unlistable: longValues.size,
|
|
5984
|
+
limit,
|
|
5985
|
+
truncated: counts.size > limit,
|
|
5986
|
+
values,
|
|
5987
|
+
answeredBy: "local",
|
|
5988
|
+
complete: args.complete ?? true
|
|
5989
|
+
};
|
|
5990
|
+
}
|
|
5991
|
+
function localFacetsAreComplete(loadedRowCount, total) {
|
|
5992
|
+
if (total === void 0 || !Number.isFinite(total) || total < 0) return false;
|
|
5993
|
+
return loadedRowCount >= total;
|
|
5994
|
+
}
|
|
5995
|
+
var NUMBERS = new Intl.NumberFormat("en-US");
|
|
5996
|
+
function n(value) {
|
|
5997
|
+
try {
|
|
5998
|
+
return NUMBERS.format(value);
|
|
5999
|
+
} catch {
|
|
6000
|
+
return String(value);
|
|
6001
|
+
}
|
|
6002
|
+
}
|
|
6003
|
+
function describeFacetSource(facets, noun = "row") {
|
|
6004
|
+
if (!facets) return "";
|
|
6005
|
+
const plural2 = `${noun}s`;
|
|
6006
|
+
if (!facets.complete) {
|
|
6007
|
+
return `These counts cover the ${n(facets.totalRows)} ${plural2} loaded here, not the whole table.`;
|
|
6008
|
+
}
|
|
6009
|
+
if (facets.truncated) {
|
|
6010
|
+
return `Showing the ${n(facets.values.length)} most common of ${n(facets.distinctCount)} values.`;
|
|
6011
|
+
}
|
|
6012
|
+
if (facets.unlistable > 0) {
|
|
6013
|
+
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"}.`;
|
|
6014
|
+
}
|
|
6015
|
+
return "";
|
|
6016
|
+
}
|
|
6017
|
+
var FACETS_LOADING_NOTICE = "Counting values\u2026";
|
|
6018
|
+
function describeFacetFailure(error) {
|
|
6019
|
+
const detail = error instanceof Error ? error.message : String(error ?? "");
|
|
6020
|
+
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.";
|
|
6021
|
+
}
|
|
6022
|
+
|
|
5934
6023
|
// src/data-table/column-marker.ts
|
|
5935
6024
|
var MARKER_ACCESSORS = {
|
|
5936
6025
|
favorite: "favorite",
|
|
@@ -5998,6 +6087,10 @@ function ColumnHeaderCell({
|
|
|
5998
6087
|
filterFooterHint,
|
|
5999
6088
|
allowNegation = false,
|
|
6000
6089
|
allowNullModes = false,
|
|
6090
|
+
facets,
|
|
6091
|
+
facetsLoading = false,
|
|
6092
|
+
facetsError,
|
|
6093
|
+
onFilterOpen,
|
|
6001
6094
|
reorderColumn
|
|
6002
6095
|
}) {
|
|
6003
6096
|
const reorderEnabled = reorderColumn !== void 0;
|
|
@@ -6032,6 +6125,11 @@ function ColumnHeaderCell({
|
|
|
6032
6125
|
setPendingNegation(filterValue?.negated ?? false);
|
|
6033
6126
|
}
|
|
6034
6127
|
}, [filterOpen, filterValue]);
|
|
6128
|
+
const notifyOpen = (0, import_react13.useRef)(onFilterOpen);
|
|
6129
|
+
notifyOpen.current = onFilterOpen;
|
|
6130
|
+
(0, import_react13.useEffect)(() => {
|
|
6131
|
+
if (filterOpen) notifyOpen.current?.();
|
|
6132
|
+
}, [filterOpen]);
|
|
6035
6133
|
const applyFilter = () => {
|
|
6036
6134
|
onFilterChange(draftFilter);
|
|
6037
6135
|
setFilterOpen(false);
|
|
@@ -6126,6 +6224,9 @@ function ColumnHeaderCell({
|
|
|
6126
6224
|
selectOptions,
|
|
6127
6225
|
selectSingle,
|
|
6128
6226
|
selectAllowCustom,
|
|
6227
|
+
facets: facets ?? null,
|
|
6228
|
+
facetsLoading,
|
|
6229
|
+
...facetsError === void 0 ? {} : { facetsError },
|
|
6129
6230
|
...markerLabels ? {
|
|
6130
6231
|
booleanLabels: {
|
|
6131
6232
|
all: "All",
|
|
@@ -6350,8 +6451,43 @@ function FilterBody({
|
|
|
6350
6451
|
selectSingle = false,
|
|
6351
6452
|
selectAllowCustom = false,
|
|
6352
6453
|
allowNullModes = false,
|
|
6353
|
-
booleanLabels
|
|
6454
|
+
booleanLabels,
|
|
6455
|
+
facets = null,
|
|
6456
|
+
facetsLoading = false,
|
|
6457
|
+
facetsError
|
|
6354
6458
|
}) {
|
|
6459
|
+
const checklist = facetsLoading || facetsError || facets && (facets.values.length > 0 || facets.blank > 0) ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
6460
|
+
FacetChecklist,
|
|
6461
|
+
{
|
|
6462
|
+
facets,
|
|
6463
|
+
loading: facetsLoading,
|
|
6464
|
+
...facetsError === void 0 ? {} : { error: facetsError },
|
|
6465
|
+
value,
|
|
6466
|
+
onChange
|
|
6467
|
+
}
|
|
6468
|
+
) : null;
|
|
6469
|
+
if (checklist && kind === "select" && facets && facets.values.length > 0) {
|
|
6470
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "space-y-2", children: checklist });
|
|
6471
|
+
}
|
|
6472
|
+
if (checklist) {
|
|
6473
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "space-y-2", children: [
|
|
6474
|
+
checklist,
|
|
6475
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "h-px bg-border" }),
|
|
6476
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
6477
|
+
FilterBody,
|
|
6478
|
+
{
|
|
6479
|
+
kind,
|
|
6480
|
+
value,
|
|
6481
|
+
onChange,
|
|
6482
|
+
selectOptions,
|
|
6483
|
+
selectSingle,
|
|
6484
|
+
selectAllowCustom,
|
|
6485
|
+
allowNullModes,
|
|
6486
|
+
...booleanLabels === void 0 ? {} : { booleanLabels }
|
|
6487
|
+
}
|
|
6488
|
+
)
|
|
6489
|
+
] });
|
|
6490
|
+
}
|
|
6355
6491
|
if (kind === "text") {
|
|
6356
6492
|
const text = value?.kind === "text" ? value.value : "";
|
|
6357
6493
|
const mode = (value?.kind === "text" ? value.mode : void 0) ?? "contains";
|
|
@@ -6462,6 +6598,112 @@ function FilterBody({
|
|
|
6462
6598
|
}
|
|
6463
6599
|
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(NumberFilterBody, { value, onChange });
|
|
6464
6600
|
}
|
|
6601
|
+
function FacetChecklist({
|
|
6602
|
+
facets,
|
|
6603
|
+
loading,
|
|
6604
|
+
error,
|
|
6605
|
+
value,
|
|
6606
|
+
onChange
|
|
6607
|
+
}) {
|
|
6608
|
+
const [query, setQuery] = (0, import_react13.useState)("");
|
|
6609
|
+
const selected = value?.kind === "select" ? value.values ?? (value.value && value.value !== "__all__" ? [value.value] : []) : [];
|
|
6610
|
+
const selectedSet = new Set(selected);
|
|
6611
|
+
const rows = (0, import_react13.useMemo)(() => {
|
|
6612
|
+
if (!facets) return [];
|
|
6613
|
+
const listed = facets.values.map((entry) => ({
|
|
6614
|
+
value: entry.value,
|
|
6615
|
+
label: entry.value,
|
|
6616
|
+
count: entry.count
|
|
6617
|
+
}));
|
|
6618
|
+
const withBlank = facets.blank > 0 ? [{ value: "", label: "(empty)", count: facets.blank }, ...listed] : listed;
|
|
6619
|
+
const q = query.trim().toLowerCase();
|
|
6620
|
+
if (!q) return withBlank;
|
|
6621
|
+
return withBlank.filter((row) => row.label.toLowerCase().includes(q));
|
|
6622
|
+
}, [facets, query]);
|
|
6623
|
+
const toggle = (candidate) => {
|
|
6624
|
+
const next = new Set(selectedSet);
|
|
6625
|
+
if (next.has(candidate)) next.delete(candidate);
|
|
6626
|
+
else next.add(candidate);
|
|
6627
|
+
const values = [...next];
|
|
6628
|
+
onChange(
|
|
6629
|
+
values.length === 0 ? void 0 : { kind: "select", value: values[0] ?? "", values }
|
|
6630
|
+
);
|
|
6631
|
+
};
|
|
6632
|
+
const notice = error ?? (loading ? FACETS_LOADING_NOTICE : describeFacetSource(facets));
|
|
6633
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "space-y-1.5", children: [
|
|
6634
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "px-1 text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: "Values" }),
|
|
6635
|
+
facets && facets.values.length + (facets.blank > 0 ? 1 : 0) > 8 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
6636
|
+
Input,
|
|
6637
|
+
{
|
|
6638
|
+
"data-matrx-filter-autofocus": true,
|
|
6639
|
+
value: query,
|
|
6640
|
+
onChange: (event) => setQuery(event.target.value),
|
|
6641
|
+
placeholder: "Find a value\u2026",
|
|
6642
|
+
className: "h-7 text-sm",
|
|
6643
|
+
style: { fontSize: "16px" }
|
|
6644
|
+
}
|
|
6645
|
+
) : null,
|
|
6646
|
+
rows.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("ul", { className: "max-h-56 space-y-0.5 overflow-y-auto", "data-matrx-facet-list": "true", children: rows.map((row) => {
|
|
6647
|
+
const checked = selectedSet.has(row.value);
|
|
6648
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
6649
|
+
"button",
|
|
6650
|
+
{
|
|
6651
|
+
type: "button",
|
|
6652
|
+
role: "checkbox",
|
|
6653
|
+
"aria-checked": checked,
|
|
6654
|
+
"data-matrx-facet-value": row.value === "" ? "__blank__" : row.value,
|
|
6655
|
+
onClick: () => toggle(row.value),
|
|
6656
|
+
className: cn(
|
|
6657
|
+
"flex w-full items-center gap-2 rounded px-1.5 py-1 text-left text-xs hover:bg-muted",
|
|
6658
|
+
checked && "bg-primary/10"
|
|
6659
|
+
),
|
|
6660
|
+
children: [
|
|
6661
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
6662
|
+
"span",
|
|
6663
|
+
{
|
|
6664
|
+
"aria-hidden": true,
|
|
6665
|
+
className: cn(
|
|
6666
|
+
"flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-[3px] border",
|
|
6667
|
+
checked ? "border-primary bg-primary text-primary-foreground" : "border-border"
|
|
6668
|
+
),
|
|
6669
|
+
children: checked ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Check, { className: "h-2.5 w-2.5" }) : null
|
|
6670
|
+
}
|
|
6671
|
+
),
|
|
6672
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: cn("min-w-0 flex-1 truncate", row.value === "" && "italic text-muted-foreground"), children: row.label }),
|
|
6673
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
6674
|
+
"span",
|
|
6675
|
+
{
|
|
6676
|
+
"data-matrx-facet-count": String(row.count),
|
|
6677
|
+
className: "shrink-0 tabular-nums text-[11px] text-muted-foreground",
|
|
6678
|
+
children: row.count.toLocaleString("en-US")
|
|
6679
|
+
}
|
|
6680
|
+
)
|
|
6681
|
+
]
|
|
6682
|
+
}
|
|
6683
|
+
) }, row.value === "" ? "__blank__" : row.value);
|
|
6684
|
+
}) }) : loading ? null : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "px-1 text-[11px] text-muted-foreground", children: query.trim() ? "No value matches that." : "This column has no values yet." }),
|
|
6685
|
+
notice ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
6686
|
+
"p",
|
|
6687
|
+
{
|
|
6688
|
+
"data-matrx-facet-notice": "true",
|
|
6689
|
+
className: cn(
|
|
6690
|
+
"px-1 text-[11px] leading-snug",
|
|
6691
|
+
error ? "text-amber-700 dark:text-amber-400" : "text-muted-foreground"
|
|
6692
|
+
),
|
|
6693
|
+
children: notice
|
|
6694
|
+
}
|
|
6695
|
+
) : null,
|
|
6696
|
+
selected.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
6697
|
+
"button",
|
|
6698
|
+
{
|
|
6699
|
+
type: "button",
|
|
6700
|
+
onClick: () => onChange(void 0),
|
|
6701
|
+
className: "px-1 text-[11px] text-muted-foreground underline-offset-2 hover:underline",
|
|
6702
|
+
children: "Clear selection"
|
|
6703
|
+
}
|
|
6704
|
+
) : null
|
|
6705
|
+
] });
|
|
6706
|
+
}
|
|
6465
6707
|
function SearchableSelectFilter({
|
|
6466
6708
|
selected,
|
|
6467
6709
|
options,
|
|
@@ -6648,8 +6890,8 @@ function NumberFilterBody({
|
|
|
6648
6890
|
}
|
|
6649
6891
|
function parseOptionalNumber(raw) {
|
|
6650
6892
|
if (raw.trim() === "") return void 0;
|
|
6651
|
-
const
|
|
6652
|
-
return Number.isFinite(
|
|
6893
|
+
const n2 = Number(raw.replace(/[^0-9.-]/g, ""));
|
|
6894
|
+
return Number.isFinite(n2) ? n2 : void 0;
|
|
6653
6895
|
}
|
|
6654
6896
|
|
|
6655
6897
|
// src/data-table/ColumnResizeHandle.tsx
|
|
@@ -6961,16 +7203,16 @@ function computeAggregate(rows, column) {
|
|
|
6961
7203
|
value = total;
|
|
6962
7204
|
break;
|
|
6963
7205
|
case "sum":
|
|
6964
|
-
value = numbers.length === 0 ? null : numbers.reduce((acc,
|
|
7206
|
+
value = numbers.length === 0 ? null : numbers.reduce((acc, n2) => acc + n2, 0);
|
|
6965
7207
|
break;
|
|
6966
7208
|
case "average":
|
|
6967
|
-
value = numbers.length === 0 ? null : numbers.reduce((acc,
|
|
7209
|
+
value = numbers.length === 0 ? null : numbers.reduce((acc, n2) => acc + n2, 0) / numbers.length;
|
|
6968
7210
|
break;
|
|
6969
7211
|
case "min":
|
|
6970
|
-
value = numbers.length === 0 ? null : numbers.reduce((acc,
|
|
7212
|
+
value = numbers.length === 0 ? null : numbers.reduce((acc, n2) => n2 < acc ? n2 : acc);
|
|
6971
7213
|
break;
|
|
6972
7214
|
case "max":
|
|
6973
|
-
value = numbers.length === 0 ? null : numbers.reduce((acc,
|
|
7215
|
+
value = numbers.length === 0 ? null : numbers.reduce((acc, n2) => n2 > acc ? n2 : acc);
|
|
6974
7216
|
break;
|
|
6975
7217
|
case "empty":
|
|
6976
7218
|
value = total - filled.length;
|
|
@@ -7394,7 +7636,7 @@ function moveSelection(current, move, rowIds, fieldNames) {
|
|
|
7394
7636
|
if (r === -1 || c === -1) return first;
|
|
7395
7637
|
const lastRow = rowIds.length - 1;
|
|
7396
7638
|
const lastCol = fieldNames.length - 1;
|
|
7397
|
-
const clamp = (
|
|
7639
|
+
const clamp = (n2, max) => Math.min(Math.max(n2, 0), max);
|
|
7398
7640
|
switch (move) {
|
|
7399
7641
|
case "up":
|
|
7400
7642
|
r = clamp(r - 1, lastRow);
|
|
@@ -7526,14 +7768,14 @@ function parseClipboardGrid(text) {
|
|
|
7526
7768
|
let row = [];
|
|
7527
7769
|
let cell = "";
|
|
7528
7770
|
let i = 0;
|
|
7529
|
-
const
|
|
7530
|
-
while (i <
|
|
7771
|
+
const n2 = text.length;
|
|
7772
|
+
while (i < n2) {
|
|
7531
7773
|
const ch = text[i];
|
|
7532
7774
|
if (cell === "" && ch === '"') {
|
|
7533
7775
|
let j = i + 1;
|
|
7534
7776
|
let out = "";
|
|
7535
7777
|
let closed = false;
|
|
7536
|
-
while (j <
|
|
7778
|
+
while (j < n2) {
|
|
7537
7779
|
const c = text[j];
|
|
7538
7780
|
if (c === '"') {
|
|
7539
7781
|
if (text[j + 1] === '"') {
|
|
@@ -7548,10 +7790,10 @@ function parseClipboardGrid(text) {
|
|
|
7548
7790
|
out += c;
|
|
7549
7791
|
j += 1;
|
|
7550
7792
|
}
|
|
7551
|
-
if (closed && (j >=
|
|
7793
|
+
if (closed && (j >= n2 || text[j] === " " || text[j] === "\n" || text[j] === "\r")) {
|
|
7552
7794
|
cell = out;
|
|
7553
7795
|
i = j;
|
|
7554
|
-
if (i >=
|
|
7796
|
+
if (i >= n2) break;
|
|
7555
7797
|
const d = text[i];
|
|
7556
7798
|
if (d === " ") {
|
|
7557
7799
|
row.push(cell);
|
|
@@ -7587,7 +7829,7 @@ function parseClipboardGrid(text) {
|
|
|
7587
7829
|
cell += ch;
|
|
7588
7830
|
i += 1;
|
|
7589
7831
|
}
|
|
7590
|
-
const endedOnBreak =
|
|
7832
|
+
const endedOnBreak = n2 > 0 && (text[n2 - 1] === "\n" || text[n2 - 1] === "\r");
|
|
7591
7833
|
if (!endedOnBreak) {
|
|
7592
7834
|
row.push(cell);
|
|
7593
7835
|
rows.push(row);
|
|
@@ -7666,11 +7908,11 @@ function directionOf(source, target) {
|
|
|
7666
7908
|
return null;
|
|
7667
7909
|
}
|
|
7668
7910
|
function tileIndex(i, a, b) {
|
|
7669
|
-
const
|
|
7670
|
-
if (
|
|
7911
|
+
const n2 = b - a + 1;
|
|
7912
|
+
if (n2 <= 0) return a;
|
|
7671
7913
|
if (i >= a && i <= b) return i;
|
|
7672
|
-
if (i > b) return a + (i - a) %
|
|
7673
|
-
return b - (a - 1 - i) %
|
|
7914
|
+
if (i > b) return a + (i - a) % n2;
|
|
7915
|
+
return b - (a - 1 - i) % n2;
|
|
7674
7916
|
}
|
|
7675
7917
|
function isFiniteNumber(v) {
|
|
7676
7918
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -8015,6 +8257,26 @@ function useSpreadsheetGrid(options) {
|
|
|
8015
8257
|
for (let i = 0; i < columnIds.length; i += 1) map.set(columnIds[i], i);
|
|
8016
8258
|
return map;
|
|
8017
8259
|
}, [columnIds]);
|
|
8260
|
+
const screenPatches = (0, import_react15.useCallback)(
|
|
8261
|
+
(patches) => {
|
|
8262
|
+
const validate = optionsRef.current?.validateCell;
|
|
8263
|
+
if (!validate) return { accepted: patches, refusals: [] };
|
|
8264
|
+
const accepted = [];
|
|
8265
|
+
const refusals = [];
|
|
8266
|
+
for (const patch of patches) {
|
|
8267
|
+
let reason;
|
|
8268
|
+
try {
|
|
8269
|
+
reason = validate({ rowId: patch.rowId, columnId: patch.columnId, value: patch.value });
|
|
8270
|
+
} catch {
|
|
8271
|
+
reason = void 0;
|
|
8272
|
+
}
|
|
8273
|
+
if (reason) refusals.push({ columnId: patch.columnId, reason });
|
|
8274
|
+
else accepted.push(patch);
|
|
8275
|
+
}
|
|
8276
|
+
return { accepted, refusals };
|
|
8277
|
+
},
|
|
8278
|
+
[]
|
|
8279
|
+
);
|
|
8018
8280
|
const applyPatches = (0, import_react15.useCallback)(
|
|
8019
8281
|
async (patches, intent, label) => {
|
|
8020
8282
|
const current = optionsRef.current;
|
|
@@ -8071,9 +8333,10 @@ function useSpreadsheetGrid(options) {
|
|
|
8071
8333
|
...base,
|
|
8072
8334
|
range: { top: bounds.r0, left: bounds.c0, bottom: bounds.r1, right: bounds.c1 }
|
|
8073
8335
|
});
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8336
|
+
const screened = screenPatches(result.patches);
|
|
8337
|
+
await applyPatches(screened.accepted, "fill-down", "Filled down");
|
|
8338
|
+
announceSkips([...result.skipped, ...screened.refusals], result.summary);
|
|
8339
|
+
}, [fillRequestBase, bounds, applyPatches, announceSkips, screenPatches]);
|
|
8077
8340
|
const doClear = (0, import_react15.useCallback)(async () => {
|
|
8078
8341
|
const current = optionsRef.current;
|
|
8079
8342
|
if (!current || !bounds) return;
|
|
@@ -8094,9 +8357,13 @@ function useSpreadsheetGrid(options) {
|
|
|
8094
8357
|
patches.push({ rowId, columnId: columnId2, value: null });
|
|
8095
8358
|
}
|
|
8096
8359
|
}
|
|
8097
|
-
|
|
8098
|
-
|
|
8099
|
-
|
|
8360
|
+
const screened = screenPatches(patches);
|
|
8361
|
+
await applyPatches(screened.accepted, "clear", "Cleared");
|
|
8362
|
+
announceSkips(
|
|
8363
|
+
[...skipped, ...screened.refusals],
|
|
8364
|
+
`Cleared ${screened.accepted.length} cells.`
|
|
8365
|
+
);
|
|
8366
|
+
}, [bounds, applyPatches, announceSkips, screenPatches]);
|
|
8100
8367
|
const doUndo = (0, import_react15.useCallback)(async () => {
|
|
8101
8368
|
const taken = popUndo(stack);
|
|
8102
8369
|
if (!taken.entry) return;
|
|
@@ -8181,6 +8448,14 @@ function useSpreadsheetGrid(options) {
|
|
|
8181
8448
|
case "escape":
|
|
8182
8449
|
setRange(null);
|
|
8183
8450
|
return;
|
|
8451
|
+
case "edit":
|
|
8452
|
+
case "editSeeded": {
|
|
8453
|
+
const focused = range?.focus;
|
|
8454
|
+
if (!focused || !current.onEditRequest) return;
|
|
8455
|
+
const seed = action.kind === "editSeeded" ? action.seed : null;
|
|
8456
|
+
if (current.onEditRequest(focused, seed)) event.preventDefault();
|
|
8457
|
+
return;
|
|
8458
|
+
}
|
|
8184
8459
|
default:
|
|
8185
8460
|
return;
|
|
8186
8461
|
}
|
|
@@ -8195,6 +8470,13 @@ function useSpreadsheetGrid(options) {
|
|
|
8195
8470
|
);
|
|
8196
8471
|
return gridToTsv(grid);
|
|
8197
8472
|
}, [range, rowIds, columnIds]);
|
|
8473
|
+
const selectionAddresses = (0, import_react15.useCallback)(() => {
|
|
8474
|
+
if (!range || !bounds) return { rowIds: [], columnIds: [] };
|
|
8475
|
+
return {
|
|
8476
|
+
rowIds: rowIds.slice(bounds.r0, bounds.r1 + 1),
|
|
8477
|
+
columnIds: columnIds.slice(bounds.c0, bounds.c1 + 1)
|
|
8478
|
+
};
|
|
8479
|
+
}, [range, bounds, rowIds, columnIds]);
|
|
8198
8480
|
const onCopy = (0, import_react15.useCallback)(
|
|
8199
8481
|
(event) => {
|
|
8200
8482
|
if (!optionsRef.current || !range || targetsAnEditor(event.target)) return;
|
|
@@ -8250,11 +8532,12 @@ function useSpreadsheetGrid(options) {
|
|
|
8250
8532
|
patches.push({ rowId, columnId: columnId2, value: line[c] ?? null });
|
|
8251
8533
|
}
|
|
8252
8534
|
}
|
|
8253
|
-
|
|
8535
|
+
const screened = screenPatches(patches);
|
|
8536
|
+
void applyPatches(screened.accepted, "paste", "Pasted");
|
|
8254
8537
|
const tail = outside > 0 ? ` ${outside} landed past the edge of the table and were ignored.` : "";
|
|
8255
|
-
announceSkips(skipped, `Pasted ${
|
|
8538
|
+
announceSkips([...skipped, ...screened.refusals], `Pasted ${screened.accepted.length} cells.${tail}`);
|
|
8256
8539
|
},
|
|
8257
|
-
[range, rowIds, columnIds, applyPatches, announceSkips]
|
|
8540
|
+
[range, rowIds, columnIds, applyPatches, announceSkips, screenPatches]
|
|
8258
8541
|
);
|
|
8259
8542
|
const cellProps = (0, import_react15.useCallback)(
|
|
8260
8543
|
(rowId, columnId2) => {
|
|
@@ -8273,6 +8556,10 @@ function useSpreadsheetGrid(options) {
|
|
|
8273
8556
|
onMouseDown: (event) => {
|
|
8274
8557
|
if (event.button !== 0) return;
|
|
8275
8558
|
event.preventDefault();
|
|
8559
|
+
const origin = event.currentTarget;
|
|
8560
|
+
if (typeof HTMLElement !== "undefined" && origin instanceof HTMLElement) {
|
|
8561
|
+
origin.closest('[data-matrx-table-spreadsheet="true"]')?.focus({ preventScroll: true });
|
|
8562
|
+
}
|
|
8276
8563
|
setRange(
|
|
8277
8564
|
(previous) => event.shiftKey && previous ? { anchor: previous.anchor, focus: address } : { anchor: address, focus: address }
|
|
8278
8565
|
);
|
|
@@ -8334,12 +8621,13 @@ function useSpreadsheetGrid(options) {
|
|
|
8334
8621
|
source: { top: source.r0, left: source.c0, bottom: source.r1, right: source.c1 },
|
|
8335
8622
|
target
|
|
8336
8623
|
});
|
|
8337
|
-
|
|
8338
|
-
|
|
8624
|
+
const screened = screenPatches(result.patches);
|
|
8625
|
+
void applyPatches(screened.accepted, "fill", "Filled");
|
|
8626
|
+
announceSkips([...result.skipped, ...screened.refusals], result.summary);
|
|
8339
8627
|
};
|
|
8340
8628
|
window.addEventListener("mouseup", commit);
|
|
8341
8629
|
return () => window.removeEventListener("mouseup", commit);
|
|
8342
|
-
}, [options, fillRequestBase, applyPatches, announceSkips]);
|
|
8630
|
+
}, [options, fillRequestBase, applyPatches, announceSkips, screenPatches]);
|
|
8343
8631
|
return {
|
|
8344
8632
|
range,
|
|
8345
8633
|
bounds,
|
|
@@ -8355,17 +8643,19 @@ function useSpreadsheetGrid(options) {
|
|
|
8355
8643
|
isFillHandleCell,
|
|
8356
8644
|
startFillDrag,
|
|
8357
8645
|
canUndo: stack.past.length > 0,
|
|
8358
|
-
canRedo: stack.future.length > 0
|
|
8646
|
+
canRedo: stack.future.length > 0,
|
|
8647
|
+
selectionTsv: selectionAsTsv,
|
|
8648
|
+
selectionAddresses
|
|
8359
8649
|
};
|
|
8360
8650
|
}
|
|
8361
8651
|
|
|
8362
8652
|
// src/data-table/coverage.ts
|
|
8363
8653
|
var PARTIAL_BADGE = "Partial";
|
|
8364
8654
|
var UNKNOWN_TOTAL_BADGE = "Unknown total";
|
|
8365
|
-
var
|
|
8655
|
+
var NUMBERS2 = new Intl.NumberFormat("en-US");
|
|
8366
8656
|
function formatNumber(value) {
|
|
8367
8657
|
try {
|
|
8368
|
-
return
|
|
8658
|
+
return NUMBERS2.format(value);
|
|
8369
8659
|
} catch {
|
|
8370
8660
|
return String(value);
|
|
8371
8661
|
}
|
|
@@ -9563,8 +9853,8 @@ function toNumber(value) {
|
|
|
9563
9853
|
if (typeof value === "string") {
|
|
9564
9854
|
const cleaned = value.replace(/[,\s$€£¥%]/g, "");
|
|
9565
9855
|
if (cleaned === "") return null;
|
|
9566
|
-
const
|
|
9567
|
-
return Number.isFinite(
|
|
9856
|
+
const n2 = Number(cleaned);
|
|
9857
|
+
return Number.isFinite(n2) ? n2 : null;
|
|
9568
9858
|
}
|
|
9569
9859
|
return null;
|
|
9570
9860
|
}
|
|
@@ -9602,14 +9892,14 @@ function toList(value) {
|
|
|
9602
9892
|
}
|
|
9603
9893
|
return null;
|
|
9604
9894
|
}
|
|
9605
|
-
function groupedNumber(
|
|
9895
|
+
function groupedNumber(n2, options) {
|
|
9606
9896
|
return new Intl.NumberFormat(void 0, {
|
|
9607
9897
|
useGrouping: options.useGrouping !== false,
|
|
9608
9898
|
...options.precision != null ? {
|
|
9609
9899
|
minimumFractionDigits: options.precision,
|
|
9610
9900
|
maximumFractionDigits: options.precision
|
|
9611
9901
|
} : { maximumFractionDigits: 10 }
|
|
9612
|
-
}).format(
|
|
9902
|
+
}).format(n2);
|
|
9613
9903
|
}
|
|
9614
9904
|
function affix(text, options) {
|
|
9615
9905
|
return `${options.prefix ?? ""}${text}${options.suffix ?? ""}`;
|
|
@@ -9743,8 +10033,8 @@ var DEFS = [
|
|
|
9743
10033
|
numericAlign: true,
|
|
9744
10034
|
optionKeys: ["useGrouping", "precision", "prefix", "suffix"],
|
|
9745
10035
|
format: (v, o) => {
|
|
9746
|
-
const
|
|
9747
|
-
return
|
|
10036
|
+
const n2 = toNumber(v);
|
|
10037
|
+
return n2 === null ? null : affix(groupedNumber(n2, o), o);
|
|
9748
10038
|
},
|
|
9749
10039
|
parse: (raw) => toNumber(raw)
|
|
9750
10040
|
},
|
|
@@ -9759,9 +10049,9 @@ var DEFS = [
|
|
|
9759
10049
|
numericAlign: true,
|
|
9760
10050
|
optionKeys: ["precision", "useGrouping", "prefix", "suffix"],
|
|
9761
10051
|
format: (v, o) => {
|
|
9762
|
-
const
|
|
9763
|
-
if (
|
|
9764
|
-
return affix(groupedNumber(
|
|
10052
|
+
const n2 = toNumber(v);
|
|
10053
|
+
if (n2 === null) return null;
|
|
10054
|
+
return affix(groupedNumber(n2, { ...o, precision: o.precision ?? 2 }), o);
|
|
9765
10055
|
},
|
|
9766
10056
|
parse: (raw) => toNumber(raw)
|
|
9767
10057
|
},
|
|
@@ -9776,8 +10066,8 @@ var DEFS = [
|
|
|
9776
10066
|
numericAlign: true,
|
|
9777
10067
|
optionKeys: ["currency", "precision"],
|
|
9778
10068
|
format: (v, o) => {
|
|
9779
|
-
const
|
|
9780
|
-
if (
|
|
10069
|
+
const n2 = toNumber(v);
|
|
10070
|
+
if (n2 === null) return null;
|
|
9781
10071
|
const currency = (o.currency || "USD").toUpperCase();
|
|
9782
10072
|
try {
|
|
9783
10073
|
return new Intl.NumberFormat(void 0, {
|
|
@@ -9787,9 +10077,9 @@ var DEFS = [
|
|
|
9787
10077
|
minimumFractionDigits: o.precision,
|
|
9788
10078
|
maximumFractionDigits: o.precision
|
|
9789
10079
|
} : {}
|
|
9790
|
-
}).format(
|
|
10080
|
+
}).format(n2);
|
|
9791
10081
|
} catch {
|
|
9792
|
-
return `${groupedNumber(
|
|
10082
|
+
return `${groupedNumber(n2, { precision: o.precision ?? 2 })} ${currency}`;
|
|
9793
10083
|
}
|
|
9794
10084
|
},
|
|
9795
10085
|
parse: (raw) => toNumber(raw)
|
|
@@ -9805,9 +10095,9 @@ var DEFS = [
|
|
|
9805
10095
|
numericAlign: true,
|
|
9806
10096
|
optionKeys: ["percentScale", "precision"],
|
|
9807
10097
|
format: (v, o) => {
|
|
9808
|
-
const
|
|
9809
|
-
if (
|
|
9810
|
-
const shown = o.percentScale === "fraction" ?
|
|
10098
|
+
const n2 = toNumber(v);
|
|
10099
|
+
if (n2 === null) return null;
|
|
10100
|
+
const shown = o.percentScale === "fraction" ? n2 * 100 : n2;
|
|
9811
10101
|
return `${groupedNumber(shown, o.precision === void 0 ? {} : { precision: o.precision })}%`;
|
|
9812
10102
|
},
|
|
9813
10103
|
parse: (raw) => toNumber(raw)
|
|
@@ -9823,9 +10113,9 @@ var DEFS = [
|
|
|
9823
10113
|
numericAlign: true,
|
|
9824
10114
|
optionKeys: ["durationUnit"],
|
|
9825
10115
|
format: (v, o) => {
|
|
9826
|
-
const
|
|
9827
|
-
if (
|
|
9828
|
-
return formatSignedDuration(
|
|
10116
|
+
const n2 = toNumber(v);
|
|
10117
|
+
if (n2 === null) return null;
|
|
10118
|
+
return formatSignedDuration(n2 * DURATION_TO_SECONDS[o.durationUnit ?? "seconds"]);
|
|
9829
10119
|
},
|
|
9830
10120
|
parse: (raw) => toNumber(raw)
|
|
9831
10121
|
},
|
|
@@ -9840,13 +10130,13 @@ var DEFS = [
|
|
|
9840
10130
|
numericAlign: true,
|
|
9841
10131
|
optionKeys: ["useGrouping", "prefix", "suffix"],
|
|
9842
10132
|
format: (v, o) => {
|
|
9843
|
-
const
|
|
9844
|
-
if (
|
|
9845
|
-
return affix(groupedNumber(Math.trunc(
|
|
10133
|
+
const n2 = toNumber(v);
|
|
10134
|
+
if (n2 === null) return null;
|
|
10135
|
+
return affix(groupedNumber(Math.trunc(n2), { ...o, precision: 0 }), o);
|
|
9846
10136
|
},
|
|
9847
10137
|
parse: (raw) => {
|
|
9848
|
-
const
|
|
9849
|
-
return
|
|
10138
|
+
const n2 = toNumber(raw);
|
|
10139
|
+
return n2 === null ? null : Math.trunc(n2);
|
|
9850
10140
|
}
|
|
9851
10141
|
},
|
|
9852
10142
|
{
|
|
@@ -9860,15 +10150,15 @@ var DEFS = [
|
|
|
9860
10150
|
rich: true,
|
|
9861
10151
|
optionKeys: ["ratingMax"],
|
|
9862
10152
|
format: (v, o) => {
|
|
9863
|
-
const
|
|
9864
|
-
if (
|
|
10153
|
+
const n2 = toNumber(v);
|
|
10154
|
+
if (n2 === null) return null;
|
|
9865
10155
|
const max = o.ratingMax ?? 5;
|
|
9866
|
-
if (
|
|
9867
|
-
return `${
|
|
10156
|
+
if (n2 < 0 || n2 > max) return null;
|
|
10157
|
+
return `${n2} / ${max}`;
|
|
9868
10158
|
},
|
|
9869
10159
|
parse: (raw) => {
|
|
9870
|
-
const
|
|
9871
|
-
return
|
|
10160
|
+
const n2 = toNumber(raw);
|
|
10161
|
+
return n2 === null ? null : Math.round(n2);
|
|
9872
10162
|
}
|
|
9873
10163
|
},
|
|
9874
10164
|
{
|
|
@@ -9881,12 +10171,12 @@ var DEFS = [
|
|
|
9881
10171
|
editor: "number",
|
|
9882
10172
|
numericAlign: true,
|
|
9883
10173
|
format: (v) => {
|
|
9884
|
-
const
|
|
9885
|
-
return
|
|
10174
|
+
const n2 = toNumber(v);
|
|
10175
|
+
return n2 === null ? null : (0, import_format3.formatFileSize)(n2);
|
|
9886
10176
|
},
|
|
9887
10177
|
parse: (raw) => {
|
|
9888
|
-
const
|
|
9889
|
-
return
|
|
10178
|
+
const n2 = toNumber(raw);
|
|
10179
|
+
return n2 === null ? null : Math.trunc(n2);
|
|
9890
10180
|
}
|
|
9891
10181
|
},
|
|
9892
10182
|
// ── Choice ────────────────────────────────────────────────────────────────
|
|
@@ -10298,6 +10588,17 @@ function DirtySavePill({
|
|
|
10298
10588
|
// src/data-table/EditableTableCell.tsx
|
|
10299
10589
|
var import_react19 = require("react");
|
|
10300
10590
|
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
10591
|
+
function CellRefusal({ reason }) {
|
|
10592
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10593
|
+
"p",
|
|
10594
|
+
{
|
|
10595
|
+
role: "alert",
|
|
10596
|
+
"data-matrx-cell-refusal": "true",
|
|
10597
|
+
className: "mt-1 text-[11px] leading-snug text-amber-700 dark:text-amber-400",
|
|
10598
|
+
children: reason
|
|
10599
|
+
}
|
|
10600
|
+
);
|
|
10601
|
+
}
|
|
10301
10602
|
function CellEditShell({
|
|
10302
10603
|
href,
|
|
10303
10604
|
display,
|
|
@@ -10344,12 +10645,17 @@ function EditableTableCell({
|
|
|
10344
10645
|
className,
|
|
10345
10646
|
href,
|
|
10346
10647
|
editTrigger = "click",
|
|
10347
|
-
editRequest
|
|
10648
|
+
editRequest,
|
|
10649
|
+
editSeed
|
|
10348
10650
|
}) {
|
|
10349
10651
|
const [open, setOpen] = (0, import_react19.useState)(false);
|
|
10652
|
+
const [refusal, setRefusal] = (0, import_react19.useState)(null);
|
|
10350
10653
|
(0, import_react19.useEffect)(() => {
|
|
10351
10654
|
if (editRequest !== void 0) setOpen(true);
|
|
10352
10655
|
}, [editRequest]);
|
|
10656
|
+
(0, import_react19.useEffect)(() => {
|
|
10657
|
+
if (!open) setRefusal(null);
|
|
10658
|
+
}, [open]);
|
|
10353
10659
|
const usePencil = Boolean(href) || editTrigger === "pencil";
|
|
10354
10660
|
if (editType === "string") {
|
|
10355
10661
|
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
@@ -10362,7 +10668,8 @@ function EditableTableCell({
|
|
|
10362
10668
|
...className === void 0 ? {} : { className },
|
|
10363
10669
|
...href === void 0 ? {} : { href },
|
|
10364
10670
|
usePencil,
|
|
10365
|
-
...editRequest === void 0 ? {} : { editRequest }
|
|
10671
|
+
...editRequest === void 0 ? {} : { editRequest },
|
|
10672
|
+
...editSeed === void 0 || editSeed === null ? {} : { editSeed }
|
|
10366
10673
|
}
|
|
10367
10674
|
);
|
|
10368
10675
|
}
|
|
@@ -10407,25 +10714,33 @@ function EditableTableCell({
|
|
|
10407
10714
|
) }) }),
|
|
10408
10715
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(TooltipContent, { children: "Edit value" })
|
|
10409
10716
|
] }),
|
|
10410
|
-
/* @__PURE__ */ (0, import_jsx_runtime39.
|
|
10717
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
|
|
10411
10718
|
PopoverContent,
|
|
10412
10719
|
{
|
|
10413
10720
|
align: "start",
|
|
10414
10721
|
className: "w-56 p-2",
|
|
10415
10722
|
onClick: (e) => e.stopPropagation(),
|
|
10416
|
-
children:
|
|
10417
|
-
|
|
10418
|
-
|
|
10419
|
-
|
|
10420
|
-
|
|
10421
|
-
|
|
10422
|
-
|
|
10423
|
-
onCommit(next)
|
|
10424
|
-
|
|
10425
|
-
|
|
10426
|
-
|
|
10427
|
-
|
|
10428
|
-
|
|
10723
|
+
children: [
|
|
10724
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10725
|
+
TypedEditor,
|
|
10726
|
+
{
|
|
10727
|
+
editType,
|
|
10728
|
+
value,
|
|
10729
|
+
editOptions,
|
|
10730
|
+
onCommit: (next) => {
|
|
10731
|
+
const refused = onCommit(next);
|
|
10732
|
+
if (typeof refused === "string" && refused) {
|
|
10733
|
+
setRefusal(refused);
|
|
10734
|
+
return;
|
|
10735
|
+
}
|
|
10736
|
+
setRefusal(null);
|
|
10737
|
+
setOpen(false);
|
|
10738
|
+
},
|
|
10739
|
+
onCancel: () => setOpen(false)
|
|
10740
|
+
}
|
|
10741
|
+
),
|
|
10742
|
+
refusal ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CellRefusal, { reason: refusal }) : null
|
|
10743
|
+
]
|
|
10429
10744
|
}
|
|
10430
10745
|
)
|
|
10431
10746
|
] });
|
|
@@ -10438,17 +10753,31 @@ function InlineStringEditor({
|
|
|
10438
10753
|
className,
|
|
10439
10754
|
href,
|
|
10440
10755
|
usePencil,
|
|
10441
|
-
editRequest
|
|
10756
|
+
editRequest,
|
|
10757
|
+
editSeed
|
|
10442
10758
|
}) {
|
|
10443
10759
|
const [editing, setEditing] = (0, import_react19.useState)(false);
|
|
10444
10760
|
const [draft, setDraft] = (0, import_react19.useState)(value);
|
|
10761
|
+
const [refusal, setRefusal] = (0, import_react19.useState)(null);
|
|
10445
10762
|
const handledEditRequest = (0, import_react19.useRef)(void 0);
|
|
10763
|
+
const seedRef = (0, import_react19.useRef)(editSeed);
|
|
10764
|
+
seedRef.current = editSeed;
|
|
10446
10765
|
(0, import_react19.useEffect)(() => {
|
|
10447
10766
|
if (editRequest === void 0 || handledEditRequest.current === editRequest) return;
|
|
10448
10767
|
handledEditRequest.current = editRequest;
|
|
10449
|
-
setDraft(value);
|
|
10768
|
+
setDraft(seedRef.current ?? value);
|
|
10769
|
+
setRefusal(null);
|
|
10450
10770
|
setEditing(true);
|
|
10451
10771
|
}, [editRequest, value]);
|
|
10772
|
+
const commit = (next) => {
|
|
10773
|
+
const refused = onCommit(next);
|
|
10774
|
+
if (typeof refused === "string" && refused) {
|
|
10775
|
+
setRefusal(refused);
|
|
10776
|
+
return false;
|
|
10777
|
+
}
|
|
10778
|
+
setRefusal(null);
|
|
10779
|
+
return true;
|
|
10780
|
+
};
|
|
10452
10781
|
if (!editing) {
|
|
10453
10782
|
if (usePencil) {
|
|
10454
10783
|
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
@@ -10499,32 +10828,38 @@ function InlineStringEditor({
|
|
|
10499
10828
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(TooltipContent, { children: "Click to edit" })
|
|
10500
10829
|
] });
|
|
10501
10830
|
}
|
|
10502
|
-
return /* @__PURE__ */ (0, import_jsx_runtime39.
|
|
10503
|
-
|
|
10504
|
-
|
|
10505
|
-
|
|
10506
|
-
|
|
10507
|
-
|
|
10508
|
-
|
|
10509
|
-
|
|
10510
|
-
|
|
10511
|
-
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
|
|
10515
|
-
|
|
10516
|
-
|
|
10517
|
-
|
|
10518
|
-
|
|
10519
|
-
|
|
10520
|
-
|
|
10521
|
-
|
|
10522
|
-
|
|
10523
|
-
|
|
10524
|
-
|
|
10525
|
-
|
|
10526
|
-
|
|
10527
|
-
|
|
10831
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "block w-full", children: [
|
|
10832
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10833
|
+
Input,
|
|
10834
|
+
{
|
|
10835
|
+
autoFocus: true,
|
|
10836
|
+
value: draft,
|
|
10837
|
+
onClick: (e) => e.stopPropagation(),
|
|
10838
|
+
onChange: (e) => {
|
|
10839
|
+
setDraft(e.target.value);
|
|
10840
|
+
if (refusal) setRefusal(null);
|
|
10841
|
+
},
|
|
10842
|
+
onBlur: () => {
|
|
10843
|
+
if (commit(draft)) setEditing(false);
|
|
10844
|
+
},
|
|
10845
|
+
onKeyDown: (e) => {
|
|
10846
|
+
if (e.key === "Enter") {
|
|
10847
|
+
e.preventDefault();
|
|
10848
|
+
if (commit(draft)) setEditing(false);
|
|
10849
|
+
}
|
|
10850
|
+
if (e.key === "Escape") {
|
|
10851
|
+
e.preventDefault();
|
|
10852
|
+
setRefusal(null);
|
|
10853
|
+
setEditing(false);
|
|
10854
|
+
}
|
|
10855
|
+
},
|
|
10856
|
+
"aria-invalid": refusal ? true : void 0,
|
|
10857
|
+
className: cn("h-7 text-sm", refusal && "border-amber-500 focus-visible:ring-amber-500"),
|
|
10858
|
+
style: { fontSize: "16px" }
|
|
10859
|
+
}
|
|
10860
|
+
),
|
|
10861
|
+
refusal ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CellRefusal, { reason: refusal }) : null
|
|
10862
|
+
] });
|
|
10528
10863
|
}
|
|
10529
10864
|
function TypedEditor({
|
|
10530
10865
|
editType,
|
|
@@ -10709,8 +11044,8 @@ function NumberEditor({
|
|
|
10709
11044
|
style: { fontSize: "16px" },
|
|
10710
11045
|
onKeyDown: (e) => {
|
|
10711
11046
|
if (e.key === "Enter") {
|
|
10712
|
-
const
|
|
10713
|
-
if (Number.isFinite(
|
|
11047
|
+
const n2 = Number(draft);
|
|
11048
|
+
if (Number.isFinite(n2)) onCommit(n2);
|
|
10714
11049
|
}
|
|
10715
11050
|
if (e.key === "Escape") onCancel();
|
|
10716
11051
|
}
|
|
@@ -10737,8 +11072,8 @@ function NumberEditor({
|
|
|
10737
11072
|
className: "h-7",
|
|
10738
11073
|
"aria-label": "Apply value",
|
|
10739
11074
|
onClick: () => {
|
|
10740
|
-
const
|
|
10741
|
-
if (Number.isFinite(
|
|
11075
|
+
const n2 = Number(draft);
|
|
11076
|
+
if (Number.isFinite(n2)) onCommit(n2);
|
|
10742
11077
|
},
|
|
10743
11078
|
children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Check, { className: "h-3.5 w-3.5" })
|
|
10744
11079
|
}
|
|
@@ -11546,6 +11881,7 @@ function MatrxDataTableCore({
|
|
|
11546
11881
|
virtualize,
|
|
11547
11882
|
coverage,
|
|
11548
11883
|
spreadsheet,
|
|
11884
|
+
facets,
|
|
11549
11885
|
rowHeight: explicitRowHeight
|
|
11550
11886
|
}) {
|
|
11551
11887
|
const appendQuery = query?.mode === "controlled-append" ? query : null;
|
|
@@ -12603,9 +12939,92 @@ function MatrxDataTableCore({
|
|
|
12603
12939
|
...spreadsheet.undoDepth === void 0 ? {} : { undoDepth: spreadsheet.undoDepth },
|
|
12604
12940
|
...spreadsheet.fillHandle === void 0 ? {} : { fillHandle: spreadsheet.fillHandle },
|
|
12605
12941
|
...spreadsheet.paste === void 0 ? {} : { paste: spreadsheet.paste },
|
|
12606
|
-
notify: spreadsheet.notify ?? ((message) => toast.success(message))
|
|
12942
|
+
notify: spreadsheet.notify ?? ((message) => toast.success(message)),
|
|
12943
|
+
onEditRequest: (address, seed) => requestCellEditRef.current(address, seed),
|
|
12944
|
+
...spreadsheet.validateCell ? { validateCell: spreadsheet.validateCell } : {}
|
|
12607
12945
|
} : null
|
|
12608
12946
|
);
|
|
12947
|
+
const sheetRef = (0, import_react21.useRef)(sheet);
|
|
12948
|
+
sheetRef.current = sheet;
|
|
12949
|
+
const searchValueRef = (0, import_react21.useRef)(searchValue);
|
|
12950
|
+
searchValueRef.current = searchValue;
|
|
12951
|
+
const facetsEnabled = Boolean(facets && facets.enabled !== false);
|
|
12952
|
+
const [facetState, setFacetState] = (0, import_react21.useState)({});
|
|
12953
|
+
const facetReadCell = (0, import_react21.useCallback)(
|
|
12954
|
+
(row, colId) => {
|
|
12955
|
+
if (facets?.readCell) return facets.readCell(row, colId);
|
|
12956
|
+
const col = visibleColumns.find((candidate) => columnId(candidate) === colId);
|
|
12957
|
+
return col ? getFilterValue(row, col) : void 0;
|
|
12958
|
+
},
|
|
12959
|
+
[facets, visibleColumns]
|
|
12960
|
+
);
|
|
12961
|
+
const facetInputsRef = (0, import_react21.useRef)({ data, facets, facetReadCell });
|
|
12962
|
+
facetInputsRef.current = { data, facets, facetReadCell };
|
|
12963
|
+
const facetRequestRef = (0, import_react21.useRef)(/* @__PURE__ */ new Map());
|
|
12964
|
+
const requestFacets = (0, import_react21.useCallback)((colId) => {
|
|
12965
|
+
const { data: rows, facets: config, facetReadCell: readCell } = facetInputsRef.current;
|
|
12966
|
+
if (!config || config.enabled === false) return;
|
|
12967
|
+
const complete = localFacetsAreComplete(rows.length, config.totalRows);
|
|
12968
|
+
const limit = config.limit;
|
|
12969
|
+
if (complete || !config.source) {
|
|
12970
|
+
setFacetState((current) => ({
|
|
12971
|
+
...current,
|
|
12972
|
+
[colId]: {
|
|
12973
|
+
loading: false,
|
|
12974
|
+
data: computeColumnFacets({
|
|
12975
|
+
columnId: colId,
|
|
12976
|
+
rows,
|
|
12977
|
+
readValue: readCell,
|
|
12978
|
+
...limit === void 0 ? {} : { limit },
|
|
12979
|
+
complete
|
|
12980
|
+
})
|
|
12981
|
+
}
|
|
12982
|
+
}));
|
|
12983
|
+
return;
|
|
12984
|
+
}
|
|
12985
|
+
const ticket = (facetRequestRef.current.get(colId) ?? 0) + 1;
|
|
12986
|
+
facetRequestRef.current.set(colId, ticket);
|
|
12987
|
+
setFacetState((current) => ({
|
|
12988
|
+
...current,
|
|
12989
|
+
[colId]: { loading: true, data: current[colId]?.data ?? null }
|
|
12990
|
+
}));
|
|
12991
|
+
void Promise.resolve().then(
|
|
12992
|
+
() => config.source?.({ columnId: colId, search: searchValueRef.current, limit: limit ?? 200 })
|
|
12993
|
+
).then((answer) => {
|
|
12994
|
+
if (facetRequestRef.current.get(colId) !== ticket) return;
|
|
12995
|
+
if (!answer) {
|
|
12996
|
+
setFacetState((current) => ({
|
|
12997
|
+
...current,
|
|
12998
|
+
[colId]: {
|
|
12999
|
+
loading: false,
|
|
13000
|
+
data: computeColumnFacets({
|
|
13001
|
+
columnId: colId,
|
|
13002
|
+
rows: facetInputsRef.current.data,
|
|
13003
|
+
readValue: facetInputsRef.current.facetReadCell,
|
|
13004
|
+
...limit === void 0 ? {} : { limit },
|
|
13005
|
+
complete: false
|
|
13006
|
+
})
|
|
13007
|
+
}
|
|
13008
|
+
}));
|
|
13009
|
+
return;
|
|
13010
|
+
}
|
|
13011
|
+
setFacetState((current) => ({
|
|
13012
|
+
...current,
|
|
13013
|
+
[colId]: { loading: false, data: { ...answer, answeredBy: "source", complete: true } }
|
|
13014
|
+
}));
|
|
13015
|
+
}).catch((error) => {
|
|
13016
|
+
if (facetRequestRef.current.get(colId) !== ticket) return;
|
|
13017
|
+
setFacetState((current) => ({
|
|
13018
|
+
...current,
|
|
13019
|
+
[colId]: { loading: false, data: null, error: describeFacetFailure(error) }
|
|
13020
|
+
}));
|
|
13021
|
+
});
|
|
13022
|
+
}, []);
|
|
13023
|
+
(0, import_react21.useEffect)(() => {
|
|
13024
|
+
if (!facetsEnabled) return;
|
|
13025
|
+
setFacetState({});
|
|
13026
|
+
facetRequestRef.current = /* @__PURE__ */ new Map();
|
|
13027
|
+
}, [facetsEnabled, data, searchValue]);
|
|
12609
13028
|
(0, import_react21.useEffect)(() => {
|
|
12610
13029
|
if (!controlledQuery || controlledQuery.state.page === safePage) return;
|
|
12611
13030
|
emitControlledQueryChange({ page: safePage });
|
|
@@ -12650,11 +13069,11 @@ function MatrxDataTableCore({
|
|
|
12650
13069
|
});
|
|
12651
13070
|
const hasActiveFilters = activeFilterCount > 0 || Boolean(searchValue.trim()) || intelligentSearchEnabled && searchScope !== "all" || Boolean(anyOfValue.trim()) || completeLayeredFilterRules(layeredFilters).length > 0 || facetActive;
|
|
12652
13071
|
const changeCount = (0, import_react21.useMemo)(() => {
|
|
12653
|
-
let
|
|
13072
|
+
let n2 = 0;
|
|
12654
13073
|
for (const fields of Object.values(edits)) {
|
|
12655
|
-
|
|
13074
|
+
n2 += Object.keys(fields).length;
|
|
12656
13075
|
}
|
|
12657
|
-
return
|
|
13076
|
+
return n2;
|
|
12658
13077
|
}, [edits]);
|
|
12659
13078
|
const showSearch = toolbar?.search !== false;
|
|
12660
13079
|
const openDetail = (row) => {
|
|
@@ -12733,6 +13152,23 @@ function MatrxDataTableCore({
|
|
|
12733
13152
|
icon: void 0
|
|
12734
13153
|
} : emptyState;
|
|
12735
13154
|
const commitCell = (rowId, field, next) => {
|
|
13155
|
+
if (edit?.validate) {
|
|
13156
|
+
const row = data.find((candidate) => getRowId(candidate) === rowId);
|
|
13157
|
+
if (row) {
|
|
13158
|
+
let refusal;
|
|
13159
|
+
try {
|
|
13160
|
+
refusal = edit.validate({
|
|
13161
|
+
row: applyRowEdits(row, edits[rowId]),
|
|
13162
|
+
rowId,
|
|
13163
|
+
columnId: field,
|
|
13164
|
+
value: next
|
|
13165
|
+
});
|
|
13166
|
+
} catch {
|
|
13167
|
+
refusal = void 0;
|
|
13168
|
+
}
|
|
13169
|
+
if (refusal) return refusal;
|
|
13170
|
+
}
|
|
13171
|
+
}
|
|
12736
13172
|
const scope = editScopeKey;
|
|
12737
13173
|
const nextEdits = { [rowId]: { [field]: next } };
|
|
12738
13174
|
const revision = setCellEdit(rowId, field, next);
|
|
@@ -12777,9 +13213,29 @@ function MatrxDataTableCore({
|
|
|
12777
13213
|
setEditRequest((current) => ({
|
|
12778
13214
|
rowId: getRowId(row),
|
|
12779
13215
|
field,
|
|
12780
|
-
nonce: (current?.nonce ?? 0) + 1
|
|
13216
|
+
nonce: (current?.nonce ?? 0) + 1,
|
|
13217
|
+
seed: null
|
|
12781
13218
|
}));
|
|
12782
13219
|
};
|
|
13220
|
+
const requestCellEdit = (address, seed) => {
|
|
13221
|
+
if (!editEnabled) return false;
|
|
13222
|
+
const row = data.find((candidate) => getRowId(candidate) === address.rowId);
|
|
13223
|
+
if (!row) return false;
|
|
13224
|
+
const column = visibleColumns.find(
|
|
13225
|
+
(candidate) => columnId(candidate) === address.fieldName
|
|
13226
|
+
);
|
|
13227
|
+
if (!column?.editable || !(column.editableIf?.(row) ?? true)) return false;
|
|
13228
|
+
const field = column.accessorKey ? String(column.accessorKey) : columnId(column);
|
|
13229
|
+
setEditRequest((current) => ({
|
|
13230
|
+
rowId: address.rowId,
|
|
13231
|
+
field,
|
|
13232
|
+
nonce: (current?.nonce ?? 0) + 1,
|
|
13233
|
+
seed
|
|
13234
|
+
}));
|
|
13235
|
+
return true;
|
|
13236
|
+
};
|
|
13237
|
+
const requestCellEditRef = (0, import_react21.useRef)(requestCellEdit);
|
|
13238
|
+
requestCellEditRef.current = requestCellEdit;
|
|
12783
13239
|
const buildRecordControls = (row) => {
|
|
12784
13240
|
const rowId = getRowId(row);
|
|
12785
13241
|
const pending = edits[rowId];
|
|
@@ -13020,17 +13476,78 @@ function MatrxDataTableCore({
|
|
|
13020
13476
|
setEdits({});
|
|
13021
13477
|
edit?.onCancel?.();
|
|
13022
13478
|
};
|
|
13023
|
-
|
|
13024
|
-
|
|
13025
|
-
return host.rowContextRegistry.register(tableContextMenuInstanceId, (rowId) => {
|
|
13479
|
+
const resolveMenuLevel = (target) => {
|
|
13480
|
+
const rowFor = (rowId) => {
|
|
13026
13481
|
const row = data.find((candidate) => getRowId(candidate) === rowId);
|
|
13027
13482
|
if (!row) return null;
|
|
13028
|
-
|
|
13029
|
-
|
|
13030
|
-
|
|
13031
|
-
|
|
13032
|
-
|
|
13033
|
-
|
|
13483
|
+
return applyRowEdits(row, edits[rowId]);
|
|
13484
|
+
};
|
|
13485
|
+
const columnFor = (id) => visibleColumns.find((col) => columnId(col) === id);
|
|
13486
|
+
const labelFor = (col, id) => col?.label ?? (typeof col?.header === "string" ? col.header : id);
|
|
13487
|
+
const fromHost = (payload) => host.createDefaultMenuContext?.(payload) ?? null;
|
|
13488
|
+
switch (target.level) {
|
|
13489
|
+
case "row": {
|
|
13490
|
+
if (!target.rowId) return null;
|
|
13491
|
+
const displayRow = rowFor(target.rowId);
|
|
13492
|
+
if (!displayRow) return null;
|
|
13493
|
+
const controls = buildRecordControls(displayRow);
|
|
13494
|
+
return contextMenu?.resolveRowContext?.(displayRow, controls) ?? fromHost({ level: "row", row: displayRow, rowId: target.rowId, controls });
|
|
13495
|
+
}
|
|
13496
|
+
case "cell": {
|
|
13497
|
+
if (!target.rowId || !target.columnId) return null;
|
|
13498
|
+
const displayRow = rowFor(target.rowId);
|
|
13499
|
+
const col = columnFor(target.columnId);
|
|
13500
|
+
if (!displayRow || !col) return null;
|
|
13501
|
+
const controls = buildRecordControls(displayRow);
|
|
13502
|
+
const value = spreadsheet?.readCell ? spreadsheet.readCell(displayRow, target.columnId) : getCellValue(displayRow, col);
|
|
13503
|
+
const args = {
|
|
13504
|
+
row: displayRow,
|
|
13505
|
+
rowId: target.rowId,
|
|
13506
|
+
columnId: target.columnId,
|
|
13507
|
+
columnLabel: labelFor(col, target.columnId),
|
|
13508
|
+
value,
|
|
13509
|
+
text: stringifyCellValue(value),
|
|
13510
|
+
controls
|
|
13511
|
+
};
|
|
13512
|
+
return contextMenu?.resolveCellContext?.(args) ?? fromHost({ level: "cell", ...args });
|
|
13513
|
+
}
|
|
13514
|
+
case "column": {
|
|
13515
|
+
if (!target.columnId) return null;
|
|
13516
|
+
const col = columnFor(target.columnId);
|
|
13517
|
+
if (!col) return null;
|
|
13518
|
+
const args = {
|
|
13519
|
+
columnId: target.columnId,
|
|
13520
|
+
columnLabel: labelFor(col, target.columnId),
|
|
13521
|
+
values: paginated.map(
|
|
13522
|
+
(row) => getCellValue(applyRowEdits(row, edits[getRowId(row)]), col)
|
|
13523
|
+
)
|
|
13524
|
+
};
|
|
13525
|
+
return contextMenu?.resolveColumnContext?.(args) ?? fromHost({ level: "column", ...args });
|
|
13526
|
+
}
|
|
13527
|
+
case "selection": {
|
|
13528
|
+
const addresses = sheetRef.current.selectionAddresses();
|
|
13529
|
+
const cellCount = addresses.rowIds.length * addresses.columnIds.length;
|
|
13530
|
+
if (cellCount <= 1) {
|
|
13531
|
+
return resolveMenuLevel({ ...target, level: "cell" });
|
|
13532
|
+
}
|
|
13533
|
+
const args = { ...addresses, tsv: sheetRef.current.selectionTsv(), cellCount };
|
|
13534
|
+
return contextMenu?.resolveSelectionContext?.(args) ?? fromHost({ level: "selection", ...args });
|
|
13535
|
+
}
|
|
13536
|
+
case "table": {
|
|
13537
|
+
const args = { rowCount: data.length, columnIds: visibleColumns.map((col) => columnId(col)) };
|
|
13538
|
+
return contextMenu?.resolveTableContext?.(args) ?? fromHost({ level: "table", ...args });
|
|
13539
|
+
}
|
|
13540
|
+
}
|
|
13541
|
+
};
|
|
13542
|
+
const resolveMenuLevelRef = (0, import_react21.useRef)(resolveMenuLevel);
|
|
13543
|
+
resolveMenuLevelRef.current = resolveMenuLevel;
|
|
13544
|
+
(0, import_react21.useEffect)(() => {
|
|
13545
|
+
if (!host.rowContextRegistry) return;
|
|
13546
|
+
return host.rowContextRegistry.register(
|
|
13547
|
+
tableContextMenuInstanceId,
|
|
13548
|
+
(target) => resolveMenuLevelRef.current(target)
|
|
13549
|
+
);
|
|
13550
|
+
}, [host.rowContextRegistry, tableContextMenuInstanceId]);
|
|
13034
13551
|
const showActionsCol = windowEnabled || Boolean(rowActions) || showInlineRowCopy;
|
|
13035
13552
|
const selectedIdSet = (0, import_react21.useMemo)(
|
|
13036
13553
|
() => new Set(selection?.selectedIds ?? []),
|
|
@@ -13112,8 +13629,19 @@ function MatrxDataTableCore({
|
|
|
13112
13629
|
dirty: Boolean(rowEdits && field in rowEdits),
|
|
13113
13630
|
onCommit: (next) => commitCell(id, field, next),
|
|
13114
13631
|
...href === void 0 ? {} : { href },
|
|
13115
|
-
...
|
|
13116
|
-
|
|
13632
|
+
...spreadsheetEnabled ? {
|
|
13633
|
+
// 🚨 THE CLICK LAW, enforced where the two paths meet. In a grid
|
|
13634
|
+
// with spreadsheet gestures a single click SELECTS a cell — it
|
|
13635
|
+
// may never drop a person into a free-text buffer, because the
|
|
13636
|
+
// same click is how they start a range, and an editor that opens
|
|
13637
|
+
// under the pointer eats the drag and the next keystroke. So the
|
|
13638
|
+
// editor opens the way it does in Excel: Enter, F2, the hover
|
|
13639
|
+
// pencil, or simply typing. An explicit `editTrigger: "click"`
|
|
13640
|
+
// does not override this; the law is the table's, not the
|
|
13641
|
+
// column's.
|
|
13642
|
+
editTrigger: "pencil"
|
|
13643
|
+
} : col.editTrigger === void 0 ? {} : { editTrigger: col.editTrigger },
|
|
13644
|
+
...editRequest?.rowId === id && editRequest.field === field ? { editRequest: editRequest.nonce, editSeed: editRequest.seed } : {}
|
|
13117
13645
|
}
|
|
13118
13646
|
);
|
|
13119
13647
|
}
|
|
@@ -13871,6 +14399,7 @@ function MatrxDataTableCore({
|
|
|
13871
14399
|
"th",
|
|
13872
14400
|
{
|
|
13873
14401
|
"data-matrx-table-column-id": id,
|
|
14402
|
+
"data-matrx-header-column-id": id,
|
|
13874
14403
|
"data-matrx-column-drag-shadow": isColumnDragShadow ? "true" : void 0,
|
|
13875
14404
|
"aria-sort": isSorted ? sort?.direction === "asc" ? "ascending" : "descending" : void 0,
|
|
13876
14405
|
className: cn(
|
|
@@ -13907,6 +14436,12 @@ function MatrxDataTableCore({
|
|
|
13907
14436
|
{
|
|
13908
14437
|
label: col.header,
|
|
13909
14438
|
labelText: headerLabel,
|
|
14439
|
+
...facetsEnabled ? {
|
|
14440
|
+
facets: facetState[id]?.data ?? null,
|
|
14441
|
+
facetsLoading: facetState[id]?.loading ?? false,
|
|
14442
|
+
...facetState[id]?.error === void 0 ? {} : { facetsError: facetState[id]?.error },
|
|
14443
|
+
onFilterOpen: () => requestFacets(id)
|
|
14444
|
+
} : {},
|
|
13910
14445
|
sortable: col.sortable !== false,
|
|
13911
14446
|
isSorted: Boolean(isSorted),
|
|
13912
14447
|
sortDirection: sort?.direction ?? defaultSortDirection,
|
|
@@ -14581,8 +15116,8 @@ function MatrxDataTableCore({
|
|
|
14581
15116
|
itemsPerPage: pageSize === 0 && allRowsAreLoaded ? 0 : effectivePageSize,
|
|
14582
15117
|
currentPage: safePage,
|
|
14583
15118
|
onPageChange: setPage,
|
|
14584
|
-
onItemsPerPageChange: (
|
|
14585
|
-
setPageSize(
|
|
15119
|
+
onItemsPerPageChange: (n2) => {
|
|
15120
|
+
setPageSize(n2);
|
|
14586
15121
|
if (!controlledQuery) setPage(1);
|
|
14587
15122
|
},
|
|
14588
15123
|
pageSizeOptions: pageSizeOptions.filter((size) => size > 0),
|