@ai-matrx/design-system 0.18.6 → 0.18.8

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.
@@ -6,9 +6,6 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __esm = (fn, res) => function __init() {
10
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
- };
12
9
  var __export = (target, all) => {
13
10
  for (var name in all)
14
11
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -31,406 +28,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
28
  ));
32
29
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
30
 
34
- // src/data-table/layered-filters.ts
35
- function operatorsForLayeredField(field) {
36
- if (field.operators) return field.operators;
37
- if (field.kind === "number") return NUMBER_OPERATORS;
38
- if (field.kind === "select") return SELECT_OPERATORS;
39
- return TEXT_OPERATORS;
40
- }
41
- function layeredFilterNeedsValue(operator) {
42
- return operator !== "is_empty" && operator !== "is_not_empty";
43
- }
44
- function isCompleteLayeredFilterRule(rule) {
45
- if (!layeredFilterNeedsValue(rule.operator)) return true;
46
- if (rule.value.trim() === "") return false;
47
- return rule.operator !== "between" || Boolean(rule.valueTo?.trim());
48
- }
49
- function completeLayeredFilterRules(rules) {
50
- return (rules ?? []).filter(isCompleteLayeredFilterRule);
51
- }
52
- function isLayeredFilterOperator(value) {
53
- return LAYERED_FILTER_OPERATORS.some((operator) => operator === value);
54
- }
55
- function normalizedText(value) {
56
- if (value === null || value === void 0) return "";
57
- return String(value).trim().toLocaleLowerCase();
58
- }
59
- function words(value) {
60
- return value.split(/[^\p{L}\p{N}]+/u).filter(Boolean);
61
- }
62
- function layeredFilterMatchesValue(value, rule) {
63
- const actual = normalizedText(value);
64
- const expected = rule.value.trim().toLocaleLowerCase();
65
- const expectedTo = rule.valueTo?.trim().toLocaleLowerCase() ?? "";
66
- switch (rule.operator) {
67
- case "contains":
68
- return actual.includes(expected);
69
- case "not_contains":
70
- return !actual.includes(expected);
71
- case "equals":
72
- return actual === expected;
73
- case "not_equals":
74
- return actual !== expected;
75
- case "starts_with":
76
- return actual.startsWith(expected);
77
- case "ends_with":
78
- return actual.endsWith(expected);
79
- case "word":
80
- return words(actual).includes(expected);
81
- case "not_word":
82
- return !words(actual).includes(expected);
83
- case "is_empty":
84
- return actual === "";
85
- case "is_not_empty":
86
- return actual !== "";
87
- case "greater_than":
88
- return Number(actual) > Number(expected);
89
- case "greater_or_equal":
90
- return Number(actual) >= Number(expected);
91
- case "less_than":
92
- return Number(actual) < Number(expected);
93
- case "less_or_equal":
94
- return Number(actual) <= Number(expected);
95
- case "between": {
96
- const numeric = Number(actual);
97
- return numeric >= Number(expected) && numeric <= Number(expectedTo);
98
- }
99
- }
100
- }
101
- function layeredFilterRuleSummary(rule, fields) {
102
- const field = fields.find((candidate) => candidate.id === rule.field);
103
- const fieldLabel = field?.label ?? rule.field;
104
- const operator = LAYERED_FILTER_OPERATOR_LABELS[rule.operator];
105
- if (!layeredFilterNeedsValue(rule.operator))
106
- return `${fieldLabel} ${operator}`;
107
- const selectedLabel = field?.kind === "select" ? field.options.find((option) => option.value === rule.value)?.label : void 0;
108
- const value = selectedLabel ?? rule.value;
109
- return rule.operator === "between" ? `${fieldLabel} ${operator} ${value} and ${rule.valueTo ?? ""}` : `${fieldLabel} ${operator} ${value}`;
110
- }
111
- var import_zod, LAYERED_FILTER_OPERATORS, layeredFilterRuleSchema, layeredFilterRulesSchema, TEXT_OPERATORS, NUMBER_OPERATORS, SELECT_OPERATORS, LAYERED_FILTER_OPERATOR_LABELS;
112
- var init_layered_filters = __esm({
113
- "src/data-table/layered-filters.ts"() {
114
- "use strict";
115
- import_zod = require("zod");
116
- LAYERED_FILTER_OPERATORS = [
117
- "contains",
118
- "not_contains",
119
- "equals",
120
- "not_equals",
121
- "starts_with",
122
- "ends_with",
123
- "word",
124
- "not_word",
125
- "is_empty",
126
- "is_not_empty",
127
- "greater_than",
128
- "greater_or_equal",
129
- "less_than",
130
- "less_or_equal",
131
- "between"
132
- ];
133
- layeredFilterRuleSchema = import_zod.z.object({
134
- id: import_zod.z.string().min(1),
135
- field: import_zod.z.string().min(1),
136
- operator: import_zod.z.enum(LAYERED_FILTER_OPERATORS),
137
- value: import_zod.z.string(),
138
- valueTo: import_zod.z.string().optional()
139
- });
140
- layeredFilterRulesSchema = import_zod.z.array(layeredFilterRuleSchema).max(20);
141
- TEXT_OPERATORS = [
142
- "contains",
143
- "not_contains",
144
- "equals",
145
- "not_equals",
146
- "starts_with",
147
- "ends_with",
148
- "word",
149
- "not_word",
150
- "is_empty",
151
- "is_not_empty"
152
- ];
153
- NUMBER_OPERATORS = [
154
- "equals",
155
- "not_equals",
156
- "greater_than",
157
- "greater_or_equal",
158
- "less_than",
159
- "less_or_equal",
160
- "between",
161
- "is_empty",
162
- "is_not_empty"
163
- ];
164
- SELECT_OPERATORS = [
165
- "equals",
166
- "not_equals",
167
- "is_empty",
168
- "is_not_empty"
169
- ];
170
- LAYERED_FILTER_OPERATOR_LABELS = {
171
- contains: "contains",
172
- not_contains: "doesn't contain",
173
- equals: "is",
174
- not_equals: "is not",
175
- starts_with: "starts with",
176
- ends_with: "ends with",
177
- word: "has the word",
178
- not_word: "doesn't have the word",
179
- is_empty: "is empty",
180
- is_not_empty: "is not empty",
181
- greater_than: "is greater than",
182
- greater_or_equal: "is at least",
183
- less_than: "is less than",
184
- less_or_equal: "is at most",
185
- between: "is between"
186
- };
187
- }
188
- });
189
-
190
- // src/data-table/filter-engine.ts
191
- function columnId(col) {
192
- if (col.id) return col.id;
193
- if (col.accessorKey) return String(col.accessorKey);
194
- throw new Error("MatrxDataTable column requires `id` or `accessorKey`");
195
- }
196
- function getCellValue(row, col) {
197
- if (col.accessorFn) return col.accessorFn(row);
198
- if (col.accessorKey) {
199
- return row[col.accessorKey];
200
- }
201
- return void 0;
202
- }
203
- function getFilterValue(row, col) {
204
- return col.filterValue ? col.filterValue(row) : getCellValue(row, col);
205
- }
206
- function getSortValue(row, col) {
207
- return col.sortValue ? col.sortValue(row) : getCellValue(row, col);
208
- }
209
- function stringifyCellValue(value) {
210
- if (value == null) return "";
211
- if (typeof value === "string") return value;
212
- if (typeof value === "number" || typeof value === "boolean") {
213
- return String(value);
214
- }
215
- if (value instanceof Date) return value.toISOString();
216
- try {
217
- return JSON.stringify(value);
218
- } catch {
219
- return String(value);
220
- }
221
- }
222
- function tableSearchWords(value) {
223
- return value.toLocaleLowerCase().split(/[^\p{L}\p{N}]+/u).filter(Boolean);
224
- }
225
- function matchesTableSearch(searchableText, query, mode = "contains") {
226
- const normalizedQuery = query.trim().toLocaleLowerCase();
227
- if (!normalizedQuery) return true;
228
- if (mode === "contains") {
229
- return searchableText.toLocaleLowerCase().includes(normalizedQuery);
230
- }
231
- const actualWords = new Set(tableSearchWords(searchableText));
232
- const expectedWords = tableSearchWords(normalizedQuery);
233
- return expectedWords.length > 0 && expectedWords.every((word) => actualWords.has(word));
234
- }
235
- function compareValues(a, b) {
236
- if (a == null && b == null) return 0;
237
- if (a == null) return -1;
238
- if (b == null) return 1;
239
- if (typeof a === "number" && typeof b === "number") return a - b;
240
- if (typeof a === "boolean" && typeof b === "boolean") {
241
- return Number(a) - Number(b);
242
- }
243
- return stringifyCellValue(a).localeCompare(stringifyCellValue(b), void 0, {
244
- numeric: true,
245
- sensitivity: "base"
246
- });
247
- }
248
- function passesColumnFilter(value, filter) {
249
- const matches = (() => {
250
- switch (filter.kind) {
251
- case "text": {
252
- const s = stringifyCellValue(value);
253
- if (filter.mode === "null") return value == null;
254
- if (filter.mode === "not_null") return value != null;
255
- if (filter.mode === "empty") return s.trim() === "";
256
- if (filter.mode === "not_empty") return s.trim() !== "";
257
- const q = filter.value.trim().toLowerCase();
258
- if (!q) return true;
259
- return s.toLowerCase().includes(q);
260
- }
261
- case "select": {
262
- const selected = filter.values ?? (filter.value && filter.value !== "__all__" ? [filter.value] : []);
263
- if (selected.length === 0) return true;
264
- const s = stringifyCellValue(value);
265
- return selected.some(
266
- (v) => v === SELECT_EMPTY_VALUE ? s === "" : v === SELECT_NOT_EMPTY_VALUE ? s !== "" : s === v
267
- );
268
- }
269
- case "boolean": {
270
- return Boolean(value) === filter.value;
271
- }
272
- case "number": {
273
- const n = typeof value === "number" ? value : Number(stringifyCellValue(value).replace(/[^0-9.-]/g, ""));
274
- if (Number.isNaN(n)) return false;
275
- if (filter.min !== void 0 && n < filter.min) return false;
276
- if (filter.max !== void 0 && n > filter.max) return false;
277
- return true;
278
- }
279
- }
280
- })();
281
- return filter.negated ? !matches : matches;
282
- }
283
- function filterAndSortRows(rows, columns, columnFilters, sort, globalSearch, anyOf, layeredFilters, globalSearchMode = "contains", searchText) {
284
- const colById = new Map(columns.map((c) => [columnId(c), c]));
285
- const q = globalSearch.trim().toLowerCase();
286
- const anyQ = anyOf?.query.trim().toLowerCase() ?? "";
287
- const activeLayeredFilters = completeLayeredFilterRules(layeredFilters);
288
- let result = rows.filter((row) => {
289
- for (const [id, filter] of Object.entries(columnFilters)) {
290
- if (!filter) continue;
291
- const col = colById.get(id);
292
- if (!col || col.filter === false) continue;
293
- if (!passesColumnFilter(getFilterValue(row, col), filter)) return false;
294
- }
295
- for (const rule of activeLayeredFilters) {
296
- const col = colById.get(rule.field);
297
- if (!col || !layeredFilterMatchesValue(getFilterValue(row, col), rule)) {
298
- return false;
299
- }
300
- }
301
- if (anyQ && anyOf) {
302
- const hit = anyOf.columnIds.some((id) => {
303
- const col = colById.get(id);
304
- if (!col) return false;
305
- return stringifyCellValue(getFilterValue(row, col)).toLowerCase().includes(anyQ);
306
- });
307
- if (!hit) return false;
308
- }
309
- if (!q) return true;
310
- const searchableValues = columns.filter(
311
- (col) => col.filter !== false || Boolean(col.accessorKey || col.accessorFn)
312
- ).map((col) => stringifyCellValue(getFilterValue(row, col)));
313
- const additionalSearchText = searchText?.(row);
314
- if (additionalSearchText) searchableValues.push(additionalSearchText);
315
- if (globalSearchMode === "contains") {
316
- return searchableValues.some(
317
- (value) => matchesTableSearch(value, q, "contains")
318
- );
319
- }
320
- return matchesTableSearch(searchableValues.join(" "), q, "whole_words");
321
- });
322
- if (sort) {
323
- const col = colById.get(sort.id);
324
- if (col && col.sortable !== false) {
325
- const dir = sort.direction === "asc" ? 1 : -1;
326
- result = [...result].sort((a, b) => {
327
- const va = getSortValue(a, col);
328
- const vb = getSortValue(b, col);
329
- const ea = va == null || stringifyCellValue(va) === "";
330
- const eb = vb == null || stringifyCellValue(vb) === "";
331
- if (ea !== eb) return ea ? 1 : -1;
332
- return compareValues(va, vb) * dir;
333
- });
334
- }
335
- }
336
- return result;
337
- }
338
- function countActiveColumnFilters(filters) {
339
- let n = 0;
340
- for (const f of Object.values(filters)) {
341
- if (!f) continue;
342
- switch (f.kind) {
343
- case "text":
344
- if (f.value.trim() || f.mode && f.mode !== "contains") n += 1;
345
- break;
346
- case "select":
347
- if (f.values ? f.values.length > 0 : f.value && f.value !== "__all__")
348
- n += 1;
349
- break;
350
- case "boolean":
351
- n += 1;
352
- break;
353
- case "number":
354
- if (f.min !== void 0 || f.max !== void 0) n += 1;
355
- break;
356
- }
357
- }
358
- return n;
359
- }
360
- function isColumnFilterActive(filter) {
361
- if (!filter) return false;
362
- switch (filter.kind) {
363
- case "text":
364
- return filter.value.trim().length > 0 || filter.mode !== void 0 && filter.mode !== "contains";
365
- case "select":
366
- return filter.values ? filter.values.length > 0 : Boolean(filter.value) && filter.value !== "__all__";
367
- case "boolean":
368
- return true;
369
- case "number":
370
- return filter.min !== void 0 || filter.max !== void 0;
371
- }
372
- }
373
- function applyRowEdits(row, edits) {
374
- if (!edits || Object.keys(edits).length === 0) return row;
375
- return { ...row, ...edits };
376
- }
377
- var SELECT_EMPTY_VALUE, SELECT_NOT_EMPTY_VALUE;
378
- var init_filter_engine = __esm({
379
- "src/data-table/filter-engine.ts"() {
380
- "use strict";
381
- init_layered_filters();
382
- SELECT_EMPTY_VALUE = "__empty__";
383
- SELECT_NOT_EMPTY_VALUE = "__not_empty__";
384
- }
385
- });
386
-
387
- // src/data-table/tableXlsx.ts
388
- var tableXlsx_exports = {};
389
- __export(tableXlsx_exports, {
390
- downloadTableAsXlsx: () => downloadTableAsXlsx
391
- });
392
- function downloadTableAsXlsx({
393
- rows,
394
- columns,
395
- label
396
- }) {
397
- const visibleColumns = columns.filter(
398
- (column) => column.filter !== false || column.accessorKey
399
- );
400
- const headers = visibleColumns.map(
401
- (column) => typeof column.header === "string" ? column.header : columnId(column)
402
- );
403
- const values = rows.map(
404
- (row) => visibleColumns.map(
405
- (column) => stringifyCellValue(getCellValue(row, column))
406
- )
407
- );
408
- const worksheet = XLSX.utils.aoa_to_sheet([headers, ...values]);
409
- const workbook = XLSX.utils.book_new();
410
- const sheetName = label.replace(/[\\/?*[\]:]/g, " ").trim().slice(0, 31) || "Data";
411
- XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
412
- const bytes = XLSX.write(workbook, {
413
- type: "array",
414
- bookType: "xlsx",
415
- compression: true
416
- });
417
- const blob = new Blob([bytes], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
418
- const url = URL.createObjectURL(blob);
419
- const anchor = document.createElement("a");
420
- anchor.href = url;
421
- anchor.download = `${label.toLowerCase().replace(/[^a-z0-9]+/g, "-") || "table"}.xlsx`;
422
- anchor.click();
423
- URL.revokeObjectURL(url);
424
- }
425
- var XLSX;
426
- var init_tableXlsx = __esm({
427
- "src/data-table/tableXlsx.ts"() {
428
- "use strict";
429
- XLSX = __toESM(require("xlsx"), 1);
430
- init_filter_engine();
431
- }
432
- });
433
-
434
31
  // src/data-table/index.ts
435
32
  var data_table_exports = {};
436
33
  __export(data_table_exports, {
@@ -3852,54 +3449,389 @@ function SourceConfiguration({
3852
3449
  }
3853
3450
  );
3854
3451
  }
3855
-
3856
- // src/data-table/copy-payload.ts
3857
- function tableAgentText(value) {
3452
+
3453
+ // src/data-table/copy-payload.ts
3454
+ function tableAgentText(value) {
3455
+ if (typeof value === "string") return value;
3456
+ const attributes = Object.entries(value.attributes ?? {}).filter(([, entry]) => entry !== null && entry !== void 0 && entry !== "").map(([key, entry]) => ` ${key}="${String(entry)}"`).join("");
3457
+ const context = Object.entries(value.context ?? {}).filter(([, entry]) => entry !== null && entry !== void 0 && entry !== "").map(([key, entry]) => `<${key}>${String(entry)}</${key}>`).join("\n");
3458
+ const url = typeof window === "undefined" ? "" : window.location.href;
3459
+ const route = typeof window === "undefined" ? "" : window.location.pathname;
3460
+ return `<${value.kind}${attributes}>
3461
+ <context>
3462
+ <location>${value.location}</location>
3463
+ ${url ? `<url>${url}</url>` : ""}
3464
+ ${route ? `<route>${route}</route>` : ""}
3465
+ <copied>${value.description}</copied>
3466
+ <copied-at>${(/* @__PURE__ */ new Date()).toISOString()}</copied-at>
3467
+ ${context}
3468
+ </context>
3469
+ ${value.summary ? `<summary>
3470
+ ${value.summary}
3471
+ </summary>
3472
+ ` : ""}<data format="json">
3473
+ \`\`\`json
3474
+ ${JSON.stringify(value.data, null, 2)}
3475
+ \`\`\`
3476
+ </data>
3477
+ </${value.kind}>`;
3478
+ }
3479
+
3480
+ // src/data-table/copy.tsx
3481
+ var import_jsx_runtime23 = require("react/jsx-runtime");
3482
+ function CopyButtons(props) {
3483
+ const { CopyControls } = useMatrxDataTableHost();
3484
+ const copyProps = props.export?.sheetRows ? { ...props, primarySource: "table" } : props;
3485
+ if (CopyControls) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CopyControls, { ...copyProps });
3486
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(MatrxCopyMenu, { ...copyProps });
3487
+ }
3488
+
3489
+ // src/data-table/CopySubset.tsx
3490
+ var import_react4 = require("react");
3491
+ var import_clipboard = require("@ai-matrx/kit/clipboard");
3492
+
3493
+ // src/data-table/layered-filters.ts
3494
+ var import_zod = require("zod");
3495
+ var LAYERED_FILTER_OPERATORS = [
3496
+ "contains",
3497
+ "not_contains",
3498
+ "equals",
3499
+ "not_equals",
3500
+ "starts_with",
3501
+ "ends_with",
3502
+ "word",
3503
+ "not_word",
3504
+ "is_empty",
3505
+ "is_not_empty",
3506
+ "greater_than",
3507
+ "greater_or_equal",
3508
+ "less_than",
3509
+ "less_or_equal",
3510
+ "between"
3511
+ ];
3512
+ var layeredFilterRuleSchema = import_zod.z.object({
3513
+ id: import_zod.z.string().min(1),
3514
+ field: import_zod.z.string().min(1),
3515
+ operator: import_zod.z.enum(LAYERED_FILTER_OPERATORS),
3516
+ value: import_zod.z.string(),
3517
+ valueTo: import_zod.z.string().optional()
3518
+ });
3519
+ var layeredFilterRulesSchema = import_zod.z.array(layeredFilterRuleSchema).max(20);
3520
+ var TEXT_OPERATORS = [
3521
+ "contains",
3522
+ "not_contains",
3523
+ "equals",
3524
+ "not_equals",
3525
+ "starts_with",
3526
+ "ends_with",
3527
+ "word",
3528
+ "not_word",
3529
+ "is_empty",
3530
+ "is_not_empty"
3531
+ ];
3532
+ var NUMBER_OPERATORS = [
3533
+ "equals",
3534
+ "not_equals",
3535
+ "greater_than",
3536
+ "greater_or_equal",
3537
+ "less_than",
3538
+ "less_or_equal",
3539
+ "between",
3540
+ "is_empty",
3541
+ "is_not_empty"
3542
+ ];
3543
+ var SELECT_OPERATORS = [
3544
+ "equals",
3545
+ "not_equals",
3546
+ "is_empty",
3547
+ "is_not_empty"
3548
+ ];
3549
+ var LAYERED_FILTER_OPERATOR_LABELS = {
3550
+ contains: "contains",
3551
+ not_contains: "doesn't contain",
3552
+ equals: "is",
3553
+ not_equals: "is not",
3554
+ starts_with: "starts with",
3555
+ ends_with: "ends with",
3556
+ word: "has the word",
3557
+ not_word: "doesn't have the word",
3558
+ is_empty: "is empty",
3559
+ is_not_empty: "is not empty",
3560
+ greater_than: "is greater than",
3561
+ greater_or_equal: "is at least",
3562
+ less_than: "is less than",
3563
+ less_or_equal: "is at most",
3564
+ between: "is between"
3565
+ };
3566
+ function operatorsForLayeredField(field) {
3567
+ if (field.operators) return field.operators;
3568
+ if (field.kind === "number") return NUMBER_OPERATORS;
3569
+ if (field.kind === "select") return SELECT_OPERATORS;
3570
+ return TEXT_OPERATORS;
3571
+ }
3572
+ function layeredFilterNeedsValue(operator) {
3573
+ return operator !== "is_empty" && operator !== "is_not_empty";
3574
+ }
3575
+ function isCompleteLayeredFilterRule(rule) {
3576
+ if (!layeredFilterNeedsValue(rule.operator)) return true;
3577
+ if (rule.value.trim() === "") return false;
3578
+ return rule.operator !== "between" || Boolean(rule.valueTo?.trim());
3579
+ }
3580
+ function completeLayeredFilterRules(rules) {
3581
+ return (rules ?? []).filter(isCompleteLayeredFilterRule);
3582
+ }
3583
+ function isLayeredFilterOperator(value) {
3584
+ return LAYERED_FILTER_OPERATORS.some((operator) => operator === value);
3585
+ }
3586
+ function normalizedText(value) {
3587
+ if (value === null || value === void 0) return "";
3588
+ return String(value).trim().toLocaleLowerCase();
3589
+ }
3590
+ function words(value) {
3591
+ return value.split(/[^\p{L}\p{N}]+/u).filter(Boolean);
3592
+ }
3593
+ function layeredFilterMatchesValue(value, rule) {
3594
+ const actual = normalizedText(value);
3595
+ const expected = rule.value.trim().toLocaleLowerCase();
3596
+ const expectedTo = rule.valueTo?.trim().toLocaleLowerCase() ?? "";
3597
+ switch (rule.operator) {
3598
+ case "contains":
3599
+ return actual.includes(expected);
3600
+ case "not_contains":
3601
+ return !actual.includes(expected);
3602
+ case "equals":
3603
+ return actual === expected;
3604
+ case "not_equals":
3605
+ return actual !== expected;
3606
+ case "starts_with":
3607
+ return actual.startsWith(expected);
3608
+ case "ends_with":
3609
+ return actual.endsWith(expected);
3610
+ case "word":
3611
+ return words(actual).includes(expected);
3612
+ case "not_word":
3613
+ return !words(actual).includes(expected);
3614
+ case "is_empty":
3615
+ return actual === "";
3616
+ case "is_not_empty":
3617
+ return actual !== "";
3618
+ case "greater_than":
3619
+ return Number(actual) > Number(expected);
3620
+ case "greater_or_equal":
3621
+ return Number(actual) >= Number(expected);
3622
+ case "less_than":
3623
+ return Number(actual) < Number(expected);
3624
+ case "less_or_equal":
3625
+ return Number(actual) <= Number(expected);
3626
+ case "between": {
3627
+ const numeric = Number(actual);
3628
+ return numeric >= Number(expected) && numeric <= Number(expectedTo);
3629
+ }
3630
+ }
3631
+ }
3632
+ function layeredFilterRuleSummary(rule, fields) {
3633
+ const field = fields.find((candidate) => candidate.id === rule.field);
3634
+ const fieldLabel = field?.label ?? rule.field;
3635
+ const operator = LAYERED_FILTER_OPERATOR_LABELS[rule.operator];
3636
+ if (!layeredFilterNeedsValue(rule.operator))
3637
+ return `${fieldLabel} ${operator}`;
3638
+ const selectedLabel = field?.kind === "select" ? field.options.find((option) => option.value === rule.value)?.label : void 0;
3639
+ const value = selectedLabel ?? rule.value;
3640
+ return rule.operator === "between" ? `${fieldLabel} ${operator} ${value} and ${rule.valueTo ?? ""}` : `${fieldLabel} ${operator} ${value}`;
3641
+ }
3642
+
3643
+ // src/data-table/filter-engine.ts
3644
+ var SELECT_EMPTY_VALUE = "__empty__";
3645
+ var SELECT_NOT_EMPTY_VALUE = "__not_empty__";
3646
+ function columnId(col) {
3647
+ if (col.id) return col.id;
3648
+ if (col.accessorKey) return String(col.accessorKey);
3649
+ throw new Error("MatrxDataTable column requires `id` or `accessorKey`");
3650
+ }
3651
+ function getCellValue(row, col) {
3652
+ if (col.accessorFn) return col.accessorFn(row);
3653
+ if (col.accessorKey) {
3654
+ return row[col.accessorKey];
3655
+ }
3656
+ return void 0;
3657
+ }
3658
+ function getFilterValue(row, col) {
3659
+ return col.filterValue ? col.filterValue(row) : getCellValue(row, col);
3660
+ }
3661
+ function getSortValue(row, col) {
3662
+ return col.sortValue ? col.sortValue(row) : getCellValue(row, col);
3663
+ }
3664
+ function stringifyCellValue(value) {
3665
+ if (value == null) return "";
3858
3666
  if (typeof value === "string") return value;
3859
- const attributes = Object.entries(value.attributes ?? {}).filter(([, entry]) => entry !== null && entry !== void 0 && entry !== "").map(([key, entry]) => ` ${key}="${String(entry)}"`).join("");
3860
- const context = Object.entries(value.context ?? {}).filter(([, entry]) => entry !== null && entry !== void 0 && entry !== "").map(([key, entry]) => `<${key}>${String(entry)}</${key}>`).join("\n");
3861
- const url = typeof window === "undefined" ? "" : window.location.href;
3862
- const route = typeof window === "undefined" ? "" : window.location.pathname;
3863
- return `<${value.kind}${attributes}>
3864
- <context>
3865
- <location>${value.location}</location>
3866
- ${url ? `<url>${url}</url>` : ""}
3867
- ${route ? `<route>${route}</route>` : ""}
3868
- <copied>${value.description}</copied>
3869
- <copied-at>${(/* @__PURE__ */ new Date()).toISOString()}</copied-at>
3870
- ${context}
3871
- </context>
3872
- ${value.summary ? `<summary>
3873
- ${value.summary}
3874
- </summary>
3875
- ` : ""}<data format="json">
3876
- \`\`\`json
3877
- ${JSON.stringify(value.data, null, 2)}
3878
- \`\`\`
3879
- </data>
3880
- </${value.kind}>`;
3667
+ if (typeof value === "number" || typeof value === "boolean") {
3668
+ return String(value);
3669
+ }
3670
+ if (value instanceof Date) return value.toISOString();
3671
+ try {
3672
+ return JSON.stringify(value);
3673
+ } catch {
3674
+ return String(value);
3675
+ }
3881
3676
  }
3882
-
3883
- // src/data-table/copy.tsx
3884
- var import_jsx_runtime23 = require("react/jsx-runtime");
3885
- function CopyButtons(props) {
3886
- const { CopyControls } = useMatrxDataTableHost();
3887
- const copyProps = props.export?.sheetRows ? { ...props, primarySource: "table" } : props;
3888
- if (CopyControls) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CopyControls, { ...copyProps });
3889
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(MatrxCopyMenu, { ...copyProps });
3677
+ function tableSearchWords(value) {
3678
+ return value.toLocaleLowerCase().split(/[^\p{L}\p{N}]+/u).filter(Boolean);
3890
3679
  }
3891
- function jsonExportItem(build, label) {
3892
- return { id: "json", label, build: () => ({ content: JSON.stringify(build(), null, 2), extension: "json", mime: "application/json" }) };
3680
+ function matchesTableSearch(searchableText, query, mode = "contains") {
3681
+ const normalizedQuery = query.trim().toLocaleLowerCase();
3682
+ if (!normalizedQuery) return true;
3683
+ if (mode === "contains") {
3684
+ return searchableText.toLocaleLowerCase().includes(normalizedQuery);
3685
+ }
3686
+ const actualWords = new Set(tableSearchWords(searchableText));
3687
+ const expectedWords = tableSearchWords(normalizedQuery);
3688
+ return expectedWords.length > 0 && expectedWords.every((word) => actualWords.has(word));
3689
+ }
3690
+ function compareValues(a, b) {
3691
+ if (a == null && b == null) return 0;
3692
+ if (a == null) return -1;
3693
+ if (b == null) return 1;
3694
+ if (typeof a === "number" && typeof b === "number") return a - b;
3695
+ if (typeof a === "boolean" && typeof b === "boolean") {
3696
+ return Number(a) - Number(b);
3697
+ }
3698
+ return stringifyCellValue(a).localeCompare(stringifyCellValue(b), void 0, {
3699
+ numeric: true,
3700
+ sensitivity: "base"
3701
+ });
3702
+ }
3703
+ function passesColumnFilter(value, filter) {
3704
+ const matches = (() => {
3705
+ switch (filter.kind) {
3706
+ case "text": {
3707
+ const s = stringifyCellValue(value);
3708
+ if (filter.mode === "null") return value == null;
3709
+ if (filter.mode === "not_null") return value != null;
3710
+ if (filter.mode === "empty") return s.trim() === "";
3711
+ if (filter.mode === "not_empty") return s.trim() !== "";
3712
+ const q = filter.value.trim().toLowerCase();
3713
+ if (!q) return true;
3714
+ return s.toLowerCase().includes(q);
3715
+ }
3716
+ case "select": {
3717
+ const selected = filter.values ?? (filter.value && filter.value !== "__all__" ? [filter.value] : []);
3718
+ if (selected.length === 0) return true;
3719
+ const s = stringifyCellValue(value);
3720
+ return selected.some(
3721
+ (v) => v === SELECT_EMPTY_VALUE ? s === "" : v === SELECT_NOT_EMPTY_VALUE ? s !== "" : s === v
3722
+ );
3723
+ }
3724
+ case "boolean": {
3725
+ return Boolean(value) === filter.value;
3726
+ }
3727
+ case "number": {
3728
+ const n = typeof value === "number" ? value : Number(stringifyCellValue(value).replace(/[^0-9.-]/g, ""));
3729
+ if (Number.isNaN(n)) return false;
3730
+ if (filter.min !== void 0 && n < filter.min) return false;
3731
+ if (filter.max !== void 0 && n > filter.max) return false;
3732
+ return true;
3733
+ }
3734
+ }
3735
+ })();
3736
+ return filter.negated ? !matches : matches;
3737
+ }
3738
+ function filterAndSortRows(rows, columns, columnFilters, sort, globalSearch, anyOf, layeredFilters, globalSearchMode = "contains", searchText) {
3739
+ const colById = new Map(columns.map((c) => [columnId(c), c]));
3740
+ const q = globalSearch.trim().toLowerCase();
3741
+ const anyQ = anyOf?.query.trim().toLowerCase() ?? "";
3742
+ const activeLayeredFilters = completeLayeredFilterRules(layeredFilters);
3743
+ let result = rows.filter((row) => {
3744
+ for (const [id, filter] of Object.entries(columnFilters)) {
3745
+ if (!filter) continue;
3746
+ const col = colById.get(id);
3747
+ if (!col || col.filter === false) continue;
3748
+ if (!passesColumnFilter(getFilterValue(row, col), filter)) return false;
3749
+ }
3750
+ for (const rule of activeLayeredFilters) {
3751
+ const col = colById.get(rule.field);
3752
+ if (!col || !layeredFilterMatchesValue(getFilterValue(row, col), rule)) {
3753
+ return false;
3754
+ }
3755
+ }
3756
+ if (anyQ && anyOf) {
3757
+ const hit = anyOf.columnIds.some((id) => {
3758
+ const col = colById.get(id);
3759
+ if (!col) return false;
3760
+ return stringifyCellValue(getFilterValue(row, col)).toLowerCase().includes(anyQ);
3761
+ });
3762
+ if (!hit) return false;
3763
+ }
3764
+ if (!q) return true;
3765
+ const searchableValues = columns.filter(
3766
+ (col) => col.filter !== false || Boolean(col.accessorKey || col.accessorFn)
3767
+ ).map((col) => stringifyCellValue(getFilterValue(row, col)));
3768
+ const additionalSearchText = searchText?.(row);
3769
+ if (additionalSearchText) searchableValues.push(additionalSearchText);
3770
+ if (globalSearchMode === "contains") {
3771
+ return searchableValues.some(
3772
+ (value) => matchesTableSearch(value, q, "contains")
3773
+ );
3774
+ }
3775
+ return matchesTableSearch(searchableValues.join(" "), q, "whole_words");
3776
+ });
3777
+ if (sort) {
3778
+ const col = colById.get(sort.id);
3779
+ if (col && col.sortable !== false) {
3780
+ const dir = sort.direction === "asc" ? 1 : -1;
3781
+ result = [...result].sort((a, b) => {
3782
+ const va = getSortValue(a, col);
3783
+ const vb = getSortValue(b, col);
3784
+ const ea = va == null || stringifyCellValue(va) === "";
3785
+ const eb = vb == null || stringifyCellValue(vb) === "";
3786
+ if (ea !== eb) return ea ? 1 : -1;
3787
+ return compareValues(va, vb) * dir;
3788
+ });
3789
+ }
3790
+ }
3791
+ return result;
3792
+ }
3793
+ function countActiveColumnFilters(filters) {
3794
+ let n = 0;
3795
+ for (const f of Object.values(filters)) {
3796
+ if (!f) continue;
3797
+ switch (f.kind) {
3798
+ case "text":
3799
+ if (f.value.trim() || f.mode && f.mode !== "contains") n += 1;
3800
+ break;
3801
+ case "select":
3802
+ if (f.values ? f.values.length > 0 : f.value && f.value !== "__all__")
3803
+ n += 1;
3804
+ break;
3805
+ case "boolean":
3806
+ n += 1;
3807
+ break;
3808
+ case "number":
3809
+ if (f.min !== void 0 || f.max !== void 0) n += 1;
3810
+ break;
3811
+ }
3812
+ }
3813
+ return n;
3814
+ }
3815
+ function isColumnFilterActive(filter) {
3816
+ if (!filter) return false;
3817
+ switch (filter.kind) {
3818
+ case "text":
3819
+ return filter.value.trim().length > 0 || filter.mode !== void 0 && filter.mode !== "contains";
3820
+ case "select":
3821
+ return filter.values ? filter.values.length > 0 : Boolean(filter.value) && filter.value !== "__all__";
3822
+ case "boolean":
3823
+ return true;
3824
+ case "number":
3825
+ return filter.min !== void 0 || filter.max !== void 0;
3826
+ }
3827
+ }
3828
+ function applyRowEdits(row, edits) {
3829
+ if (!edits || Object.keys(edits).length === 0) return row;
3830
+ return { ...row, ...edits };
3893
3831
  }
3894
-
3895
- // src/data-table/CopySubset.tsx
3896
- var import_react4 = require("react");
3897
- var import_clipboard = require("@ai-matrx/kit/clipboard");
3898
- init_filter_engine();
3899
3832
 
3900
3833
  // src/data-table/tableCopy.ts
3901
3834
  var import_content_transfer3 = require("@ai-matrx/kit/content-transfer");
3902
- init_filter_engine();
3903
3835
  function projectDefaultTableCopyRow(row, columns) {
3904
3836
  const record = /* @__PURE__ */ Object.create(null);
3905
3837
  for (const column of columns) {
@@ -4488,7 +4420,6 @@ var CommandShortcut = ({
4488
4420
  CommandShortcut.displayName = "CommandShortcut";
4489
4421
 
4490
4422
  // src/data-table/ColumnHeaderCell.tsx
4491
- init_filter_engine();
4492
4423
  var import_jsx_runtime27 = require("react/jsx-runtime");
4493
4424
  var HeaderButton = (0, import_react7.forwardRef)(({ dragDescription, "aria-describedby": tooltipDescription, ...props }, ref) => {
4494
4425
  const descriptions = [tooltipDescription, dragDescription].filter((value) => Boolean(value)).join(" ");
@@ -5132,7 +5063,6 @@ function parseOptionalNumber(raw) {
5132
5063
  // src/data-table/ColumnManager.tsx
5133
5064
  var import_react8 = require("react");
5134
5065
  var import_core2 = require("@dnd-kit/core");
5135
- init_filter_engine();
5136
5066
  var import_jsx_runtime28 = require("react/jsx-runtime");
5137
5067
  function ColumnManager({
5138
5068
  open,
@@ -5812,7 +5742,6 @@ function DirtySavePill({
5812
5742
 
5813
5743
  // src/data-table/EditableTableCell.tsx
5814
5744
  var import_react11 = require("react");
5815
- init_filter_engine();
5816
5745
  var import_jsx_runtime33 = require("react/jsx-runtime");
5817
5746
  function CellEditShell({
5818
5747
  href,
@@ -6328,7 +6257,6 @@ function resetToolbarFacets(facets) {
6328
6257
 
6329
6258
  // src/data-table/LayeredFilterBuilder.tsx
6330
6259
  var import_react12 = require("react");
6331
- init_layered_filters();
6332
6260
  var import_jsx_runtime35 = require("react/jsx-runtime");
6333
6261
  function moveRule(rules, from, to) {
6334
6262
  if (from === to || to < 0 || to >= rules.length) return [...rules];
@@ -6696,12 +6624,7 @@ function LayeredRuleRow({
6696
6624
  );
6697
6625
  }
6698
6626
 
6699
- // src/data-table/MatrxDataTable.tsx
6700
- init_layered_filters();
6701
- init_filter_engine();
6702
-
6703
6627
  // src/data-table/infer-filter.ts
6704
- init_filter_engine();
6705
6628
  var SELECT_CARDINALITY_CAP = 24;
6706
6629
  function resolveFilterKind(col, sampleRows) {
6707
6630
  if (col.filter === false) return null;
@@ -7337,6 +7260,7 @@ function MatrxDataTableCore({
7337
7260
  [visibleColumns]
7338
7261
  );
7339
7262
  const tableCopySourceNamespace = (0, import_react13.useId)();
7263
+ const tableDndContextId = (0, import_react13.useId)();
7340
7264
  const defaultCopyTitle = toolbar?.title || "Table";
7341
7265
  const defaultCopy = (0, import_react13.useMemo)(() => ({
7342
7266
  label: defaultCopyTitle,
@@ -7870,8 +7794,14 @@ function MatrxDataTableCore({
7870
7794
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
7871
7795
  import_core3.DndContext,
7872
7796
  {
7797
+ id: tableDndContextId,
7873
7798
  sensors: hierarchySensors,
7874
7799
  collisionDetection: import_core3.pointerWithin,
7800
+ accessibility: {
7801
+ screenReaderInstructions: {
7802
+ draggable: "Drag with a pointer. To reorder columns with a keyboard, open Columns and use Move earlier or Move later."
7803
+ }
7804
+ },
7875
7805
  measuring: { droppable: { strategy: import_core3.MeasuringStrategy.Always } },
7876
7806
  onDragStart: (event) => {
7877
7807
  const kind = event.active.data.current?.matrxDragKind;
@@ -8133,37 +8063,14 @@ function MatrxDataTableCore({
8133
8063
  ],
8134
8064
  ...effectiveCopy.aiCustom ? { aiCustom: effectiveCopy.aiCustom(processed, data) } : {},
8135
8065
  export: {
8136
- items: copy === void 0 ? [] : [
8137
- jsonExportItem(
8138
- () => processed.map(
8139
- (r) => effectiveCopy.agentRow ? effectiveCopy.agentRow(r) : r
8140
- ),
8141
- "JSON (rows, raw)"
8142
- ),
8143
- {
8144
- id: "csv",
8145
- label: "CSV (current view)",
8146
- build: () => ({
8147
- content: rowsToCsvFromColumns(processed, effectiveCopyColumns),
8148
- extension: "csv",
8149
- mime: "text/csv"
8150
- })
8151
- },
8152
- {
8153
- id: "xlsx",
8154
- label: "Excel (.xlsx)",
8155
- onSelect: async () => {
8156
- const { downloadTableAsXlsx: downloadTableAsXlsx2 } = await Promise.resolve().then(() => (init_tableXlsx(), tableXlsx_exports));
8157
- downloadTableAsXlsx2({
8158
- rows: processed,
8159
- columns: effectiveCopyColumns,
8160
- label: effectiveCopy.listLabel ?? effectiveCopy.label
8161
- });
8162
- }
8163
- }
8164
- ],
8165
- sheetRows: () => copy === void 0 ? processed.map((row) => projectDefaultTableCopyRow(row, declaredVisibleCopyColumns)) : rowsToRecordsFromColumns(processed, effectiveCopyColumns),
8166
- ...copy === void 0 ? { sheetColumns: () => declaredVisibleCopyColumns.map((column) => ({ id: columnId(column), label: column.label ?? (typeof column.header === "string" ? column.header : columnId(column)) })) } : {}
8066
+ items: [],
8067
+ sheetRows: () => processed.map(
8068
+ (row) => projectDefaultTableCopyRow(row, declaredVisibleCopyColumns)
8069
+ ),
8070
+ sheetColumns: () => declaredVisibleCopyColumns.map((column) => ({
8071
+ id: columnId(column),
8072
+ label: column.label ?? (typeof column.header === "string" ? column.header : columnId(column))
8073
+ }))
8167
8074
  }
8168
8075
  }
8169
8076
  ) : null,
@@ -8237,40 +8144,14 @@ function MatrxDataTableCore({
8237
8144
  "selected"
8238
8145
  ),
8239
8146
  export: {
8240
- items: copy === void 0 ? [] : [
8241
- jsonExportItem(
8242
- () => selectedRows.map(
8243
- (row) => effectiveCopy.agentRow ? effectiveCopy.agentRow(row) : row
8244
- ),
8245
- "JSON (selected rows)"
8246
- ),
8247
- {
8248
- id: "csv",
8249
- label: "CSV (selected rows)",
8250
- build: () => ({
8251
- content: rowsToCsvFromColumns(
8252
- selectedRows,
8253
- effectiveCopyColumns
8254
- ),
8255
- extension: "csv",
8256
- mime: "text/csv"
8257
- })
8258
- },
8259
- {
8260
- id: "xlsx",
8261
- label: "Excel (.xlsx)",
8262
- onSelect: async () => {
8263
- const { downloadTableAsXlsx: downloadTableAsXlsx2 } = await Promise.resolve().then(() => (init_tableXlsx(), tableXlsx_exports));
8264
- downloadTableAsXlsx2({
8265
- rows: selectedRows,
8266
- columns: effectiveCopyColumns,
8267
- label: `${effectiveCopy.listLabel ?? effectiveCopy.label} selected`
8268
- });
8269
- }
8270
- }
8271
- ],
8272
- sheetRows: () => copy === void 0 ? selectedRows.map((row) => projectDefaultTableCopyRow(row, declaredVisibleCopyColumns)) : rowsToRecordsFromColumns(selectedRows, effectiveCopyColumns),
8273
- ...copy === void 0 ? { sheetColumns: () => declaredVisibleCopyColumns.map((column) => ({ id: columnId(column), label: column.label ?? (typeof column.header === "string" ? column.header : columnId(column)) })) } : {}
8147
+ items: [],
8148
+ sheetRows: () => selectedRows.map(
8149
+ (row) => projectDefaultTableCopyRow(row, declaredVisibleCopyColumns)
8150
+ ),
8151
+ sheetColumns: () => declaredVisibleCopyColumns.map((column) => ({
8152
+ id: columnId(column),
8153
+ label: column.label ?? (typeof column.header === "string" ? column.header : columnId(column))
8154
+ }))
8274
8155
  }
8275
8156
  }
8276
8157
  ) : null,
@@ -9359,6 +9240,39 @@ function resolveStringTitle(title, fallback) {
9359
9240
  return fallback;
9360
9241
  }
9361
9242
 
9362
- // src/data-table/index.ts
9363
- init_tableXlsx();
9243
+ // src/data-table/tableXlsx.ts
9244
+ var XLSX = __toESM(require("xlsx"), 1);
9245
+ function downloadTableAsXlsx({
9246
+ rows,
9247
+ columns,
9248
+ label
9249
+ }) {
9250
+ const visibleColumns = columns.filter(
9251
+ (column) => column.filter !== false || column.accessorKey
9252
+ );
9253
+ const headers = visibleColumns.map(
9254
+ (column) => typeof column.header === "string" ? column.header : columnId(column)
9255
+ );
9256
+ const values = rows.map(
9257
+ (row) => visibleColumns.map(
9258
+ (column) => stringifyCellValue(getCellValue(row, column))
9259
+ )
9260
+ );
9261
+ const worksheet = XLSX.utils.aoa_to_sheet([headers, ...values]);
9262
+ const workbook = XLSX.utils.book_new();
9263
+ const sheetName = label.replace(/[\\/?*[\]:]/g, " ").trim().slice(0, 31) || "Data";
9264
+ XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
9265
+ const bytes = XLSX.write(workbook, {
9266
+ type: "array",
9267
+ bookType: "xlsx",
9268
+ compression: true
9269
+ });
9270
+ const blob = new Blob([bytes], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
9271
+ const url = URL.createObjectURL(blob);
9272
+ const anchor = document.createElement("a");
9273
+ anchor.href = url;
9274
+ anchor.download = `${label.toLowerCase().replace(/[^a-z0-9]+/g, "-") || "table"}.xlsx`;
9275
+ anchor.click();
9276
+ URL.revokeObjectURL(url);
9277
+ }
9364
9278
  //# sourceMappingURL=index.cjs.map