@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
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 {
|
|
@@ -5139,10 +5139,10 @@ function passesColumnFilter(value, filter) {
|
|
|
5139
5139
|
if (raw === "") return false;
|
|
5140
5140
|
const normalized = raw.replace(/[^0-9.-]/g, "");
|
|
5141
5141
|
if (normalized === "") return false;
|
|
5142
|
-
const
|
|
5143
|
-
if (!Number.isFinite(
|
|
5144
|
-
if (filter.min !== void 0 &&
|
|
5145
|
-
if (filter.max !== void 0 &&
|
|
5142
|
+
const n2 = typeof value === "number" ? value : Number(normalized);
|
|
5143
|
+
if (!Number.isFinite(n2)) return false;
|
|
5144
|
+
if (filter.min !== void 0 && n2 < filter.min) return false;
|
|
5145
|
+
if (filter.max !== void 0 && n2 > filter.max) return false;
|
|
5146
5146
|
return true;
|
|
5147
5147
|
}
|
|
5148
5148
|
}
|
|
@@ -5205,26 +5205,26 @@ function filterAndSortRows(rows, columns, columnFilters, sort, globalSearch, any
|
|
|
5205
5205
|
return result;
|
|
5206
5206
|
}
|
|
5207
5207
|
function countActiveColumnFilters(filters) {
|
|
5208
|
-
let
|
|
5208
|
+
let n2 = 0;
|
|
5209
5209
|
for (const f of Object.values(filters)) {
|
|
5210
5210
|
if (!f) continue;
|
|
5211
5211
|
switch (f.kind) {
|
|
5212
5212
|
case "text":
|
|
5213
|
-
if (f.value.trim() || f.mode && f.mode !== "contains")
|
|
5213
|
+
if (f.value.trim() || f.mode && f.mode !== "contains") n2 += 1;
|
|
5214
5214
|
break;
|
|
5215
5215
|
case "select":
|
|
5216
5216
|
if (f.values !== void 0 || f.value && f.value !== "__all__")
|
|
5217
|
-
|
|
5217
|
+
n2 += 1;
|
|
5218
5218
|
break;
|
|
5219
5219
|
case "boolean":
|
|
5220
|
-
|
|
5220
|
+
n2 += 1;
|
|
5221
5221
|
break;
|
|
5222
5222
|
case "number":
|
|
5223
|
-
if (f.min !== void 0 || f.max !== void 0)
|
|
5223
|
+
if (f.min !== void 0 || f.max !== void 0) n2 += 1;
|
|
5224
5224
|
break;
|
|
5225
5225
|
}
|
|
5226
5226
|
}
|
|
5227
|
-
return
|
|
5227
|
+
return n2;
|
|
5228
5228
|
}
|
|
5229
5229
|
function isColumnFilterActive(filter) {
|
|
5230
5230
|
if (!filter) return false;
|
|
@@ -5506,8 +5506,8 @@ function parseLayeredFilters(raw) {
|
|
|
5506
5506
|
}
|
|
5507
5507
|
}
|
|
5508
5508
|
function positiveInt(raw, fallback) {
|
|
5509
|
-
const
|
|
5510
|
-
return Number.isFinite(
|
|
5509
|
+
const n2 = raw ? Number.parseInt(raw, 10) : Number.NaN;
|
|
5510
|
+
return Number.isFinite(n2) && n2 > 0 ? n2 : fallback;
|
|
5511
5511
|
}
|
|
5512
5512
|
function tableUrlParamPrefix(tableId) {
|
|
5513
5513
|
if (!/^[a-z][a-z0-9-]{0,63}$/.test(tableId)) {
|
|
@@ -5708,6 +5708,7 @@ import {
|
|
|
5708
5708
|
forwardRef as forwardRef12,
|
|
5709
5709
|
useEffect as useEffect9,
|
|
5710
5710
|
useMemo as useMemo5,
|
|
5711
|
+
useRef as useRef10,
|
|
5711
5712
|
useState as useState14
|
|
5712
5713
|
} from "react";
|
|
5713
5714
|
import { useDraggable } from "@dnd-kit/core";
|
|
@@ -5855,6 +5856,95 @@ var CommandShortcut = ({
|
|
|
5855
5856
|
};
|
|
5856
5857
|
CommandShortcut.displayName = "CommandShortcut";
|
|
5857
5858
|
|
|
5859
|
+
// src/data-table/facets.ts
|
|
5860
|
+
var MAX_LISTABLE_FACET_LENGTH = 300;
|
|
5861
|
+
var DEFAULT_FACET_LIMIT = 200;
|
|
5862
|
+
var MAX_FACET_LIMIT = 500;
|
|
5863
|
+
function facetText(raw) {
|
|
5864
|
+
if (raw === null || raw === void 0) return "";
|
|
5865
|
+
if (typeof raw === "object") {
|
|
5866
|
+
try {
|
|
5867
|
+
return JSON.stringify(raw);
|
|
5868
|
+
} catch {
|
|
5869
|
+
return String(raw);
|
|
5870
|
+
}
|
|
5871
|
+
}
|
|
5872
|
+
return String(raw);
|
|
5873
|
+
}
|
|
5874
|
+
function computeColumnFacets(args) {
|
|
5875
|
+
const { columnId: columnId2, rows, readValue: readValue2 } = args;
|
|
5876
|
+
const limit = Math.min(Math.max(args.limit ?? DEFAULT_FACET_LIMIT, 1), MAX_FACET_LIMIT);
|
|
5877
|
+
const counts = /* @__PURE__ */ new Map();
|
|
5878
|
+
const longValues = /* @__PURE__ */ new Set();
|
|
5879
|
+
let blank = 0;
|
|
5880
|
+
let maxLength = 0;
|
|
5881
|
+
for (const row of rows) {
|
|
5882
|
+
let raw;
|
|
5883
|
+
try {
|
|
5884
|
+
raw = readValue2(row, columnId2);
|
|
5885
|
+
} catch {
|
|
5886
|
+
raw = void 0;
|
|
5887
|
+
}
|
|
5888
|
+
const trimmed = facetText(raw).trim();
|
|
5889
|
+
if (trimmed === "") {
|
|
5890
|
+
blank += 1;
|
|
5891
|
+
continue;
|
|
5892
|
+
}
|
|
5893
|
+
if (trimmed.length > maxLength) maxLength = trimmed.length;
|
|
5894
|
+
if (trimmed.length > MAX_LISTABLE_FACET_LENGTH) {
|
|
5895
|
+
longValues.add(trimmed);
|
|
5896
|
+
continue;
|
|
5897
|
+
}
|
|
5898
|
+
counts.set(trimmed, (counts.get(trimmed) ?? 0) + 1);
|
|
5899
|
+
}
|
|
5900
|
+
const values = [...counts.entries()].map(([value, count]) => ({ value, count })).sort((a, b) => b.count - a.count || a.value.localeCompare(b.value)).slice(0, limit);
|
|
5901
|
+
return {
|
|
5902
|
+
columnId: columnId2,
|
|
5903
|
+
totalRows: rows.length,
|
|
5904
|
+
filled: rows.length - blank,
|
|
5905
|
+
blank,
|
|
5906
|
+
distinctCount: counts.size + longValues.size,
|
|
5907
|
+
maxLength,
|
|
5908
|
+
unlistable: longValues.size,
|
|
5909
|
+
limit,
|
|
5910
|
+
truncated: counts.size > limit,
|
|
5911
|
+
values,
|
|
5912
|
+
answeredBy: "local",
|
|
5913
|
+
complete: args.complete ?? true
|
|
5914
|
+
};
|
|
5915
|
+
}
|
|
5916
|
+
function localFacetsAreComplete(loadedRowCount, total) {
|
|
5917
|
+
if (total === void 0 || !Number.isFinite(total) || total < 0) return false;
|
|
5918
|
+
return loadedRowCount >= total;
|
|
5919
|
+
}
|
|
5920
|
+
var NUMBERS = new Intl.NumberFormat("en-US");
|
|
5921
|
+
function n(value) {
|
|
5922
|
+
try {
|
|
5923
|
+
return NUMBERS.format(value);
|
|
5924
|
+
} catch {
|
|
5925
|
+
return String(value);
|
|
5926
|
+
}
|
|
5927
|
+
}
|
|
5928
|
+
function describeFacetSource(facets, noun = "row") {
|
|
5929
|
+
if (!facets) return "";
|
|
5930
|
+
const plural2 = `${noun}s`;
|
|
5931
|
+
if (!facets.complete) {
|
|
5932
|
+
return `These counts cover the ${n(facets.totalRows)} ${plural2} loaded here, not the whole table.`;
|
|
5933
|
+
}
|
|
5934
|
+
if (facets.truncated) {
|
|
5935
|
+
return `Showing the ${n(facets.values.length)} most common of ${n(facets.distinctCount)} values.`;
|
|
5936
|
+
}
|
|
5937
|
+
if (facets.unlistable > 0) {
|
|
5938
|
+
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"}.`;
|
|
5939
|
+
}
|
|
5940
|
+
return "";
|
|
5941
|
+
}
|
|
5942
|
+
var FACETS_LOADING_NOTICE = "Counting values\u2026";
|
|
5943
|
+
function describeFacetFailure(error) {
|
|
5944
|
+
const detail = error instanceof Error ? error.message : String(error ?? "");
|
|
5945
|
+
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.";
|
|
5946
|
+
}
|
|
5947
|
+
|
|
5858
5948
|
// src/data-table/column-marker.ts
|
|
5859
5949
|
var MARKER_ACCESSORS = {
|
|
5860
5950
|
favorite: "favorite",
|
|
@@ -5922,6 +6012,10 @@ function ColumnHeaderCell({
|
|
|
5922
6012
|
filterFooterHint,
|
|
5923
6013
|
allowNegation = false,
|
|
5924
6014
|
allowNullModes = false,
|
|
6015
|
+
facets,
|
|
6016
|
+
facetsLoading = false,
|
|
6017
|
+
facetsError,
|
|
6018
|
+
onFilterOpen,
|
|
5925
6019
|
reorderColumn
|
|
5926
6020
|
}) {
|
|
5927
6021
|
const reorderEnabled = reorderColumn !== void 0;
|
|
@@ -5956,6 +6050,11 @@ function ColumnHeaderCell({
|
|
|
5956
6050
|
setPendingNegation(filterValue?.negated ?? false);
|
|
5957
6051
|
}
|
|
5958
6052
|
}, [filterOpen, filterValue]);
|
|
6053
|
+
const notifyOpen = useRef10(onFilterOpen);
|
|
6054
|
+
notifyOpen.current = onFilterOpen;
|
|
6055
|
+
useEffect9(() => {
|
|
6056
|
+
if (filterOpen) notifyOpen.current?.();
|
|
6057
|
+
}, [filterOpen]);
|
|
5959
6058
|
const applyFilter = () => {
|
|
5960
6059
|
onFilterChange(draftFilter);
|
|
5961
6060
|
setFilterOpen(false);
|
|
@@ -6050,6 +6149,9 @@ function ColumnHeaderCell({
|
|
|
6050
6149
|
selectOptions,
|
|
6051
6150
|
selectSingle,
|
|
6052
6151
|
selectAllowCustom,
|
|
6152
|
+
facets: facets ?? null,
|
|
6153
|
+
facetsLoading,
|
|
6154
|
+
...facetsError === void 0 ? {} : { facetsError },
|
|
6053
6155
|
...markerLabels ? {
|
|
6054
6156
|
booleanLabels: {
|
|
6055
6157
|
all: "All",
|
|
@@ -6274,8 +6376,43 @@ function FilterBody({
|
|
|
6274
6376
|
selectSingle = false,
|
|
6275
6377
|
selectAllowCustom = false,
|
|
6276
6378
|
allowNullModes = false,
|
|
6277
|
-
booleanLabels
|
|
6379
|
+
booleanLabels,
|
|
6380
|
+
facets = null,
|
|
6381
|
+
facetsLoading = false,
|
|
6382
|
+
facetsError
|
|
6278
6383
|
}) {
|
|
6384
|
+
const checklist = facetsLoading || facetsError || facets && (facets.values.length > 0 || facets.blank > 0) ? /* @__PURE__ */ jsx31(
|
|
6385
|
+
FacetChecklist,
|
|
6386
|
+
{
|
|
6387
|
+
facets,
|
|
6388
|
+
loading: facetsLoading,
|
|
6389
|
+
...facetsError === void 0 ? {} : { error: facetsError },
|
|
6390
|
+
value,
|
|
6391
|
+
onChange
|
|
6392
|
+
}
|
|
6393
|
+
) : null;
|
|
6394
|
+
if (checklist && kind === "select" && facets && facets.values.length > 0) {
|
|
6395
|
+
return /* @__PURE__ */ jsx31("div", { className: "space-y-2", children: checklist });
|
|
6396
|
+
}
|
|
6397
|
+
if (checklist) {
|
|
6398
|
+
return /* @__PURE__ */ jsxs22("div", { className: "space-y-2", children: [
|
|
6399
|
+
checklist,
|
|
6400
|
+
/* @__PURE__ */ jsx31("div", { className: "h-px bg-border" }),
|
|
6401
|
+
/* @__PURE__ */ jsx31(
|
|
6402
|
+
FilterBody,
|
|
6403
|
+
{
|
|
6404
|
+
kind,
|
|
6405
|
+
value,
|
|
6406
|
+
onChange,
|
|
6407
|
+
selectOptions,
|
|
6408
|
+
selectSingle,
|
|
6409
|
+
selectAllowCustom,
|
|
6410
|
+
allowNullModes,
|
|
6411
|
+
...booleanLabels === void 0 ? {} : { booleanLabels }
|
|
6412
|
+
}
|
|
6413
|
+
)
|
|
6414
|
+
] });
|
|
6415
|
+
}
|
|
6279
6416
|
if (kind === "text") {
|
|
6280
6417
|
const text = value?.kind === "text" ? value.value : "";
|
|
6281
6418
|
const mode = (value?.kind === "text" ? value.mode : void 0) ?? "contains";
|
|
@@ -6386,6 +6523,112 @@ function FilterBody({
|
|
|
6386
6523
|
}
|
|
6387
6524
|
return /* @__PURE__ */ jsx31(NumberFilterBody, { value, onChange });
|
|
6388
6525
|
}
|
|
6526
|
+
function FacetChecklist({
|
|
6527
|
+
facets,
|
|
6528
|
+
loading,
|
|
6529
|
+
error,
|
|
6530
|
+
value,
|
|
6531
|
+
onChange
|
|
6532
|
+
}) {
|
|
6533
|
+
const [query, setQuery] = useState14("");
|
|
6534
|
+
const selected = value?.kind === "select" ? value.values ?? (value.value && value.value !== "__all__" ? [value.value] : []) : [];
|
|
6535
|
+
const selectedSet = new Set(selected);
|
|
6536
|
+
const rows = useMemo5(() => {
|
|
6537
|
+
if (!facets) return [];
|
|
6538
|
+
const listed = facets.values.map((entry) => ({
|
|
6539
|
+
value: entry.value,
|
|
6540
|
+
label: entry.value,
|
|
6541
|
+
count: entry.count
|
|
6542
|
+
}));
|
|
6543
|
+
const withBlank = facets.blank > 0 ? [{ value: "", label: "(empty)", count: facets.blank }, ...listed] : listed;
|
|
6544
|
+
const q = query.trim().toLowerCase();
|
|
6545
|
+
if (!q) return withBlank;
|
|
6546
|
+
return withBlank.filter((row) => row.label.toLowerCase().includes(q));
|
|
6547
|
+
}, [facets, query]);
|
|
6548
|
+
const toggle = (candidate) => {
|
|
6549
|
+
const next = new Set(selectedSet);
|
|
6550
|
+
if (next.has(candidate)) next.delete(candidate);
|
|
6551
|
+
else next.add(candidate);
|
|
6552
|
+
const values = [...next];
|
|
6553
|
+
onChange(
|
|
6554
|
+
values.length === 0 ? void 0 : { kind: "select", value: values[0] ?? "", values }
|
|
6555
|
+
);
|
|
6556
|
+
};
|
|
6557
|
+
const notice = error ?? (loading ? FACETS_LOADING_NOTICE : describeFacetSource(facets));
|
|
6558
|
+
return /* @__PURE__ */ jsxs22("div", { className: "space-y-1.5", children: [
|
|
6559
|
+
/* @__PURE__ */ jsx31("p", { className: "px-1 text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: "Values" }),
|
|
6560
|
+
facets && facets.values.length + (facets.blank > 0 ? 1 : 0) > 8 ? /* @__PURE__ */ jsx31(
|
|
6561
|
+
Input,
|
|
6562
|
+
{
|
|
6563
|
+
"data-matrx-filter-autofocus": true,
|
|
6564
|
+
value: query,
|
|
6565
|
+
onChange: (event) => setQuery(event.target.value),
|
|
6566
|
+
placeholder: "Find a value\u2026",
|
|
6567
|
+
className: "h-7 text-sm",
|
|
6568
|
+
style: { fontSize: "16px" }
|
|
6569
|
+
}
|
|
6570
|
+
) : null,
|
|
6571
|
+
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) => {
|
|
6572
|
+
const checked = selectedSet.has(row.value);
|
|
6573
|
+
return /* @__PURE__ */ jsx31("li", { children: /* @__PURE__ */ jsxs22(
|
|
6574
|
+
"button",
|
|
6575
|
+
{
|
|
6576
|
+
type: "button",
|
|
6577
|
+
role: "checkbox",
|
|
6578
|
+
"aria-checked": checked,
|
|
6579
|
+
"data-matrx-facet-value": row.value === "" ? "__blank__" : row.value,
|
|
6580
|
+
onClick: () => toggle(row.value),
|
|
6581
|
+
className: cn(
|
|
6582
|
+
"flex w-full items-center gap-2 rounded px-1.5 py-1 text-left text-xs hover:bg-muted",
|
|
6583
|
+
checked && "bg-primary/10"
|
|
6584
|
+
),
|
|
6585
|
+
children: [
|
|
6586
|
+
/* @__PURE__ */ jsx31(
|
|
6587
|
+
"span",
|
|
6588
|
+
{
|
|
6589
|
+
"aria-hidden": true,
|
|
6590
|
+
className: cn(
|
|
6591
|
+
"flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-[3px] border",
|
|
6592
|
+
checked ? "border-primary bg-primary text-primary-foreground" : "border-border"
|
|
6593
|
+
),
|
|
6594
|
+
children: checked ? /* @__PURE__ */ jsx31(Check, { className: "h-2.5 w-2.5" }) : null
|
|
6595
|
+
}
|
|
6596
|
+
),
|
|
6597
|
+
/* @__PURE__ */ jsx31("span", { className: cn("min-w-0 flex-1 truncate", row.value === "" && "italic text-muted-foreground"), children: row.label }),
|
|
6598
|
+
/* @__PURE__ */ jsx31(
|
|
6599
|
+
"span",
|
|
6600
|
+
{
|
|
6601
|
+
"data-matrx-facet-count": String(row.count),
|
|
6602
|
+
className: "shrink-0 tabular-nums text-[11px] text-muted-foreground",
|
|
6603
|
+
children: row.count.toLocaleString("en-US")
|
|
6604
|
+
}
|
|
6605
|
+
)
|
|
6606
|
+
]
|
|
6607
|
+
}
|
|
6608
|
+
) }, row.value === "" ? "__blank__" : row.value);
|
|
6609
|
+
}) }) : 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." }),
|
|
6610
|
+
notice ? /* @__PURE__ */ jsx31(
|
|
6611
|
+
"p",
|
|
6612
|
+
{
|
|
6613
|
+
"data-matrx-facet-notice": "true",
|
|
6614
|
+
className: cn(
|
|
6615
|
+
"px-1 text-[11px] leading-snug",
|
|
6616
|
+
error ? "text-amber-700 dark:text-amber-400" : "text-muted-foreground"
|
|
6617
|
+
),
|
|
6618
|
+
children: notice
|
|
6619
|
+
}
|
|
6620
|
+
) : null,
|
|
6621
|
+
selected.length > 0 ? /* @__PURE__ */ jsx31(
|
|
6622
|
+
"button",
|
|
6623
|
+
{
|
|
6624
|
+
type: "button",
|
|
6625
|
+
onClick: () => onChange(void 0),
|
|
6626
|
+
className: "px-1 text-[11px] text-muted-foreground underline-offset-2 hover:underline",
|
|
6627
|
+
children: "Clear selection"
|
|
6628
|
+
}
|
|
6629
|
+
) : null
|
|
6630
|
+
] });
|
|
6631
|
+
}
|
|
6389
6632
|
function SearchableSelectFilter({
|
|
6390
6633
|
selected,
|
|
6391
6634
|
options,
|
|
@@ -6572,15 +6815,15 @@ function NumberFilterBody({
|
|
|
6572
6815
|
}
|
|
6573
6816
|
function parseOptionalNumber(raw) {
|
|
6574
6817
|
if (raw.trim() === "") return void 0;
|
|
6575
|
-
const
|
|
6576
|
-
return Number.isFinite(
|
|
6818
|
+
const n2 = Number(raw.replace(/[^0-9.-]/g, ""));
|
|
6819
|
+
return Number.isFinite(n2) ? n2 : void 0;
|
|
6577
6820
|
}
|
|
6578
6821
|
|
|
6579
6822
|
// src/data-table/ColumnResizeHandle.tsx
|
|
6580
6823
|
import {
|
|
6581
6824
|
useCallback as useCallback6,
|
|
6582
6825
|
useEffect as useEffect10,
|
|
6583
|
-
useRef as
|
|
6826
|
+
useRef as useRef11,
|
|
6584
6827
|
useState as useState15
|
|
6585
6828
|
} from "react";
|
|
6586
6829
|
|
|
@@ -6624,11 +6867,11 @@ function ColumnResizeHandle({
|
|
|
6624
6867
|
onResizeCancel,
|
|
6625
6868
|
onResizeCommit
|
|
6626
6869
|
}) {
|
|
6627
|
-
const handleRef =
|
|
6628
|
-
const activeResizeRef =
|
|
6629
|
-
const previewRafRef =
|
|
6630
|
-
const queuedWidthRef =
|
|
6631
|
-
const keyboardWidthRef =
|
|
6870
|
+
const handleRef = useRef11(null);
|
|
6871
|
+
const activeResizeRef = useRef11(null);
|
|
6872
|
+
const previewRafRef = useRef11(null);
|
|
6873
|
+
const queuedWidthRef = useRef11(null);
|
|
6874
|
+
const keyboardWidthRef = useRef11(null);
|
|
6632
6875
|
const [announcedWidth, setAnnouncedWidth] = useState15(null);
|
|
6633
6876
|
const bounds = resolveColumnResizeBounds(minWidth, maxWidth);
|
|
6634
6877
|
const cssVar = columnResizeCssVar(columnId2);
|
|
@@ -6890,16 +7133,16 @@ function computeAggregate(rows, column) {
|
|
|
6890
7133
|
value = total;
|
|
6891
7134
|
break;
|
|
6892
7135
|
case "sum":
|
|
6893
|
-
value = numbers.length === 0 ? null : numbers.reduce((acc,
|
|
7136
|
+
value = numbers.length === 0 ? null : numbers.reduce((acc, n2) => acc + n2, 0);
|
|
6894
7137
|
break;
|
|
6895
7138
|
case "average":
|
|
6896
|
-
value = numbers.length === 0 ? null : numbers.reduce((acc,
|
|
7139
|
+
value = numbers.length === 0 ? null : numbers.reduce((acc, n2) => acc + n2, 0) / numbers.length;
|
|
6897
7140
|
break;
|
|
6898
7141
|
case "min":
|
|
6899
|
-
value = numbers.length === 0 ? null : numbers.reduce((acc,
|
|
7142
|
+
value = numbers.length === 0 ? null : numbers.reduce((acc, n2) => n2 < acc ? n2 : acc);
|
|
6900
7143
|
break;
|
|
6901
7144
|
case "max":
|
|
6902
|
-
value = numbers.length === 0 ? null : numbers.reduce((acc,
|
|
7145
|
+
value = numbers.length === 0 ? null : numbers.reduce((acc, n2) => n2 > acc ? n2 : acc);
|
|
6903
7146
|
break;
|
|
6904
7147
|
case "empty":
|
|
6905
7148
|
value = total - filled.length;
|
|
@@ -7217,7 +7460,7 @@ function scrollOffsetForIndex(input) {
|
|
|
7217
7460
|
}
|
|
7218
7461
|
|
|
7219
7462
|
// src/data-table/useSpreadsheetGrid.ts
|
|
7220
|
-
import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo6, useRef as
|
|
7463
|
+
import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo6, useRef as useRef12, useState as useState16 } from "react";
|
|
7221
7464
|
|
|
7222
7465
|
// src/data-table/grid-selection.ts
|
|
7223
7466
|
function rangeBounds(range, rowIds, fieldNames) {
|
|
@@ -7323,7 +7566,7 @@ function moveSelection(current, move, rowIds, fieldNames) {
|
|
|
7323
7566
|
if (r === -1 || c === -1) return first;
|
|
7324
7567
|
const lastRow = rowIds.length - 1;
|
|
7325
7568
|
const lastCol = fieldNames.length - 1;
|
|
7326
|
-
const clamp = (
|
|
7569
|
+
const clamp = (n2, max) => Math.min(Math.max(n2, 0), max);
|
|
7327
7570
|
switch (move) {
|
|
7328
7571
|
case "up":
|
|
7329
7572
|
r = clamp(r - 1, lastRow);
|
|
@@ -7455,14 +7698,14 @@ function parseClipboardGrid(text) {
|
|
|
7455
7698
|
let row = [];
|
|
7456
7699
|
let cell = "";
|
|
7457
7700
|
let i = 0;
|
|
7458
|
-
const
|
|
7459
|
-
while (i <
|
|
7701
|
+
const n2 = text.length;
|
|
7702
|
+
while (i < n2) {
|
|
7460
7703
|
const ch = text[i];
|
|
7461
7704
|
if (cell === "" && ch === '"') {
|
|
7462
7705
|
let j = i + 1;
|
|
7463
7706
|
let out = "";
|
|
7464
7707
|
let closed = false;
|
|
7465
|
-
while (j <
|
|
7708
|
+
while (j < n2) {
|
|
7466
7709
|
const c = text[j];
|
|
7467
7710
|
if (c === '"') {
|
|
7468
7711
|
if (text[j + 1] === '"') {
|
|
@@ -7477,10 +7720,10 @@ function parseClipboardGrid(text) {
|
|
|
7477
7720
|
out += c;
|
|
7478
7721
|
j += 1;
|
|
7479
7722
|
}
|
|
7480
|
-
if (closed && (j >=
|
|
7723
|
+
if (closed && (j >= n2 || text[j] === " " || text[j] === "\n" || text[j] === "\r")) {
|
|
7481
7724
|
cell = out;
|
|
7482
7725
|
i = j;
|
|
7483
|
-
if (i >=
|
|
7726
|
+
if (i >= n2) break;
|
|
7484
7727
|
const d = text[i];
|
|
7485
7728
|
if (d === " ") {
|
|
7486
7729
|
row.push(cell);
|
|
@@ -7516,7 +7759,7 @@ function parseClipboardGrid(text) {
|
|
|
7516
7759
|
cell += ch;
|
|
7517
7760
|
i += 1;
|
|
7518
7761
|
}
|
|
7519
|
-
const endedOnBreak =
|
|
7762
|
+
const endedOnBreak = n2 > 0 && (text[n2 - 1] === "\n" || text[n2 - 1] === "\r");
|
|
7520
7763
|
if (!endedOnBreak) {
|
|
7521
7764
|
row.push(cell);
|
|
7522
7765
|
rows.push(row);
|
|
@@ -7595,11 +7838,11 @@ function directionOf(source, target) {
|
|
|
7595
7838
|
return null;
|
|
7596
7839
|
}
|
|
7597
7840
|
function tileIndex(i, a, b) {
|
|
7598
|
-
const
|
|
7599
|
-
if (
|
|
7841
|
+
const n2 = b - a + 1;
|
|
7842
|
+
if (n2 <= 0) return a;
|
|
7600
7843
|
if (i >= a && i <= b) return i;
|
|
7601
|
-
if (i > b) return a + (i - a) %
|
|
7602
|
-
return b - (a - 1 - i) %
|
|
7844
|
+
if (i > b) return a + (i - a) % n2;
|
|
7845
|
+
return b - (a - 1 - i) % n2;
|
|
7603
7846
|
}
|
|
7604
7847
|
function isFiniteNumber(v) {
|
|
7605
7848
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -7915,8 +8158,8 @@ function useSpreadsheetGrid(options) {
|
|
|
7915
8158
|
const [range, setRange] = useState16(null);
|
|
7916
8159
|
const [fillTarget, setFillTarget] = useState16(null);
|
|
7917
8160
|
const [stack, setStack] = useState16(() => createUndoStack(options?.undoDepth ?? 100));
|
|
7918
|
-
const draggingRef =
|
|
7919
|
-
const optionsRef =
|
|
8161
|
+
const draggingRef = useRef12(null);
|
|
8162
|
+
const optionsRef = useRef12(options);
|
|
7920
8163
|
optionsRef.current = options;
|
|
7921
8164
|
const rowIds = options?.rowIds ?? [];
|
|
7922
8165
|
const columnIds = useMemo6(
|
|
@@ -7944,6 +8187,26 @@ function useSpreadsheetGrid(options) {
|
|
|
7944
8187
|
for (let i = 0; i < columnIds.length; i += 1) map.set(columnIds[i], i);
|
|
7945
8188
|
return map;
|
|
7946
8189
|
}, [columnIds]);
|
|
8190
|
+
const screenPatches = useCallback7(
|
|
8191
|
+
(patches) => {
|
|
8192
|
+
const validate = optionsRef.current?.validateCell;
|
|
8193
|
+
if (!validate) return { accepted: patches, refusals: [] };
|
|
8194
|
+
const accepted = [];
|
|
8195
|
+
const refusals = [];
|
|
8196
|
+
for (const patch of patches) {
|
|
8197
|
+
let reason;
|
|
8198
|
+
try {
|
|
8199
|
+
reason = validate({ rowId: patch.rowId, columnId: patch.columnId, value: patch.value });
|
|
8200
|
+
} catch {
|
|
8201
|
+
reason = void 0;
|
|
8202
|
+
}
|
|
8203
|
+
if (reason) refusals.push({ columnId: patch.columnId, reason });
|
|
8204
|
+
else accepted.push(patch);
|
|
8205
|
+
}
|
|
8206
|
+
return { accepted, refusals };
|
|
8207
|
+
},
|
|
8208
|
+
[]
|
|
8209
|
+
);
|
|
7947
8210
|
const applyPatches = useCallback7(
|
|
7948
8211
|
async (patches, intent, label) => {
|
|
7949
8212
|
const current = optionsRef.current;
|
|
@@ -8000,9 +8263,10 @@ function useSpreadsheetGrid(options) {
|
|
|
8000
8263
|
...base,
|
|
8001
8264
|
range: { top: bounds.r0, left: bounds.c0, bottom: bounds.r1, right: bounds.c1 }
|
|
8002
8265
|
});
|
|
8003
|
-
|
|
8004
|
-
|
|
8005
|
-
|
|
8266
|
+
const screened = screenPatches(result.patches);
|
|
8267
|
+
await applyPatches(screened.accepted, "fill-down", "Filled down");
|
|
8268
|
+
announceSkips([...result.skipped, ...screened.refusals], result.summary);
|
|
8269
|
+
}, [fillRequestBase, bounds, applyPatches, announceSkips, screenPatches]);
|
|
8006
8270
|
const doClear = useCallback7(async () => {
|
|
8007
8271
|
const current = optionsRef.current;
|
|
8008
8272
|
if (!current || !bounds) return;
|
|
@@ -8023,9 +8287,13 @@ function useSpreadsheetGrid(options) {
|
|
|
8023
8287
|
patches.push({ rowId, columnId: columnId2, value: null });
|
|
8024
8288
|
}
|
|
8025
8289
|
}
|
|
8026
|
-
|
|
8027
|
-
|
|
8028
|
-
|
|
8290
|
+
const screened = screenPatches(patches);
|
|
8291
|
+
await applyPatches(screened.accepted, "clear", "Cleared");
|
|
8292
|
+
announceSkips(
|
|
8293
|
+
[...skipped, ...screened.refusals],
|
|
8294
|
+
`Cleared ${screened.accepted.length} cells.`
|
|
8295
|
+
);
|
|
8296
|
+
}, [bounds, applyPatches, announceSkips, screenPatches]);
|
|
8029
8297
|
const doUndo = useCallback7(async () => {
|
|
8030
8298
|
const taken = popUndo(stack);
|
|
8031
8299
|
if (!taken.entry) return;
|
|
@@ -8110,6 +8378,14 @@ function useSpreadsheetGrid(options) {
|
|
|
8110
8378
|
case "escape":
|
|
8111
8379
|
setRange(null);
|
|
8112
8380
|
return;
|
|
8381
|
+
case "edit":
|
|
8382
|
+
case "editSeeded": {
|
|
8383
|
+
const focused = range?.focus;
|
|
8384
|
+
if (!focused || !current.onEditRequest) return;
|
|
8385
|
+
const seed = action.kind === "editSeeded" ? action.seed : null;
|
|
8386
|
+
if (current.onEditRequest(focused, seed)) event.preventDefault();
|
|
8387
|
+
return;
|
|
8388
|
+
}
|
|
8113
8389
|
default:
|
|
8114
8390
|
return;
|
|
8115
8391
|
}
|
|
@@ -8124,6 +8400,13 @@ function useSpreadsheetGrid(options) {
|
|
|
8124
8400
|
);
|
|
8125
8401
|
return gridToTsv(grid);
|
|
8126
8402
|
}, [range, rowIds, columnIds]);
|
|
8403
|
+
const selectionAddresses = useCallback7(() => {
|
|
8404
|
+
if (!range || !bounds) return { rowIds: [], columnIds: [] };
|
|
8405
|
+
return {
|
|
8406
|
+
rowIds: rowIds.slice(bounds.r0, bounds.r1 + 1),
|
|
8407
|
+
columnIds: columnIds.slice(bounds.c0, bounds.c1 + 1)
|
|
8408
|
+
};
|
|
8409
|
+
}, [range, bounds, rowIds, columnIds]);
|
|
8127
8410
|
const onCopy = useCallback7(
|
|
8128
8411
|
(event) => {
|
|
8129
8412
|
if (!optionsRef.current || !range || targetsAnEditor(event.target)) return;
|
|
@@ -8179,11 +8462,12 @@ function useSpreadsheetGrid(options) {
|
|
|
8179
8462
|
patches.push({ rowId, columnId: columnId2, value: line[c] ?? null });
|
|
8180
8463
|
}
|
|
8181
8464
|
}
|
|
8182
|
-
|
|
8465
|
+
const screened = screenPatches(patches);
|
|
8466
|
+
void applyPatches(screened.accepted, "paste", "Pasted");
|
|
8183
8467
|
const tail = outside > 0 ? ` ${outside} landed past the edge of the table and were ignored.` : "";
|
|
8184
|
-
announceSkips(skipped, `Pasted ${
|
|
8468
|
+
announceSkips([...skipped, ...screened.refusals], `Pasted ${screened.accepted.length} cells.${tail}`);
|
|
8185
8469
|
},
|
|
8186
|
-
[range, rowIds, columnIds, applyPatches, announceSkips]
|
|
8470
|
+
[range, rowIds, columnIds, applyPatches, announceSkips, screenPatches]
|
|
8187
8471
|
);
|
|
8188
8472
|
const cellProps = useCallback7(
|
|
8189
8473
|
(rowId, columnId2) => {
|
|
@@ -8202,6 +8486,10 @@ function useSpreadsheetGrid(options) {
|
|
|
8202
8486
|
onMouseDown: (event) => {
|
|
8203
8487
|
if (event.button !== 0) return;
|
|
8204
8488
|
event.preventDefault();
|
|
8489
|
+
const origin = event.currentTarget;
|
|
8490
|
+
if (typeof HTMLElement !== "undefined" && origin instanceof HTMLElement) {
|
|
8491
|
+
origin.closest('[data-matrx-table-spreadsheet="true"]')?.focus({ preventScroll: true });
|
|
8492
|
+
}
|
|
8205
8493
|
setRange(
|
|
8206
8494
|
(previous) => event.shiftKey && previous ? { anchor: previous.anchor, focus: address } : { anchor: address, focus: address }
|
|
8207
8495
|
);
|
|
@@ -8242,9 +8530,9 @@ function useSpreadsheetGrid(options) {
|
|
|
8242
8530
|
},
|
|
8243
8531
|
[]
|
|
8244
8532
|
);
|
|
8245
|
-
const fillTargetRef =
|
|
8533
|
+
const fillTargetRef = useRef12(null);
|
|
8246
8534
|
fillTargetRef.current = fillTarget;
|
|
8247
|
-
const boundsRef =
|
|
8535
|
+
const boundsRef = useRef12(null);
|
|
8248
8536
|
boundsRef.current = bounds;
|
|
8249
8537
|
useEffect11(() => {
|
|
8250
8538
|
if (!options) return;
|
|
@@ -8263,12 +8551,13 @@ function useSpreadsheetGrid(options) {
|
|
|
8263
8551
|
source: { top: source.r0, left: source.c0, bottom: source.r1, right: source.c1 },
|
|
8264
8552
|
target
|
|
8265
8553
|
});
|
|
8266
|
-
|
|
8267
|
-
|
|
8554
|
+
const screened = screenPatches(result.patches);
|
|
8555
|
+
void applyPatches(screened.accepted, "fill", "Filled");
|
|
8556
|
+
announceSkips([...result.skipped, ...screened.refusals], result.summary);
|
|
8268
8557
|
};
|
|
8269
8558
|
window.addEventListener("mouseup", commit);
|
|
8270
8559
|
return () => window.removeEventListener("mouseup", commit);
|
|
8271
|
-
}, [options, fillRequestBase, applyPatches, announceSkips]);
|
|
8560
|
+
}, [options, fillRequestBase, applyPatches, announceSkips, screenPatches]);
|
|
8272
8561
|
return {
|
|
8273
8562
|
range,
|
|
8274
8563
|
bounds,
|
|
@@ -8284,17 +8573,19 @@ function useSpreadsheetGrid(options) {
|
|
|
8284
8573
|
isFillHandleCell,
|
|
8285
8574
|
startFillDrag,
|
|
8286
8575
|
canUndo: stack.past.length > 0,
|
|
8287
|
-
canRedo: stack.future.length > 0
|
|
8576
|
+
canRedo: stack.future.length > 0,
|
|
8577
|
+
selectionTsv: selectionAsTsv,
|
|
8578
|
+
selectionAddresses
|
|
8288
8579
|
};
|
|
8289
8580
|
}
|
|
8290
8581
|
|
|
8291
8582
|
// src/data-table/coverage.ts
|
|
8292
8583
|
var PARTIAL_BADGE = "Partial";
|
|
8293
8584
|
var UNKNOWN_TOTAL_BADGE = "Unknown total";
|
|
8294
|
-
var
|
|
8585
|
+
var NUMBERS2 = new Intl.NumberFormat("en-US");
|
|
8295
8586
|
function formatNumber(value) {
|
|
8296
8587
|
try {
|
|
8297
|
-
return
|
|
8588
|
+
return NUMBERS2.format(value);
|
|
8298
8589
|
} catch {
|
|
8299
8590
|
return String(value);
|
|
8300
8591
|
}
|
|
@@ -8987,7 +9278,7 @@ function parseTableViewSnapshot(raw) {
|
|
|
8987
9278
|
// src/data-table/MatrxUuidCell.tsx
|
|
8988
9279
|
import {
|
|
8989
9280
|
useEffect as useEffect13,
|
|
8990
|
-
useRef as
|
|
9281
|
+
useRef as useRef13,
|
|
8991
9282
|
useState as useState18
|
|
8992
9283
|
} from "react";
|
|
8993
9284
|
import { jsx as jsx34, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
@@ -9032,7 +9323,7 @@ function MatrxUuidCell({
|
|
|
9032
9323
|
const [copied, setCopied] = useState18(false);
|
|
9033
9324
|
const [opening, setOpening] = useState18(false);
|
|
9034
9325
|
const [peekOpen, setPeekOpen] = useState18(false);
|
|
9035
|
-
const timer =
|
|
9326
|
+
const timer = useRef13(null);
|
|
9036
9327
|
useEffect13(
|
|
9037
9328
|
() => () => {
|
|
9038
9329
|
if (timer.current) clearTimeout(timer.current);
|
|
@@ -9500,8 +9791,8 @@ function toNumber(value) {
|
|
|
9500
9791
|
if (typeof value === "string") {
|
|
9501
9792
|
const cleaned = value.replace(/[,\s$€£¥%]/g, "");
|
|
9502
9793
|
if (cleaned === "") return null;
|
|
9503
|
-
const
|
|
9504
|
-
return Number.isFinite(
|
|
9794
|
+
const n2 = Number(cleaned);
|
|
9795
|
+
return Number.isFinite(n2) ? n2 : null;
|
|
9505
9796
|
}
|
|
9506
9797
|
return null;
|
|
9507
9798
|
}
|
|
@@ -9539,14 +9830,14 @@ function toList(value) {
|
|
|
9539
9830
|
}
|
|
9540
9831
|
return null;
|
|
9541
9832
|
}
|
|
9542
|
-
function groupedNumber(
|
|
9833
|
+
function groupedNumber(n2, options) {
|
|
9543
9834
|
return new Intl.NumberFormat(void 0, {
|
|
9544
9835
|
useGrouping: options.useGrouping !== false,
|
|
9545
9836
|
...options.precision != null ? {
|
|
9546
9837
|
minimumFractionDigits: options.precision,
|
|
9547
9838
|
maximumFractionDigits: options.precision
|
|
9548
9839
|
} : { maximumFractionDigits: 10 }
|
|
9549
|
-
}).format(
|
|
9840
|
+
}).format(n2);
|
|
9550
9841
|
}
|
|
9551
9842
|
function affix(text, options) {
|
|
9552
9843
|
return `${options.prefix ?? ""}${text}${options.suffix ?? ""}`;
|
|
@@ -9680,8 +9971,8 @@ var DEFS = [
|
|
|
9680
9971
|
numericAlign: true,
|
|
9681
9972
|
optionKeys: ["useGrouping", "precision", "prefix", "suffix"],
|
|
9682
9973
|
format: (v, o) => {
|
|
9683
|
-
const
|
|
9684
|
-
return
|
|
9974
|
+
const n2 = toNumber(v);
|
|
9975
|
+
return n2 === null ? null : affix(groupedNumber(n2, o), o);
|
|
9685
9976
|
},
|
|
9686
9977
|
parse: (raw) => toNumber(raw)
|
|
9687
9978
|
},
|
|
@@ -9696,9 +9987,9 @@ var DEFS = [
|
|
|
9696
9987
|
numericAlign: true,
|
|
9697
9988
|
optionKeys: ["precision", "useGrouping", "prefix", "suffix"],
|
|
9698
9989
|
format: (v, o) => {
|
|
9699
|
-
const
|
|
9700
|
-
if (
|
|
9701
|
-
return affix(groupedNumber(
|
|
9990
|
+
const n2 = toNumber(v);
|
|
9991
|
+
if (n2 === null) return null;
|
|
9992
|
+
return affix(groupedNumber(n2, { ...o, precision: o.precision ?? 2 }), o);
|
|
9702
9993
|
},
|
|
9703
9994
|
parse: (raw) => toNumber(raw)
|
|
9704
9995
|
},
|
|
@@ -9713,8 +10004,8 @@ var DEFS = [
|
|
|
9713
10004
|
numericAlign: true,
|
|
9714
10005
|
optionKeys: ["currency", "precision"],
|
|
9715
10006
|
format: (v, o) => {
|
|
9716
|
-
const
|
|
9717
|
-
if (
|
|
10007
|
+
const n2 = toNumber(v);
|
|
10008
|
+
if (n2 === null) return null;
|
|
9718
10009
|
const currency = (o.currency || "USD").toUpperCase();
|
|
9719
10010
|
try {
|
|
9720
10011
|
return new Intl.NumberFormat(void 0, {
|
|
@@ -9724,9 +10015,9 @@ var DEFS = [
|
|
|
9724
10015
|
minimumFractionDigits: o.precision,
|
|
9725
10016
|
maximumFractionDigits: o.precision
|
|
9726
10017
|
} : {}
|
|
9727
|
-
}).format(
|
|
10018
|
+
}).format(n2);
|
|
9728
10019
|
} catch {
|
|
9729
|
-
return `${groupedNumber(
|
|
10020
|
+
return `${groupedNumber(n2, { precision: o.precision ?? 2 })} ${currency}`;
|
|
9730
10021
|
}
|
|
9731
10022
|
},
|
|
9732
10023
|
parse: (raw) => toNumber(raw)
|
|
@@ -9742,9 +10033,9 @@ var DEFS = [
|
|
|
9742
10033
|
numericAlign: true,
|
|
9743
10034
|
optionKeys: ["percentScale", "precision"],
|
|
9744
10035
|
format: (v, o) => {
|
|
9745
|
-
const
|
|
9746
|
-
if (
|
|
9747
|
-
const shown = o.percentScale === "fraction" ?
|
|
10036
|
+
const n2 = toNumber(v);
|
|
10037
|
+
if (n2 === null) return null;
|
|
10038
|
+
const shown = o.percentScale === "fraction" ? n2 * 100 : n2;
|
|
9748
10039
|
return `${groupedNumber(shown, o.precision === void 0 ? {} : { precision: o.precision })}%`;
|
|
9749
10040
|
},
|
|
9750
10041
|
parse: (raw) => toNumber(raw)
|
|
@@ -9760,9 +10051,9 @@ var DEFS = [
|
|
|
9760
10051
|
numericAlign: true,
|
|
9761
10052
|
optionKeys: ["durationUnit"],
|
|
9762
10053
|
format: (v, o) => {
|
|
9763
|
-
const
|
|
9764
|
-
if (
|
|
9765
|
-
return formatSignedDuration(
|
|
10054
|
+
const n2 = toNumber(v);
|
|
10055
|
+
if (n2 === null) return null;
|
|
10056
|
+
return formatSignedDuration(n2 * DURATION_TO_SECONDS[o.durationUnit ?? "seconds"]);
|
|
9766
10057
|
},
|
|
9767
10058
|
parse: (raw) => toNumber(raw)
|
|
9768
10059
|
},
|
|
@@ -9777,13 +10068,13 @@ var DEFS = [
|
|
|
9777
10068
|
numericAlign: true,
|
|
9778
10069
|
optionKeys: ["useGrouping", "prefix", "suffix"],
|
|
9779
10070
|
format: (v, o) => {
|
|
9780
|
-
const
|
|
9781
|
-
if (
|
|
9782
|
-
return affix(groupedNumber(Math.trunc(
|
|
10071
|
+
const n2 = toNumber(v);
|
|
10072
|
+
if (n2 === null) return null;
|
|
10073
|
+
return affix(groupedNumber(Math.trunc(n2), { ...o, precision: 0 }), o);
|
|
9783
10074
|
},
|
|
9784
10075
|
parse: (raw) => {
|
|
9785
|
-
const
|
|
9786
|
-
return
|
|
10076
|
+
const n2 = toNumber(raw);
|
|
10077
|
+
return n2 === null ? null : Math.trunc(n2);
|
|
9787
10078
|
}
|
|
9788
10079
|
},
|
|
9789
10080
|
{
|
|
@@ -9797,15 +10088,15 @@ var DEFS = [
|
|
|
9797
10088
|
rich: true,
|
|
9798
10089
|
optionKeys: ["ratingMax"],
|
|
9799
10090
|
format: (v, o) => {
|
|
9800
|
-
const
|
|
9801
|
-
if (
|
|
10091
|
+
const n2 = toNumber(v);
|
|
10092
|
+
if (n2 === null) return null;
|
|
9802
10093
|
const max = o.ratingMax ?? 5;
|
|
9803
|
-
if (
|
|
9804
|
-
return `${
|
|
10094
|
+
if (n2 < 0 || n2 > max) return null;
|
|
10095
|
+
return `${n2} / ${max}`;
|
|
9805
10096
|
},
|
|
9806
10097
|
parse: (raw) => {
|
|
9807
|
-
const
|
|
9808
|
-
return
|
|
10098
|
+
const n2 = toNumber(raw);
|
|
10099
|
+
return n2 === null ? null : Math.round(n2);
|
|
9809
10100
|
}
|
|
9810
10101
|
},
|
|
9811
10102
|
{
|
|
@@ -9818,12 +10109,12 @@ var DEFS = [
|
|
|
9818
10109
|
editor: "number",
|
|
9819
10110
|
numericAlign: true,
|
|
9820
10111
|
format: (v) => {
|
|
9821
|
-
const
|
|
9822
|
-
return
|
|
10112
|
+
const n2 = toNumber(v);
|
|
10113
|
+
return n2 === null ? null : formatFileSize(n2);
|
|
9823
10114
|
},
|
|
9824
10115
|
parse: (raw) => {
|
|
9825
|
-
const
|
|
9826
|
-
return
|
|
10116
|
+
const n2 = toNumber(raw);
|
|
10117
|
+
return n2 === null ? null : Math.trunc(n2);
|
|
9827
10118
|
}
|
|
9828
10119
|
},
|
|
9829
10120
|
// ── Choice ────────────────────────────────────────────────────────────────
|
|
@@ -10233,8 +10524,19 @@ function DirtySavePill({
|
|
|
10233
10524
|
}
|
|
10234
10525
|
|
|
10235
10526
|
// src/data-table/EditableTableCell.tsx
|
|
10236
|
-
import { useEffect as useEffect15, useRef as
|
|
10527
|
+
import { useEffect as useEffect15, useRef as useRef14, useState as useState20 } from "react";
|
|
10237
10528
|
import { jsx as jsx39, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
10529
|
+
function CellRefusal({ reason }) {
|
|
10530
|
+
return /* @__PURE__ */ jsx39(
|
|
10531
|
+
"p",
|
|
10532
|
+
{
|
|
10533
|
+
role: "alert",
|
|
10534
|
+
"data-matrx-cell-refusal": "true",
|
|
10535
|
+
className: "mt-1 text-[11px] leading-snug text-amber-700 dark:text-amber-400",
|
|
10536
|
+
children: reason
|
|
10537
|
+
}
|
|
10538
|
+
);
|
|
10539
|
+
}
|
|
10238
10540
|
function CellEditShell({
|
|
10239
10541
|
href,
|
|
10240
10542
|
display,
|
|
@@ -10281,12 +10583,17 @@ function EditableTableCell({
|
|
|
10281
10583
|
className,
|
|
10282
10584
|
href,
|
|
10283
10585
|
editTrigger = "click",
|
|
10284
|
-
editRequest
|
|
10586
|
+
editRequest,
|
|
10587
|
+
editSeed
|
|
10285
10588
|
}) {
|
|
10286
10589
|
const [open, setOpen] = useState20(false);
|
|
10590
|
+
const [refusal, setRefusal] = useState20(null);
|
|
10287
10591
|
useEffect15(() => {
|
|
10288
10592
|
if (editRequest !== void 0) setOpen(true);
|
|
10289
10593
|
}, [editRequest]);
|
|
10594
|
+
useEffect15(() => {
|
|
10595
|
+
if (!open) setRefusal(null);
|
|
10596
|
+
}, [open]);
|
|
10290
10597
|
const usePencil = Boolean(href) || editTrigger === "pencil";
|
|
10291
10598
|
if (editType === "string") {
|
|
10292
10599
|
return /* @__PURE__ */ jsx39(
|
|
@@ -10299,7 +10606,8 @@ function EditableTableCell({
|
|
|
10299
10606
|
...className === void 0 ? {} : { className },
|
|
10300
10607
|
...href === void 0 ? {} : { href },
|
|
10301
10608
|
usePencil,
|
|
10302
|
-
...editRequest === void 0 ? {} : { editRequest }
|
|
10609
|
+
...editRequest === void 0 ? {} : { editRequest },
|
|
10610
|
+
...editSeed === void 0 || editSeed === null ? {} : { editSeed }
|
|
10303
10611
|
}
|
|
10304
10612
|
);
|
|
10305
10613
|
}
|
|
@@ -10344,25 +10652,33 @@ function EditableTableCell({
|
|
|
10344
10652
|
) }) }),
|
|
10345
10653
|
/* @__PURE__ */ jsx39(TooltipContent, { children: "Edit value" })
|
|
10346
10654
|
] }),
|
|
10347
|
-
/* @__PURE__ */
|
|
10655
|
+
/* @__PURE__ */ jsxs29(
|
|
10348
10656
|
PopoverContent,
|
|
10349
10657
|
{
|
|
10350
10658
|
align: "start",
|
|
10351
10659
|
className: "w-56 p-2",
|
|
10352
10660
|
onClick: (e) => e.stopPropagation(),
|
|
10353
|
-
children:
|
|
10354
|
-
|
|
10355
|
-
|
|
10356
|
-
|
|
10357
|
-
|
|
10358
|
-
|
|
10359
|
-
|
|
10360
|
-
onCommit(next)
|
|
10361
|
-
|
|
10362
|
-
|
|
10363
|
-
|
|
10364
|
-
|
|
10365
|
-
|
|
10661
|
+
children: [
|
|
10662
|
+
/* @__PURE__ */ jsx39(
|
|
10663
|
+
TypedEditor,
|
|
10664
|
+
{
|
|
10665
|
+
editType,
|
|
10666
|
+
value,
|
|
10667
|
+
editOptions,
|
|
10668
|
+
onCommit: (next) => {
|
|
10669
|
+
const refused = onCommit(next);
|
|
10670
|
+
if (typeof refused === "string" && refused) {
|
|
10671
|
+
setRefusal(refused);
|
|
10672
|
+
return;
|
|
10673
|
+
}
|
|
10674
|
+
setRefusal(null);
|
|
10675
|
+
setOpen(false);
|
|
10676
|
+
},
|
|
10677
|
+
onCancel: () => setOpen(false)
|
|
10678
|
+
}
|
|
10679
|
+
),
|
|
10680
|
+
refusal ? /* @__PURE__ */ jsx39(CellRefusal, { reason: refusal }) : null
|
|
10681
|
+
]
|
|
10366
10682
|
}
|
|
10367
10683
|
)
|
|
10368
10684
|
] });
|
|
@@ -10375,17 +10691,31 @@ function InlineStringEditor({
|
|
|
10375
10691
|
className,
|
|
10376
10692
|
href,
|
|
10377
10693
|
usePencil,
|
|
10378
|
-
editRequest
|
|
10694
|
+
editRequest,
|
|
10695
|
+
editSeed
|
|
10379
10696
|
}) {
|
|
10380
10697
|
const [editing, setEditing] = useState20(false);
|
|
10381
10698
|
const [draft, setDraft] = useState20(value);
|
|
10382
|
-
const
|
|
10699
|
+
const [refusal, setRefusal] = useState20(null);
|
|
10700
|
+
const handledEditRequest = useRef14(void 0);
|
|
10701
|
+
const seedRef = useRef14(editSeed);
|
|
10702
|
+
seedRef.current = editSeed;
|
|
10383
10703
|
useEffect15(() => {
|
|
10384
10704
|
if (editRequest === void 0 || handledEditRequest.current === editRequest) return;
|
|
10385
10705
|
handledEditRequest.current = editRequest;
|
|
10386
|
-
setDraft(value);
|
|
10706
|
+
setDraft(seedRef.current ?? value);
|
|
10707
|
+
setRefusal(null);
|
|
10387
10708
|
setEditing(true);
|
|
10388
10709
|
}, [editRequest, value]);
|
|
10710
|
+
const commit = (next) => {
|
|
10711
|
+
const refused = onCommit(next);
|
|
10712
|
+
if (typeof refused === "string" && refused) {
|
|
10713
|
+
setRefusal(refused);
|
|
10714
|
+
return false;
|
|
10715
|
+
}
|
|
10716
|
+
setRefusal(null);
|
|
10717
|
+
return true;
|
|
10718
|
+
};
|
|
10389
10719
|
if (!editing) {
|
|
10390
10720
|
if (usePencil) {
|
|
10391
10721
|
return /* @__PURE__ */ jsx39(
|
|
@@ -10436,32 +10766,38 @@ function InlineStringEditor({
|
|
|
10436
10766
|
/* @__PURE__ */ jsx39(TooltipContent, { children: "Click to edit" })
|
|
10437
10767
|
] });
|
|
10438
10768
|
}
|
|
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
|
-
|
|
10769
|
+
return /* @__PURE__ */ jsxs29("span", { className: "block w-full", children: [
|
|
10770
|
+
/* @__PURE__ */ jsx39(
|
|
10771
|
+
Input,
|
|
10772
|
+
{
|
|
10773
|
+
autoFocus: true,
|
|
10774
|
+
value: draft,
|
|
10775
|
+
onClick: (e) => e.stopPropagation(),
|
|
10776
|
+
onChange: (e) => {
|
|
10777
|
+
setDraft(e.target.value);
|
|
10778
|
+
if (refusal) setRefusal(null);
|
|
10779
|
+
},
|
|
10780
|
+
onBlur: () => {
|
|
10781
|
+
if (commit(draft)) setEditing(false);
|
|
10782
|
+
},
|
|
10783
|
+
onKeyDown: (e) => {
|
|
10784
|
+
if (e.key === "Enter") {
|
|
10785
|
+
e.preventDefault();
|
|
10786
|
+
if (commit(draft)) setEditing(false);
|
|
10787
|
+
}
|
|
10788
|
+
if (e.key === "Escape") {
|
|
10789
|
+
e.preventDefault();
|
|
10790
|
+
setRefusal(null);
|
|
10791
|
+
setEditing(false);
|
|
10792
|
+
}
|
|
10793
|
+
},
|
|
10794
|
+
"aria-invalid": refusal ? true : void 0,
|
|
10795
|
+
className: cn("h-7 text-sm", refusal && "border-amber-500 focus-visible:ring-amber-500"),
|
|
10796
|
+
style: { fontSize: "16px" }
|
|
10797
|
+
}
|
|
10798
|
+
),
|
|
10799
|
+
refusal ? /* @__PURE__ */ jsx39(CellRefusal, { reason: refusal }) : null
|
|
10800
|
+
] });
|
|
10465
10801
|
}
|
|
10466
10802
|
function TypedEditor({
|
|
10467
10803
|
editType,
|
|
@@ -10646,8 +10982,8 @@ function NumberEditor({
|
|
|
10646
10982
|
style: { fontSize: "16px" },
|
|
10647
10983
|
onKeyDown: (e) => {
|
|
10648
10984
|
if (e.key === "Enter") {
|
|
10649
|
-
const
|
|
10650
|
-
if (Number.isFinite(
|
|
10985
|
+
const n2 = Number(draft);
|
|
10986
|
+
if (Number.isFinite(n2)) onCommit(n2);
|
|
10651
10987
|
}
|
|
10652
10988
|
if (e.key === "Escape") onCancel();
|
|
10653
10989
|
}
|
|
@@ -10674,8 +11010,8 @@ function NumberEditor({
|
|
|
10674
11010
|
className: "h-7",
|
|
10675
11011
|
"aria-label": "Apply value",
|
|
10676
11012
|
onClick: () => {
|
|
10677
|
-
const
|
|
10678
|
-
if (Number.isFinite(
|
|
11013
|
+
const n2 = Number(draft);
|
|
11014
|
+
if (Number.isFinite(n2)) onCommit(n2);
|
|
10679
11015
|
},
|
|
10680
11016
|
children: /* @__PURE__ */ jsx39(Check, { className: "h-3.5 w-3.5" })
|
|
10681
11017
|
}
|
|
@@ -11483,11 +11819,12 @@ function MatrxDataTableCore({
|
|
|
11483
11819
|
virtualize,
|
|
11484
11820
|
coverage,
|
|
11485
11821
|
spreadsheet,
|
|
11822
|
+
facets,
|
|
11486
11823
|
rowHeight: explicitRowHeight
|
|
11487
11824
|
}) {
|
|
11488
11825
|
const appendQuery = query?.mode === "controlled-append" ? query : null;
|
|
11489
11826
|
const appendQueryKey = appendQuery?.pagination.queryKey ?? null;
|
|
11490
|
-
const committedAppendQueryKey =
|
|
11827
|
+
const committedAppendQueryKey = useRef15(appendQueryKey);
|
|
11491
11828
|
const appendSourceChanged = appendQuery !== null && committedAppendQueryKey.current !== appendQueryKey;
|
|
11492
11829
|
const data = (appendQuery ? appendQuery.pagination.rows : suppliedData) ?? [];
|
|
11493
11830
|
const isLoading = appendQuery ? appendQuery.pagination.loading : suppliedLoading;
|
|
@@ -11502,7 +11839,7 @@ function MatrxDataTableCore({
|
|
|
11502
11839
|
const [savedViewError, setSavedViewError] = useState22(null);
|
|
11503
11840
|
const [toolbarActionError, setToolbarActionError] = useState22(null);
|
|
11504
11841
|
const [toolbarActionPending, setToolbarActionPending] = useState22({ refresh: false, add: false });
|
|
11505
|
-
const toolbarActionPendingRef =
|
|
11842
|
+
const toolbarActionPendingRef = useRef15({ refresh: false, add: false });
|
|
11506
11843
|
const CHECKBOX_TAP_AREA = "h-4 w-4 touch-manipulation";
|
|
11507
11844
|
const mobileCardsClass = mobileCardsBreakpoint === "lg" ? "lg:hidden" : "sm:hidden";
|
|
11508
11845
|
const tableWithCardsClass = mobileCardsBreakpoint === "lg" ? "max-lg:hidden" : "max-sm:hidden";
|
|
@@ -11640,9 +11977,9 @@ function MatrxDataTableCore({
|
|
|
11640
11977
|
const [windowRowSnapshot, setWindowRowSnapshot] = useState22(null);
|
|
11641
11978
|
const editScopeKey = appendQueryKey === null ? "\0local" : `append:${appendQueryKey}`;
|
|
11642
11979
|
const [editsByScope, setEditsByScope] = useState22({});
|
|
11643
|
-
const editRevisionRef =
|
|
11980
|
+
const editRevisionRef = useRef15({});
|
|
11644
11981
|
const [savingByScope, setSavingByScope] = useState22({});
|
|
11645
|
-
const savingScopesRef =
|
|
11982
|
+
const savingScopesRef = useRef15(/* @__PURE__ */ new Set());
|
|
11646
11983
|
const [editRequest, setEditRequest] = useState22(null);
|
|
11647
11984
|
const [confirmForeignDraftDiscard, setConfirmForeignDraftDiscard] = useState22(false);
|
|
11648
11985
|
const edits = editsByScope[editScopeKey]?.values ?? {};
|
|
@@ -11729,13 +12066,13 @@ function MatrxDataTableCore({
|
|
|
11729
12066
|
onWindowRowIdChange,
|
|
11730
12067
|
selectionConfig
|
|
11731
12068
|
]);
|
|
11732
|
-
const scrollRef =
|
|
11733
|
-
const tableRef =
|
|
11734
|
-
const tableHeaderRef =
|
|
11735
|
-
const cardsScrollRef =
|
|
12069
|
+
const scrollRef = useRef15(null);
|
|
12070
|
+
const tableRef = useRef15(null);
|
|
12071
|
+
const tableHeaderRef = useRef15(null);
|
|
12072
|
+
const cardsScrollRef = useRef15(null);
|
|
11736
12073
|
const [documentStickyHeader, setDocumentStickyHeader] = useState22(false);
|
|
11737
|
-
const documentStickyHeaderRef =
|
|
11738
|
-
const previousAppendKeyForScrollReset =
|
|
12074
|
+
const documentStickyHeaderRef = useRef15(false);
|
|
12075
|
+
const previousAppendKeyForScrollReset = useRef15(appendQueryKey);
|
|
11739
12076
|
useLayoutEffect2(() => {
|
|
11740
12077
|
const previous = previousAppendKeyForScrollReset.current;
|
|
11741
12078
|
previousAppendKeyForScrollReset.current = appendQueryKey;
|
|
@@ -11761,7 +12098,7 @@ function MatrxDataTableCore({
|
|
|
11761
12098
|
...appendScrollPolicy?.mode === "scroll" && appendScrollPolicy.thresholdPx !== void 0 ? { thresholdPx: appendScrollPolicy.thresholdPx } : {},
|
|
11762
12099
|
...appendScrollPolicy?.mode === "scroll" && appendScrollPolicy.intentTimeoutMs !== void 0 ? { intentTimeoutMs: appendScrollPolicy.intentTimeoutMs } : {}
|
|
11763
12100
|
});
|
|
11764
|
-
const rootRef =
|
|
12101
|
+
const rootRef = useRef15(null);
|
|
11765
12102
|
useClippedContentGuard(rootRef, {
|
|
11766
12103
|
label: typeof copy === "object" && copy.listLabel ? `Table: ${copy.listLabel}` : "MatrxDataTable"
|
|
11767
12104
|
});
|
|
@@ -11863,11 +12200,11 @@ function MatrxDataTableCore({
|
|
|
11863
12200
|
() => normalizeColumnWidthsForColumns(columnState?.widths, columns)
|
|
11864
12201
|
);
|
|
11865
12202
|
const [fixedTableGeometry, setFixedTableGeometry] = useState22(null);
|
|
11866
|
-
const knownColumnIds =
|
|
11867
|
-
const draggedColumnId =
|
|
11868
|
-
const columnDragActive =
|
|
11869
|
-
const columnDragRaf =
|
|
11870
|
-
const columnDragScrollDirection =
|
|
12203
|
+
const knownColumnIds = useRef15(new Set(columns.map(columnId)));
|
|
12204
|
+
const draggedColumnId = useRef15(null);
|
|
12205
|
+
const columnDragActive = useRef15(false);
|
|
12206
|
+
const columnDragRaf = useRef15(null);
|
|
12207
|
+
const columnDragScrollDirection = useRef15(0);
|
|
11871
12208
|
const [columnDragPreview, setColumnDragPreview] = useState22(null);
|
|
11872
12209
|
const stopColumnDragScroll = useCallback8(() => {
|
|
11873
12210
|
if (columnDragRaf.current !== null) cancelAnimationFrame(columnDragRaf.current);
|
|
@@ -11922,7 +12259,7 @@ function MatrxDataTableCore({
|
|
|
11922
12259
|
() => normalizeColumnWidthsForColumns(columnState?.widths ?? columnWidths, columns),
|
|
11923
12260
|
[columns, columnState?.widths, columnWidths]
|
|
11924
12261
|
);
|
|
11925
|
-
const resizeGestureSnapshotRef =
|
|
12262
|
+
const resizeGestureSnapshotRef = useRef15(null);
|
|
11926
12263
|
const measureVisibleColumnWidths = useCallback8(() => {
|
|
11927
12264
|
const measured = {};
|
|
11928
12265
|
const headers = tableRef.current ? Array.from(tableRef.current.querySelectorAll(
|
|
@@ -12228,7 +12565,7 @@ function MatrxDataTableCore({
|
|
|
12228
12565
|
intelligentSearchEnabled,
|
|
12229
12566
|
searchScope
|
|
12230
12567
|
]);
|
|
12231
|
-
const lastNotifiedViewRows =
|
|
12568
|
+
const lastNotifiedViewRows = useRef15(null);
|
|
12232
12569
|
useEffect16(() => {
|
|
12233
12570
|
if (!onViewChange) {
|
|
12234
12571
|
lastNotifiedViewRows.current = null;
|
|
@@ -12348,7 +12685,7 @@ function MatrxDataTableCore({
|
|
|
12348
12685
|
const columnVirtualizeActive = virtualizeConfig !== null && virtualizeConfig.enabled !== false && virtualizeConfig.columns === true && visibleColumns.length - frozenRunLength > 30 && !hierarchy && mobileCards === void 0;
|
|
12349
12686
|
const [rowWindow, setRowWindow] = useState22(null);
|
|
12350
12687
|
const [columnWindow, setColumnWindow] = useState22(null);
|
|
12351
|
-
const windowInputs =
|
|
12688
|
+
const windowInputs = useRef15({
|
|
12352
12689
|
virtualizeActive: false,
|
|
12353
12690
|
bodyEntryCount: 0,
|
|
12354
12691
|
virtualRowHeight: 40,
|
|
@@ -12498,7 +12835,7 @@ function MatrxDataTableCore({
|
|
|
12498
12835
|
windowed.push({ kind: "spacer", height: effectiveRowWindow.padEnd, place: "end" });
|
|
12499
12836
|
return windowed;
|
|
12500
12837
|
}, [groupedRenderRows, collapsedGroups, paginated, effectiveRowWindow]);
|
|
12501
|
-
const getRowIdRef =
|
|
12838
|
+
const getRowIdRef = useRef15(getRowId);
|
|
12502
12839
|
getRowIdRef.current = getRowId;
|
|
12503
12840
|
const spreadsheetRowIds = useMemo8(
|
|
12504
12841
|
() => paginated.map((row) => getRowIdRef.current(row)),
|
|
@@ -12540,9 +12877,92 @@ function MatrxDataTableCore({
|
|
|
12540
12877
|
...spreadsheet.undoDepth === void 0 ? {} : { undoDepth: spreadsheet.undoDepth },
|
|
12541
12878
|
...spreadsheet.fillHandle === void 0 ? {} : { fillHandle: spreadsheet.fillHandle },
|
|
12542
12879
|
...spreadsheet.paste === void 0 ? {} : { paste: spreadsheet.paste },
|
|
12543
|
-
notify: spreadsheet.notify ?? ((message) => toast.success(message))
|
|
12880
|
+
notify: spreadsheet.notify ?? ((message) => toast.success(message)),
|
|
12881
|
+
onEditRequest: (address, seed) => requestCellEditRef.current(address, seed),
|
|
12882
|
+
...spreadsheet.validateCell ? { validateCell: spreadsheet.validateCell } : {}
|
|
12544
12883
|
} : null
|
|
12545
12884
|
);
|
|
12885
|
+
const sheetRef = useRef15(sheet);
|
|
12886
|
+
sheetRef.current = sheet;
|
|
12887
|
+
const searchValueRef = useRef15(searchValue);
|
|
12888
|
+
searchValueRef.current = searchValue;
|
|
12889
|
+
const facetsEnabled = Boolean(facets && facets.enabled !== false);
|
|
12890
|
+
const [facetState, setFacetState] = useState22({});
|
|
12891
|
+
const facetReadCell = useCallback8(
|
|
12892
|
+
(row, colId) => {
|
|
12893
|
+
if (facets?.readCell) return facets.readCell(row, colId);
|
|
12894
|
+
const col = visibleColumns.find((candidate) => columnId(candidate) === colId);
|
|
12895
|
+
return col ? getFilterValue(row, col) : void 0;
|
|
12896
|
+
},
|
|
12897
|
+
[facets, visibleColumns]
|
|
12898
|
+
);
|
|
12899
|
+
const facetInputsRef = useRef15({ data, facets, facetReadCell });
|
|
12900
|
+
facetInputsRef.current = { data, facets, facetReadCell };
|
|
12901
|
+
const facetRequestRef = useRef15(/* @__PURE__ */ new Map());
|
|
12902
|
+
const requestFacets = useCallback8((colId) => {
|
|
12903
|
+
const { data: rows, facets: config, facetReadCell: readCell } = facetInputsRef.current;
|
|
12904
|
+
if (!config || config.enabled === false) return;
|
|
12905
|
+
const complete = localFacetsAreComplete(rows.length, config.totalRows);
|
|
12906
|
+
const limit = config.limit;
|
|
12907
|
+
if (complete || !config.source) {
|
|
12908
|
+
setFacetState((current) => ({
|
|
12909
|
+
...current,
|
|
12910
|
+
[colId]: {
|
|
12911
|
+
loading: false,
|
|
12912
|
+
data: computeColumnFacets({
|
|
12913
|
+
columnId: colId,
|
|
12914
|
+
rows,
|
|
12915
|
+
readValue: readCell,
|
|
12916
|
+
...limit === void 0 ? {} : { limit },
|
|
12917
|
+
complete
|
|
12918
|
+
})
|
|
12919
|
+
}
|
|
12920
|
+
}));
|
|
12921
|
+
return;
|
|
12922
|
+
}
|
|
12923
|
+
const ticket = (facetRequestRef.current.get(colId) ?? 0) + 1;
|
|
12924
|
+
facetRequestRef.current.set(colId, ticket);
|
|
12925
|
+
setFacetState((current) => ({
|
|
12926
|
+
...current,
|
|
12927
|
+
[colId]: { loading: true, data: current[colId]?.data ?? null }
|
|
12928
|
+
}));
|
|
12929
|
+
void Promise.resolve().then(
|
|
12930
|
+
() => config.source?.({ columnId: colId, search: searchValueRef.current, limit: limit ?? 200 })
|
|
12931
|
+
).then((answer) => {
|
|
12932
|
+
if (facetRequestRef.current.get(colId) !== ticket) return;
|
|
12933
|
+
if (!answer) {
|
|
12934
|
+
setFacetState((current) => ({
|
|
12935
|
+
...current,
|
|
12936
|
+
[colId]: {
|
|
12937
|
+
loading: false,
|
|
12938
|
+
data: computeColumnFacets({
|
|
12939
|
+
columnId: colId,
|
|
12940
|
+
rows: facetInputsRef.current.data,
|
|
12941
|
+
readValue: facetInputsRef.current.facetReadCell,
|
|
12942
|
+
...limit === void 0 ? {} : { limit },
|
|
12943
|
+
complete: false
|
|
12944
|
+
})
|
|
12945
|
+
}
|
|
12946
|
+
}));
|
|
12947
|
+
return;
|
|
12948
|
+
}
|
|
12949
|
+
setFacetState((current) => ({
|
|
12950
|
+
...current,
|
|
12951
|
+
[colId]: { loading: false, data: { ...answer, answeredBy: "source", complete: true } }
|
|
12952
|
+
}));
|
|
12953
|
+
}).catch((error) => {
|
|
12954
|
+
if (facetRequestRef.current.get(colId) !== ticket) return;
|
|
12955
|
+
setFacetState((current) => ({
|
|
12956
|
+
...current,
|
|
12957
|
+
[colId]: { loading: false, data: null, error: describeFacetFailure(error) }
|
|
12958
|
+
}));
|
|
12959
|
+
});
|
|
12960
|
+
}, []);
|
|
12961
|
+
useEffect16(() => {
|
|
12962
|
+
if (!facetsEnabled) return;
|
|
12963
|
+
setFacetState({});
|
|
12964
|
+
facetRequestRef.current = /* @__PURE__ */ new Map();
|
|
12965
|
+
}, [facetsEnabled, data, searchValue]);
|
|
12546
12966
|
useEffect16(() => {
|
|
12547
12967
|
if (!controlledQuery || controlledQuery.state.page === safePage) return;
|
|
12548
12968
|
emitControlledQueryChange({ page: safePage });
|
|
@@ -12587,11 +13007,11 @@ function MatrxDataTableCore({
|
|
|
12587
13007
|
});
|
|
12588
13008
|
const hasActiveFilters = activeFilterCount > 0 || Boolean(searchValue.trim()) || intelligentSearchEnabled && searchScope !== "all" || Boolean(anyOfValue.trim()) || completeLayeredFilterRules(layeredFilters).length > 0 || facetActive;
|
|
12589
13009
|
const changeCount = useMemo8(() => {
|
|
12590
|
-
let
|
|
13010
|
+
let n2 = 0;
|
|
12591
13011
|
for (const fields of Object.values(edits)) {
|
|
12592
|
-
|
|
13012
|
+
n2 += Object.keys(fields).length;
|
|
12593
13013
|
}
|
|
12594
|
-
return
|
|
13014
|
+
return n2;
|
|
12595
13015
|
}, [edits]);
|
|
12596
13016
|
const showSearch = toolbar?.search !== false;
|
|
12597
13017
|
const openDetail = (row) => {
|
|
@@ -12670,6 +13090,23 @@ function MatrxDataTableCore({
|
|
|
12670
13090
|
icon: void 0
|
|
12671
13091
|
} : emptyState;
|
|
12672
13092
|
const commitCell = (rowId, field, next) => {
|
|
13093
|
+
if (edit?.validate) {
|
|
13094
|
+
const row = data.find((candidate) => getRowId(candidate) === rowId);
|
|
13095
|
+
if (row) {
|
|
13096
|
+
let refusal;
|
|
13097
|
+
try {
|
|
13098
|
+
refusal = edit.validate({
|
|
13099
|
+
row: applyRowEdits(row, edits[rowId]),
|
|
13100
|
+
rowId,
|
|
13101
|
+
columnId: field,
|
|
13102
|
+
value: next
|
|
13103
|
+
});
|
|
13104
|
+
} catch {
|
|
13105
|
+
refusal = void 0;
|
|
13106
|
+
}
|
|
13107
|
+
if (refusal) return refusal;
|
|
13108
|
+
}
|
|
13109
|
+
}
|
|
12673
13110
|
const scope = editScopeKey;
|
|
12674
13111
|
const nextEdits = { [rowId]: { [field]: next } };
|
|
12675
13112
|
const revision = setCellEdit(rowId, field, next);
|
|
@@ -12714,9 +13151,29 @@ function MatrxDataTableCore({
|
|
|
12714
13151
|
setEditRequest((current) => ({
|
|
12715
13152
|
rowId: getRowId(row),
|
|
12716
13153
|
field,
|
|
12717
|
-
nonce: (current?.nonce ?? 0) + 1
|
|
13154
|
+
nonce: (current?.nonce ?? 0) + 1,
|
|
13155
|
+
seed: null
|
|
12718
13156
|
}));
|
|
12719
13157
|
};
|
|
13158
|
+
const requestCellEdit = (address, seed) => {
|
|
13159
|
+
if (!editEnabled) return false;
|
|
13160
|
+
const row = data.find((candidate) => getRowId(candidate) === address.rowId);
|
|
13161
|
+
if (!row) return false;
|
|
13162
|
+
const column = visibleColumns.find(
|
|
13163
|
+
(candidate) => columnId(candidate) === address.fieldName
|
|
13164
|
+
);
|
|
13165
|
+
if (!column?.editable || !(column.editableIf?.(row) ?? true)) return false;
|
|
13166
|
+
const field = column.accessorKey ? String(column.accessorKey) : columnId(column);
|
|
13167
|
+
setEditRequest((current) => ({
|
|
13168
|
+
rowId: address.rowId,
|
|
13169
|
+
field,
|
|
13170
|
+
nonce: (current?.nonce ?? 0) + 1,
|
|
13171
|
+
seed
|
|
13172
|
+
}));
|
|
13173
|
+
return true;
|
|
13174
|
+
};
|
|
13175
|
+
const requestCellEditRef = useRef15(requestCellEdit);
|
|
13176
|
+
requestCellEditRef.current = requestCellEdit;
|
|
12720
13177
|
const buildRecordControls = (row) => {
|
|
12721
13178
|
const rowId = getRowId(row);
|
|
12722
13179
|
const pending = edits[rowId];
|
|
@@ -12957,17 +13414,78 @@ function MatrxDataTableCore({
|
|
|
12957
13414
|
setEdits({});
|
|
12958
13415
|
edit?.onCancel?.();
|
|
12959
13416
|
};
|
|
12960
|
-
|
|
12961
|
-
|
|
12962
|
-
return host.rowContextRegistry.register(tableContextMenuInstanceId, (rowId) => {
|
|
13417
|
+
const resolveMenuLevel = (target) => {
|
|
13418
|
+
const rowFor = (rowId) => {
|
|
12963
13419
|
const row = data.find((candidate) => getRowId(candidate) === rowId);
|
|
12964
13420
|
if (!row) return null;
|
|
12965
|
-
|
|
12966
|
-
|
|
12967
|
-
|
|
12968
|
-
|
|
12969
|
-
|
|
12970
|
-
|
|
13421
|
+
return applyRowEdits(row, edits[rowId]);
|
|
13422
|
+
};
|
|
13423
|
+
const columnFor = (id) => visibleColumns.find((col) => columnId(col) === id);
|
|
13424
|
+
const labelFor = (col, id) => col?.label ?? (typeof col?.header === "string" ? col.header : id);
|
|
13425
|
+
const fromHost = (payload) => host.createDefaultMenuContext?.(payload) ?? null;
|
|
13426
|
+
switch (target.level) {
|
|
13427
|
+
case "row": {
|
|
13428
|
+
if (!target.rowId) return null;
|
|
13429
|
+
const displayRow = rowFor(target.rowId);
|
|
13430
|
+
if (!displayRow) return null;
|
|
13431
|
+
const controls = buildRecordControls(displayRow);
|
|
13432
|
+
return contextMenu?.resolveRowContext?.(displayRow, controls) ?? fromHost({ level: "row", row: displayRow, rowId: target.rowId, controls });
|
|
13433
|
+
}
|
|
13434
|
+
case "cell": {
|
|
13435
|
+
if (!target.rowId || !target.columnId) return null;
|
|
13436
|
+
const displayRow = rowFor(target.rowId);
|
|
13437
|
+
const col = columnFor(target.columnId);
|
|
13438
|
+
if (!displayRow || !col) return null;
|
|
13439
|
+
const controls = buildRecordControls(displayRow);
|
|
13440
|
+
const value = spreadsheet?.readCell ? spreadsheet.readCell(displayRow, target.columnId) : getCellValue(displayRow, col);
|
|
13441
|
+
const args = {
|
|
13442
|
+
row: displayRow,
|
|
13443
|
+
rowId: target.rowId,
|
|
13444
|
+
columnId: target.columnId,
|
|
13445
|
+
columnLabel: labelFor(col, target.columnId),
|
|
13446
|
+
value,
|
|
13447
|
+
text: stringifyCellValue(value),
|
|
13448
|
+
controls
|
|
13449
|
+
};
|
|
13450
|
+
return contextMenu?.resolveCellContext?.(args) ?? fromHost({ level: "cell", ...args });
|
|
13451
|
+
}
|
|
13452
|
+
case "column": {
|
|
13453
|
+
if (!target.columnId) return null;
|
|
13454
|
+
const col = columnFor(target.columnId);
|
|
13455
|
+
if (!col) return null;
|
|
13456
|
+
const args = {
|
|
13457
|
+
columnId: target.columnId,
|
|
13458
|
+
columnLabel: labelFor(col, target.columnId),
|
|
13459
|
+
values: paginated.map(
|
|
13460
|
+
(row) => getCellValue(applyRowEdits(row, edits[getRowId(row)]), col)
|
|
13461
|
+
)
|
|
13462
|
+
};
|
|
13463
|
+
return contextMenu?.resolveColumnContext?.(args) ?? fromHost({ level: "column", ...args });
|
|
13464
|
+
}
|
|
13465
|
+
case "selection": {
|
|
13466
|
+
const addresses = sheetRef.current.selectionAddresses();
|
|
13467
|
+
const cellCount = addresses.rowIds.length * addresses.columnIds.length;
|
|
13468
|
+
if (cellCount <= 1) {
|
|
13469
|
+
return resolveMenuLevel({ ...target, level: "cell" });
|
|
13470
|
+
}
|
|
13471
|
+
const args = { ...addresses, tsv: sheetRef.current.selectionTsv(), cellCount };
|
|
13472
|
+
return contextMenu?.resolveSelectionContext?.(args) ?? fromHost({ level: "selection", ...args });
|
|
13473
|
+
}
|
|
13474
|
+
case "table": {
|
|
13475
|
+
const args = { rowCount: data.length, columnIds: visibleColumns.map((col) => columnId(col)) };
|
|
13476
|
+
return contextMenu?.resolveTableContext?.(args) ?? fromHost({ level: "table", ...args });
|
|
13477
|
+
}
|
|
13478
|
+
}
|
|
13479
|
+
};
|
|
13480
|
+
const resolveMenuLevelRef = useRef15(resolveMenuLevel);
|
|
13481
|
+
resolveMenuLevelRef.current = resolveMenuLevel;
|
|
13482
|
+
useEffect16(() => {
|
|
13483
|
+
if (!host.rowContextRegistry) return;
|
|
13484
|
+
return host.rowContextRegistry.register(
|
|
13485
|
+
tableContextMenuInstanceId,
|
|
13486
|
+
(target) => resolveMenuLevelRef.current(target)
|
|
13487
|
+
);
|
|
13488
|
+
}, [host.rowContextRegistry, tableContextMenuInstanceId]);
|
|
12971
13489
|
const showActionsCol = windowEnabled || Boolean(rowActions) || showInlineRowCopy;
|
|
12972
13490
|
const selectedIdSet = useMemo8(
|
|
12973
13491
|
() => new Set(selection?.selectedIds ?? []),
|
|
@@ -12985,7 +13503,7 @@ function MatrxDataTableCore({
|
|
|
12985
13503
|
() => data.filter((row) => selectedIdSet.has(getRowId(row))),
|
|
12986
13504
|
[data, selectedIdSet, getRowId]
|
|
12987
13505
|
);
|
|
12988
|
-
const lastToggledIndex =
|
|
13506
|
+
const lastToggledIndex = useRef15(null);
|
|
12989
13507
|
const setSelectedIds = (next) => selection?.onSelectedIdsChange([...next]);
|
|
12990
13508
|
const toggleRowSelected = (index, shiftKey) => {
|
|
12991
13509
|
if (!selection) return;
|
|
@@ -13049,8 +13567,19 @@ function MatrxDataTableCore({
|
|
|
13049
13567
|
dirty: Boolean(rowEdits && field in rowEdits),
|
|
13050
13568
|
onCommit: (next) => commitCell(id, field, next),
|
|
13051
13569
|
...href === void 0 ? {} : { href },
|
|
13052
|
-
...
|
|
13053
|
-
|
|
13570
|
+
...spreadsheetEnabled ? {
|
|
13571
|
+
// 🚨 THE CLICK LAW, enforced where the two paths meet. In a grid
|
|
13572
|
+
// with spreadsheet gestures a single click SELECTS a cell — it
|
|
13573
|
+
// may never drop a person into a free-text buffer, because the
|
|
13574
|
+
// same click is how they start a range, and an editor that opens
|
|
13575
|
+
// under the pointer eats the drag and the next keystroke. So the
|
|
13576
|
+
// editor opens the way it does in Excel: Enter, F2, the hover
|
|
13577
|
+
// pencil, or simply typing. An explicit `editTrigger: "click"`
|
|
13578
|
+
// does not override this; the law is the table's, not the
|
|
13579
|
+
// column's.
|
|
13580
|
+
editTrigger: "pencil"
|
|
13581
|
+
} : col.editTrigger === void 0 ? {} : { editTrigger: col.editTrigger },
|
|
13582
|
+
...editRequest?.rowId === id && editRequest.field === field ? { editRequest: editRequest.nonce, editSeed: editRequest.seed } : {}
|
|
13054
13583
|
}
|
|
13055
13584
|
);
|
|
13056
13585
|
}
|
|
@@ -13808,6 +14337,7 @@ function MatrxDataTableCore({
|
|
|
13808
14337
|
"th",
|
|
13809
14338
|
{
|
|
13810
14339
|
"data-matrx-table-column-id": id,
|
|
14340
|
+
"data-matrx-header-column-id": id,
|
|
13811
14341
|
"data-matrx-column-drag-shadow": isColumnDragShadow ? "true" : void 0,
|
|
13812
14342
|
"aria-sort": isSorted ? sort?.direction === "asc" ? "ascending" : "descending" : void 0,
|
|
13813
14343
|
className: cn(
|
|
@@ -13844,6 +14374,12 @@ function MatrxDataTableCore({
|
|
|
13844
14374
|
{
|
|
13845
14375
|
label: col.header,
|
|
13846
14376
|
labelText: headerLabel,
|
|
14377
|
+
...facetsEnabled ? {
|
|
14378
|
+
facets: facetState[id]?.data ?? null,
|
|
14379
|
+
facetsLoading: facetState[id]?.loading ?? false,
|
|
14380
|
+
...facetState[id]?.error === void 0 ? {} : { facetsError: facetState[id]?.error },
|
|
14381
|
+
onFilterOpen: () => requestFacets(id)
|
|
14382
|
+
} : {},
|
|
13847
14383
|
sortable: col.sortable !== false,
|
|
13848
14384
|
isSorted: Boolean(isSorted),
|
|
13849
14385
|
sortDirection: sort?.direction ?? defaultSortDirection,
|
|
@@ -14518,8 +15054,8 @@ function MatrxDataTableCore({
|
|
|
14518
15054
|
itemsPerPage: pageSize === 0 && allRowsAreLoaded ? 0 : effectivePageSize,
|
|
14519
15055
|
currentPage: safePage,
|
|
14520
15056
|
onPageChange: setPage,
|
|
14521
|
-
onItemsPerPageChange: (
|
|
14522
|
-
setPageSize(
|
|
15057
|
+
onItemsPerPageChange: (n2) => {
|
|
15058
|
+
setPageSize(n2);
|
|
14523
15059
|
if (!controlledQuery) setPage(1);
|
|
14524
15060
|
},
|
|
14525
15061
|
pageSizeOptions: pageSizeOptions.filter((size) => size > 0),
|