@iyulab/flex-table 0.10.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.
@@ -0,0 +1,2137 @@
1
+ import { css as W, html as u, LitElement as T, nothing as k } from "lit";
2
+ import { property as w, state as C, customElement as M } from "lit/decorators.js";
3
+ const K = W`
4
+ /* --- Theme Variables (Light defaults) --- */
5
+ :host {
6
+ --ft-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
7
+ --ft-font-size: 14px;
8
+ --ft-border-color: #e0e0e0;
9
+ --ft-bg: #fff;
10
+ --ft-text-color: #202124;
11
+ --ft-header-bg: #f8f9fa;
12
+ --ft-header-hover-bg: #e8eaed;
13
+ --ft-header-text-color: #202124;
14
+ --ft-row-even-bg: #fff;
15
+ --ft-row-odd-bg: #fafafa;
16
+ --ft-row-hover-bg: #f0f4ff;
17
+ --ft-active-color: #1a73e8;
18
+ --ft-selection-bg: #e8f0fe;
19
+ --ft-bool-color: #2196f3;
20
+ --ft-sort-indicator-color: #5f6368;
21
+ --ft-editor-bg: #fff;
22
+ --ft-empty-color: #999;
23
+ }
24
+
25
+ /* --- Dark Theme (auto via prefers-color-scheme) --- */
26
+ @media (prefers-color-scheme: dark) {
27
+ :host(:not([theme="light"])) {
28
+ --ft-border-color: #3c4043;
29
+ --ft-bg: #1e1e1e;
30
+ --ft-text-color: #e8eaed;
31
+ --ft-header-bg: #292a2d;
32
+ --ft-header-hover-bg: #3c4043;
33
+ --ft-header-text-color: #e8eaed;
34
+ --ft-row-even-bg: #1e1e1e;
35
+ --ft-row-odd-bg: #252526;
36
+ --ft-row-hover-bg: #2a2d2e;
37
+ --ft-active-color: #4da3ff;
38
+ --ft-selection-bg: #264f78;
39
+ --ft-bool-color: #64b5f6;
40
+ --ft-sort-indicator-color: #9aa0a6;
41
+ --ft-editor-bg: #2d2d2d;
42
+ --ft-empty-color: #9aa0a6;
43
+ }
44
+ }
45
+
46
+ /* --- Force dark via attribute --- */
47
+ :host([theme="dark"]) {
48
+ --ft-border-color: #3c4043;
49
+ --ft-bg: #1e1e1e;
50
+ --ft-text-color: #e8eaed;
51
+ --ft-header-bg: #292a2d;
52
+ --ft-header-hover-bg: #3c4043;
53
+ --ft-header-text-color: #e8eaed;
54
+ --ft-row-even-bg: #1e1e1e;
55
+ --ft-row-odd-bg: #252526;
56
+ --ft-row-hover-bg: #2a2d2e;
57
+ --ft-active-color: #4da3ff;
58
+ --ft-selection-bg: #264f78;
59
+ --ft-bool-color: #64b5f6;
60
+ --ft-sort-indicator-color: #9aa0a6;
61
+ --ft-editor-bg: #2d2d2d;
62
+ --ft-empty-color: #9aa0a6;
63
+ }
64
+
65
+ /* --- Layout --- */
66
+ :host {
67
+ display: block;
68
+ position: relative;
69
+ overflow: auto;
70
+ font-family: var(--ft-font-family);
71
+ font-size: var(--ft-font-size);
72
+ color: var(--ft-text-color);
73
+ background: var(--ft-bg);
74
+ border: 1px solid var(--ft-border-color);
75
+ outline: none;
76
+ }
77
+
78
+ .ft-header {
79
+ display: block;
80
+ position: sticky;
81
+ top: 0;
82
+ z-index: 3;
83
+ }
84
+
85
+ .ft-header-cell {
86
+ position: absolute;
87
+ top: 0;
88
+ padding: 8px 12px;
89
+ background: var(--ft-header-bg);
90
+ color: var(--ft-header-text-color);
91
+ font-weight: 600;
92
+ user-select: none;
93
+ border-bottom: 2px solid var(--ft-border-color);
94
+ overflow: hidden;
95
+ text-overflow: ellipsis;
96
+ white-space: nowrap;
97
+ box-sizing: border-box;
98
+ display: flex;
99
+ align-items: center;
100
+ gap: 4px;
101
+ }
102
+
103
+ .ft-header-cell.ft-sortable { cursor: pointer; }
104
+ .ft-header-cell.ft-sortable:hover { background: var(--ft-header-hover-bg); }
105
+
106
+ .ft-resize-handle {
107
+ position: absolute;
108
+ right: 0; top: 0; bottom: 0;
109
+ width: 6px;
110
+ cursor: col-resize;
111
+ z-index: 3;
112
+ }
113
+
114
+ .ft-resize-handle:hover,
115
+ .ft-resize-handle.ft-resizing {
116
+ background: var(--ft-active-color);
117
+ opacity: 0.3;
118
+ }
119
+
120
+ .ft-sort-indicator {
121
+ flex-shrink: 0;
122
+ font-size: 12px;
123
+ color: var(--ft-sort-indicator-color);
124
+ }
125
+
126
+ .ft-sort-order {
127
+ font-size: 10px;
128
+ color: var(--ft-sort-indicator-color);
129
+ }
130
+
131
+ .ft-body { position: relative; }
132
+
133
+ .ft-row {
134
+ display: block;
135
+ position: absolute;
136
+ left: 0;
137
+ }
138
+
139
+ .ft-cell {
140
+ position: absolute;
141
+ top: 0;
142
+ padding: 6px 12px;
143
+ border-bottom: 1px solid var(--ft-border-color);
144
+ overflow: hidden;
145
+ text-overflow: ellipsis;
146
+ white-space: nowrap;
147
+ box-sizing: border-box;
148
+ cursor: default;
149
+ }
150
+
151
+ .ft-row-even .ft-cell { background: var(--ft-row-even-bg); }
152
+ .ft-row-odd .ft-cell { background: var(--ft-row-odd-bg); }
153
+ .ft-row:hover .ft-cell { background: var(--ft-row-hover-bg); }
154
+
155
+ .ft-cell.ft-active {
156
+ outline: 2px solid var(--ft-active-color);
157
+ outline-offset: -2px;
158
+ z-index: 1;
159
+ }
160
+
161
+ .ft-cell.ft-selected {
162
+ background: var(--ft-selection-bg) !important;
163
+ }
164
+
165
+ .ft-cell.ft-invalid {
166
+ outline: 2px solid #d93025;
167
+ outline-offset: -2px;
168
+ background: rgba(217, 48, 37, 0.08);
169
+ }
170
+
171
+ .ft-cell.ft-editing { padding: 0; overflow: visible; }
172
+
173
+ .ft-editor {
174
+ width: 100%; height: 100%;
175
+ border: none; outline: none;
176
+ padding: 6px 12px;
177
+ font: inherit;
178
+ color: var(--ft-text-color);
179
+ background: var(--ft-editor-bg);
180
+ box-sizing: border-box;
181
+ }
182
+ .ft-editor:focus {
183
+ outline: 2px solid var(--ft-active-color);
184
+ outline-offset: -2px;
185
+ }
186
+
187
+ .ft-editor-number { text-align: right; }
188
+
189
+ .ft-cell.ft-type-number {
190
+ text-align: right;
191
+ font-variant-numeric: tabular-nums;
192
+ }
193
+
194
+ .ft-cell.ft-type-boolean { text-align: center; }
195
+ .ft-bool { color: var(--ft-bool-color); }
196
+
197
+ .ft-empty {
198
+ padding: 24px;
199
+ text-align: center;
200
+ color: var(--ft-empty-color);
201
+ }
202
+
203
+ .ft-row-num-header,
204
+ .ft-row-num {
205
+ position: absolute;
206
+ top: 0;
207
+ display: flex;
208
+ align-items: center;
209
+ justify-content: center;
210
+ color: var(--ft-sort-indicator-color);
211
+ font-size: 12px;
212
+ padding: 6px 4px;
213
+ box-sizing: border-box;
214
+ user-select: none;
215
+ }
216
+
217
+ .ft-row-num-header {
218
+ background: var(--ft-header-bg);
219
+ font-weight: 600;
220
+ border-bottom: 2px solid var(--ft-border-color);
221
+ padding: 8px 4px;
222
+ }
223
+
224
+ .ft-row-num {
225
+ border-bottom: 1px solid var(--ft-border-color);
226
+ cursor: pointer;
227
+ background: var(--ft-row-even-bg);
228
+ }
229
+
230
+ .ft-row-odd .ft-row-num { background: var(--ft-row-odd-bg); }
231
+ .ft-row:hover .ft-row-num { background: var(--ft-row-hover-bg); }
232
+
233
+ .ft-row-num:hover {
234
+ background: var(--ft-header-hover-bg);
235
+ }
236
+
237
+ /* --- Pinned Columns --- */
238
+
239
+ .ft-pinned {
240
+ background: var(--ft-bg);
241
+ }
242
+
243
+ .ft-header-cell.ft-pinned {
244
+ background: var(--ft-header-bg);
245
+ }
246
+
247
+ .ft-row-even .ft-cell.ft-pinned { background: var(--ft-row-even-bg); }
248
+ .ft-row-odd .ft-cell.ft-pinned { background: var(--ft-row-odd-bg); }
249
+ .ft-row:hover .ft-cell.ft-pinned { background: var(--ft-row-hover-bg); }
250
+ .ft-cell.ft-pinned.ft-selected { background: var(--ft-selection-bg) !important; }
251
+
252
+ /* --- Filter UI --- */
253
+
254
+ .ft-filter-btn {
255
+ all: unset;
256
+ cursor: pointer;
257
+ font-size: 10px;
258
+ color: var(--ft-sort-indicator-color);
259
+ padding: 0 2px;
260
+ margin-left: auto;
261
+ opacity: 0.7;
262
+ flex-shrink: 0;
263
+ }
264
+
265
+ .ft-filter-btn:hover { opacity: 1; }
266
+
267
+ .ft-filter-btn.ft-filter-active {
268
+ color: var(--ft-active-color);
269
+ opacity: 1;
270
+ }
271
+
272
+ .ft-filter-dropdown {
273
+ position: absolute;
274
+ top: 100%;
275
+ left: 0;
276
+ min-width: 160px;
277
+ background: var(--ft-bg);
278
+ border: 1px solid var(--ft-border-color);
279
+ border-radius: 4px;
280
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
281
+ padding: 8px;
282
+ z-index: 10;
283
+ box-sizing: border-box;
284
+ }
285
+
286
+ .ft-filter-input {
287
+ width: 100%;
288
+ padding: 4px 8px;
289
+ font: inherit;
290
+ font-size: 13px;
291
+ border: 1px solid var(--ft-border-color);
292
+ border-radius: 3px;
293
+ color: var(--ft-text-color);
294
+ background: var(--ft-editor-bg);
295
+ box-sizing: border-box;
296
+ }
297
+
298
+ .ft-filter-input:focus {
299
+ outline: 1px solid var(--ft-active-color);
300
+ }
301
+
302
+ .ft-filter-range {
303
+ display: flex;
304
+ gap: 4px;
305
+ }
306
+
307
+ .ft-filter-range .ft-filter-input {
308
+ width: 50%;
309
+ }
310
+
311
+ .ft-filter-actions {
312
+ margin-top: 6px;
313
+ text-align: right;
314
+ }
315
+
316
+ .ft-filter-clear {
317
+ all: unset;
318
+ cursor: pointer;
319
+ font-size: 12px;
320
+ color: var(--ft-sort-indicator-color);
321
+ padding: 2px 8px;
322
+ border-radius: 3px;
323
+ }
324
+
325
+ .ft-filter-clear:hover {
326
+ background: var(--ft-header-hover-bg);
327
+ color: var(--ft-text-color);
328
+ }
329
+
330
+ /* --- Row Selection (Checkbox) --- */
331
+
332
+ .ft-checkbox-header,
333
+ .ft-checkbox-cell {
334
+ position: absolute;
335
+ top: 0;
336
+ display: flex;
337
+ align-items: center;
338
+ justify-content: center;
339
+ padding: 0 4px;
340
+ box-sizing: border-box;
341
+ user-select: none;
342
+ }
343
+
344
+ .ft-checkbox-header {
345
+ background: var(--ft-header-bg);
346
+ border-bottom: 2px solid var(--ft-border-color);
347
+ }
348
+
349
+ .ft-checkbox-cell {
350
+ border-bottom: 1px solid var(--ft-border-color);
351
+ background: var(--ft-row-even-bg);
352
+ }
353
+
354
+ .ft-row-odd .ft-checkbox-cell { background: var(--ft-row-odd-bg); }
355
+ .ft-row:hover .ft-checkbox-cell { background: var(--ft-row-hover-bg); }
356
+ .ft-row-selected .ft-checkbox-cell { background: var(--ft-selection-bg); }
357
+ .ft-row-selected .ft-cell { background: var(--ft-selection-bg) !important; }
358
+ .ft-row-selected .ft-row-num { background: var(--ft-selection-bg); }
359
+
360
+ .ft-checkbox-header input[type="checkbox"],
361
+ .ft-checkbox-cell input[type="checkbox"] {
362
+ width: 16px;
363
+ height: 16px;
364
+ cursor: pointer;
365
+ accent-color: var(--ft-active-color);
366
+ }
367
+
368
+ /* --- Footer Row --- */
369
+
370
+ .ft-footer {
371
+ display: block;
372
+ position: sticky;
373
+ bottom: 0;
374
+ z-index: 2;
375
+ background: var(--ft-header-bg);
376
+ border-top: 2px solid var(--ft-border-color);
377
+ }
378
+
379
+ .ft-footer-cell {
380
+ position: absolute;
381
+ top: 0;
382
+ padding: 6px 12px;
383
+ font-weight: 600;
384
+ font-size: 13px;
385
+ color: var(--ft-header-text-color);
386
+ overflow: hidden;
387
+ text-overflow: ellipsis;
388
+ white-space: nowrap;
389
+ box-sizing: border-box;
390
+ }
391
+ `;
392
+ function H(t, e, i) {
393
+ return i.renderer ? i.renderer(t, e, i) : q(t, i);
394
+ }
395
+ function q(t, e) {
396
+ if (t == null) return "";
397
+ switch (e.type) {
398
+ case "number":
399
+ return I(t);
400
+ case "boolean":
401
+ return u`<span class="ft-bool">${t ? "✔" : ""}</span>`;
402
+ case "date":
403
+ return P(t);
404
+ case "datetime":
405
+ return V(t);
406
+ default:
407
+ return String(t);
408
+ }
409
+ }
410
+ function I(t) {
411
+ return typeof t == "number" ? Number.isInteger(t) ? t.toLocaleString() : t.toLocaleString(void 0, { minimumFractionDigits: 1 }) : String(t);
412
+ }
413
+ function P(t) {
414
+ if (t instanceof Date) return t.toLocaleDateString();
415
+ if (typeof t == "string") {
416
+ const e = new Date(t);
417
+ return isNaN(e.getTime()) ? t : e.toLocaleDateString();
418
+ }
419
+ return String(t);
420
+ }
421
+ function V(t) {
422
+ if (t instanceof Date) return t.toLocaleString();
423
+ if (typeof t == "string") {
424
+ const e = new Date(t);
425
+ return isNaN(e.getTime()) ? t : e.toLocaleString();
426
+ }
427
+ return String(t);
428
+ }
429
+ function O(t) {
430
+ return {
431
+ startRow: Math.min(t.startRow, t.endRow),
432
+ startCol: Math.min(t.startCol, t.endCol),
433
+ endRow: Math.max(t.startRow, t.endRow),
434
+ endCol: Math.max(t.startCol, t.endCol)
435
+ };
436
+ }
437
+ class j {
438
+ constructor() {
439
+ this.activeCell = null, this.rangeAnchor = null, this.range = null, this._rowCount = 0, this._colCount = 0;
440
+ }
441
+ setDimensions(e, i) {
442
+ this._rowCount = e, this._colCount = i;
443
+ }
444
+ setActive(e, i) {
445
+ return e < 0 || e >= this._rowCount || i < 0 || i >= this._colCount ? this.activeCell : (this.activeCell = { row: e, col: i }, this.rangeAnchor = null, this.range = null, this.activeCell);
446
+ }
447
+ /** Set active cell and extend range from anchor */
448
+ setActiveWithRange(e, i) {
449
+ return e < 0 || e >= this._rowCount || i < 0 || i >= this._colCount ? this.activeCell : (!this.rangeAnchor && this.activeCell && (this.rangeAnchor = { ...this.activeCell }), this.activeCell = { row: e, col: i }, this.rangeAnchor && (this.range = O({
450
+ startRow: this.rangeAnchor.row,
451
+ startCol: this.rangeAnchor.col,
452
+ endRow: e,
453
+ endCol: i
454
+ })), this.activeCell);
455
+ }
456
+ /** Check if a cell is within the current selection range */
457
+ isInRange(e, i) {
458
+ if (!this.range) return !1;
459
+ const s = this.range;
460
+ return e >= s.startRow && e <= s.endRow && i >= s.startCol && i <= s.endCol;
461
+ }
462
+ /** Get the effective range: either the explicit range or just the active cell */
463
+ getEffectiveRange() {
464
+ return this.range ? this.range : this.activeCell ? {
465
+ startRow: this.activeCell.row,
466
+ startCol: this.activeCell.col,
467
+ endRow: this.activeCell.row,
468
+ endCol: this.activeCell.col
469
+ } : null;
470
+ }
471
+ clear() {
472
+ this.activeCell = null, this.rangeAnchor = null, this.range = null;
473
+ }
474
+ moveUp() {
475
+ return this.activeCell ? this.setActive(this.activeCell.row - 1, this.activeCell.col) : null;
476
+ }
477
+ moveDown() {
478
+ return this.activeCell ? this.setActive(this.activeCell.row + 1, this.activeCell.col) : null;
479
+ }
480
+ moveLeft() {
481
+ return this.activeCell ? this.setActive(this.activeCell.row, this.activeCell.col - 1) : null;
482
+ }
483
+ moveRight() {
484
+ return this.activeCell ? this.setActive(this.activeCell.row, this.activeCell.col + 1) : null;
485
+ }
486
+ moveNext() {
487
+ if (!this.activeCell) return null;
488
+ let { row: e, col: i } = this.activeCell;
489
+ return i++, i >= this._colCount && (i = 0, e++), e >= this._rowCount ? this.activeCell : this.setActive(e, i);
490
+ }
491
+ movePrev() {
492
+ if (!this.activeCell) return null;
493
+ let { row: e, col: i } = this.activeCell;
494
+ return i--, i < 0 && (i = this._colCount - 1, e--), e < 0 ? this.activeCell : this.setActive(e, i);
495
+ }
496
+ moveToStart() {
497
+ return this.setActive(0, 0);
498
+ }
499
+ moveToEnd() {
500
+ return this.setActive(this._rowCount - 1, this._colCount - 1);
501
+ }
502
+ moveToRowStart() {
503
+ return this.activeCell ? this.setActive(this.activeCell.row, 0) : null;
504
+ }
505
+ moveToRowEnd() {
506
+ return this.activeCell ? this.setActive(this.activeCell.row, this._colCount - 1) : null;
507
+ }
508
+ // Shift variants for range selection
509
+ shiftMoveUp() {
510
+ return this.activeCell ? this.setActiveWithRange(this.activeCell.row - 1, this.activeCell.col) : null;
511
+ }
512
+ shiftMoveDown() {
513
+ return this.activeCell ? this.setActiveWithRange(this.activeCell.row + 1, this.activeCell.col) : null;
514
+ }
515
+ shiftMoveLeft() {
516
+ return this.activeCell ? this.setActiveWithRange(this.activeCell.row, this.activeCell.col - 1) : null;
517
+ }
518
+ shiftMoveRight() {
519
+ return this.activeCell ? this.setActiveWithRange(this.activeCell.row, this.activeCell.col + 1) : null;
520
+ }
521
+ }
522
+ class B {
523
+ constructor() {
524
+ this.current = null;
525
+ }
526
+ start(e, i) {
527
+ this.current = { position: e, originalValue: i };
528
+ }
529
+ isEditing(e, i) {
530
+ return this.current !== null && this.current.position.row === e && this.current.position.col === i;
531
+ }
532
+ cancel() {
533
+ const e = this.current;
534
+ return this.current = null, e;
535
+ }
536
+ commit() {
537
+ const e = this.current;
538
+ return this.current = null, e;
539
+ }
540
+ }
541
+ class X {
542
+ constructor() {
543
+ this._selected = /* @__PURE__ */ new Set(), this._mode = "multi", this._rowCount = 0;
544
+ }
545
+ get mode() {
546
+ return this._mode;
547
+ }
548
+ set mode(e) {
549
+ if (this._mode = e, e === "single" && this._selected.size > 1) {
550
+ const i = this._selected.values().next().value;
551
+ this._selected.clear(), i !== void 0 && this._selected.add(i);
552
+ }
553
+ }
554
+ setRowCount(e) {
555
+ this._rowCount = e;
556
+ for (const i of this._selected)
557
+ i >= e && this._selected.delete(i);
558
+ }
559
+ get selectedIndices() {
560
+ return [...this._selected].sort((e, i) => e - i);
561
+ }
562
+ get selectedCount() {
563
+ return this._selected.size;
564
+ }
565
+ get isAllSelected() {
566
+ return this._rowCount > 0 && this._selected.size === this._rowCount;
567
+ }
568
+ get isSomeSelected() {
569
+ return this._selected.size > 0 && this._selected.size < this._rowCount;
570
+ }
571
+ isSelected(e) {
572
+ return this._selected.has(e);
573
+ }
574
+ toggle(e) {
575
+ this._mode === "single" ? this._selected.has(e) ? this._selected.clear() : (this._selected.clear(), this._selected.add(e)) : this._selected.has(e) ? this._selected.delete(e) : this._selected.add(e);
576
+ }
577
+ select(e) {
578
+ this._mode === "single" && this._selected.clear(), this._selected.add(e);
579
+ }
580
+ deselect(e) {
581
+ this._selected.delete(e);
582
+ }
583
+ selectAll() {
584
+ if (this._mode !== "single") {
585
+ this._selected.clear();
586
+ for (let e = 0; e < this._rowCount; e++)
587
+ this._selected.add(e);
588
+ }
589
+ }
590
+ deselectAll() {
591
+ this._selected.clear();
592
+ }
593
+ }
594
+ function Y(t, e, i) {
595
+ const s = Array.from({ length: t.length }, (r, n) => n);
596
+ if (e.length === 0) return s;
597
+ const o = /* @__PURE__ */ new Map();
598
+ for (const r of i)
599
+ o.set(r.key, r.type ?? "text");
600
+ return s.sort((r, n) => {
601
+ for (const { key: l, direction: a } of e) {
602
+ const d = t[r][l], f = t[n][l], h = d == null, g = f == null;
603
+ if (h && g) continue;
604
+ if (h) return 1;
605
+ if (g) return -1;
606
+ const p = J(d, f, o.get(l) ?? "text");
607
+ if (p !== 0)
608
+ return a === "asc" ? p : -p;
609
+ }
610
+ return r - n;
611
+ }), s;
612
+ }
613
+ function J(t, e, i) {
614
+ switch (i) {
615
+ case "number": {
616
+ const s = Number(t), o = Number(e);
617
+ return isNaN(s) && isNaN(o) ? 0 : isNaN(s) ? 1 : isNaN(o) ? -1 : s - o;
618
+ }
619
+ case "boolean":
620
+ return (t ? 1 : 0) - (e ? 1 : 0);
621
+ case "date":
622
+ case "datetime": {
623
+ const s = new Date(t).getTime(), o = new Date(e).getTime();
624
+ return (isNaN(s) ? 0 : s) - (isNaN(o) ? 0 : o);
625
+ }
626
+ default:
627
+ return String(t).localeCompare(String(e));
628
+ }
629
+ }
630
+ function G(t, e, i) {
631
+ const s = t.find((o) => o.key === e);
632
+ return i ? s ? s.direction === "asc" ? t.map((o) => o.key === e ? { ...o, direction: "desc" } : o) : t.filter((o) => o.key !== e) : [...t, { key: e, direction: "asc" }] : s ? s.direction === "asc" ? [{ key: e, direction: "desc" }] : [] : [{ key: e, direction: "asc" }];
633
+ }
634
+ function Q(t, e, i) {
635
+ if (e.length === 0)
636
+ return Array.from({ length: t.length }, (o, r) => r);
637
+ const s = [];
638
+ for (let o = 0; o < t.length; o++) {
639
+ const r = t[o];
640
+ let n = !0;
641
+ for (const l of e)
642
+ try {
643
+ if (!l.predicate(r[l.key], r)) {
644
+ n = !1;
645
+ break;
646
+ }
647
+ } catch (a) {
648
+ console.warn('Filter predicate error for key "%s":', l.key, a), i && i(a, r, l);
649
+ }
650
+ n && s.push(o);
651
+ }
652
+ return s;
653
+ }
654
+ const Z = 100;
655
+ class tt {
656
+ constructor() {
657
+ this._undoStack = [], this._redoStack = [], this._maxSize = Z;
658
+ }
659
+ /** Get/set the maximum number of undo actions stored. */
660
+ get maxSize() {
661
+ return this._maxSize;
662
+ }
663
+ set maxSize(e) {
664
+ for (this._maxSize = Math.max(1, e); this._undoStack.length > this._maxSize; )
665
+ this._undoStack.shift();
666
+ }
667
+ get canUndo() {
668
+ return this._undoStack.length > 0;
669
+ }
670
+ get canRedo() {
671
+ return this._redoStack.length > 0;
672
+ }
673
+ get undoCount() {
674
+ return this._undoStack.length;
675
+ }
676
+ get redoCount() {
677
+ return this._redoStack.length;
678
+ }
679
+ /**
680
+ * Push a new action onto the undo stack.
681
+ * Clears the redo stack (new action invalidates redo history).
682
+ */
683
+ push(e) {
684
+ this._undoStack.push(e), this._undoStack.length > this._maxSize && this._undoStack.shift(), this._redoStack.length = 0;
685
+ }
686
+ /**
687
+ * Undo the most recent action.
688
+ * Returns the action label, or null if nothing to undo.
689
+ */
690
+ undo() {
691
+ const e = this._undoStack.pop();
692
+ return e ? (e.undo(), this._redoStack.push(e), e.label) : null;
693
+ }
694
+ /**
695
+ * Redo the most recently undone action.
696
+ * Returns the action label, or null if nothing to redo.
697
+ */
698
+ redo() {
699
+ const e = this._redoStack.pop();
700
+ return e ? (e.redo(), this._undoStack.push(e), e.label) : null;
701
+ }
702
+ /**
703
+ * Clear all undo/redo history.
704
+ */
705
+ clear() {
706
+ this._undoStack.length = 0, this._redoStack.length = 0;
707
+ }
708
+ }
709
+ function et(t, e, i) {
710
+ const s = [];
711
+ for (let o = i.startRow; o <= i.endRow; o++) {
712
+ const r = t[o], n = [];
713
+ for (let l = i.startCol; l <= i.endCol; l++) {
714
+ const a = e[l], d = r[a.key];
715
+ n.push(d == null ? "" : String(d));
716
+ }
717
+ s.push(n.join(" "));
718
+ }
719
+ return s.join(`
720
+ `);
721
+ }
722
+ function it(t) {
723
+ const e = t.replace(/\r\n/g, `
724
+ `).replace(/\r/g, `
725
+ `), i = [];
726
+ let s = [], o = 0;
727
+ const r = e.length;
728
+ for (; o <= r; ) {
729
+ if (o === r) {
730
+ (s.length > 0 || i.length > 0) && i.push(s);
731
+ break;
732
+ }
733
+ if (e[o] === '"') {
734
+ let l = "";
735
+ for (o++; o < r; )
736
+ if (e[o] === '"')
737
+ if (o + 1 < r && e[o + 1] === '"')
738
+ l += '"', o += 2;
739
+ else {
740
+ o++;
741
+ break;
742
+ }
743
+ else
744
+ l += e[o], o++;
745
+ s.push(l), o < r && e[o] === " " ? o++ : o < r && e[o] === `
746
+ ` && (i.push(s), s = [], o++);
747
+ } else {
748
+ let l = "";
749
+ for (; o < r && e[o] !== " " && e[o] !== `
750
+ `; )
751
+ l += e[o], o++;
752
+ s.push(l), o < r && e[o] === " " ? o++ : o < r && e[o] === `
753
+ ` && (i.push(s), s = [], o++);
754
+ }
755
+ }
756
+ for (; i.length > 0; ) {
757
+ const n = i[i.length - 1];
758
+ if (n.length === 0 || n.length === 1 && n[0] === "")
759
+ i.pop();
760
+ else
761
+ break;
762
+ }
763
+ return i;
764
+ }
765
+ function A(t, e) {
766
+ if (t === "") return null;
767
+ switch (e.type) {
768
+ case "number": {
769
+ const i = Number(t);
770
+ return isNaN(i) ? t : i;
771
+ }
772
+ case "boolean":
773
+ return t.toLowerCase() === "true" || t === "1";
774
+ default:
775
+ return t;
776
+ }
777
+ }
778
+ function z(t, e, i) {
779
+ switch (i) {
780
+ case "csv":
781
+ return U(t, e, ",");
782
+ case "tsv":
783
+ return U(t, e, " ");
784
+ case "json":
785
+ return ot(t, e);
786
+ }
787
+ }
788
+ function st(t, e) {
789
+ return t == null ? "" : (e.type === "date" || e.type === "datetime") && t instanceof Date ? t.toISOString() : String(t);
790
+ }
791
+ function U(t, e, i) {
792
+ const s = e.map((r) => L(r.header, i)).join(i), o = t.map(
793
+ (r) => e.map((n) => {
794
+ const l = st(r[n.key], n);
795
+ return L(l, i);
796
+ }).join(i)
797
+ );
798
+ return [s, ...o].join(`
799
+ `);
800
+ }
801
+ function L(t, e) {
802
+ return t.includes(e) || t.includes('"') || t.includes(`
803
+ `) || t.includes("\r") ? '"' + t.replace(/"/g, '""') + '"' : t;
804
+ }
805
+ function ot(t, e) {
806
+ const i = t.map((s) => {
807
+ const o = {};
808
+ for (const r of e) {
809
+ const n = s[r.key];
810
+ (r.type === "date" || r.type === "datetime") && n instanceof Date ? o[r.key] = n.toISOString() : o[r.key] = n ?? null;
811
+ }
812
+ return o;
813
+ });
814
+ return JSON.stringify(i, null, 2);
815
+ }
816
+ function rt(t, e, i) {
817
+ const s = new Blob([t], { type: i }), o = URL.createObjectURL(s), r = document.createElement("a");
818
+ r.href = o, r.download = e, r.style.display = "none", document.body.appendChild(r), r.click(), document.body.removeChild(r), setTimeout(() => URL.revokeObjectURL(o), 100);
819
+ }
820
+ const nt = {
821
+ csv: "text/csv;charset=utf-8",
822
+ tsv: "text/tab-separated-values;charset=utf-8",
823
+ json: "application/json;charset=utf-8"
824
+ }, lt = {
825
+ csv: ".csv",
826
+ tsv: ".tsv",
827
+ json: ".json"
828
+ };
829
+ function at(t) {
830
+ return nt[t];
831
+ }
832
+ function ct(t) {
833
+ return lt[t];
834
+ }
835
+ var ht = Object.defineProperty, dt = Object.getOwnPropertyDescriptor, v = (t, e, i, s) => {
836
+ for (var o = s > 1 ? void 0 : s ? dt(e, i) : e, r = t.length - 1, n; r >= 0; r--)
837
+ (n = t[r]) && (o = (s ? n(e, i, o) : n(o)) || o);
838
+ return s && o && ht(e, i, o), o;
839
+ };
840
+ const S = 120, E = 40, ut = 32, $ = 5;
841
+ let _ = class extends T {
842
+ constructor() {
843
+ super(...arguments), this.columns = [], this.data = [], this.rowHeight = ut, this.showRowNumbers = !1, this.theme = void 0, this.maxRows = 0, this.editable = !0, this.showFilters = !1, this.selectable = !1, this.dataMode = "client", this.footerData = null, this._scrollTop = 0, this._scrollLeft = 0, this._viewportHeight = 0, this._viewportWidth = 0, this._colLeftOffsets = [], this._totalRowWidth = 0, this._activeCell = null, this._editingCell = null, this._sortCriteria = [], this._selection = new j(), this._editing = new B(), this._rowSelection = new X(), this._undo = new tt(), this._filters = [], this._filteredIndices = [], this._sortedIndices = [], this._openFilterKey = null, this._rowSelectionVersion = 0, this._viewDirty = !0, this._resizing = null, this._resizeCleanup = null, this._columnWidths = /* @__PURE__ */ new Map(), this._invalidCells = /* @__PURE__ */ new Map(), this._textFilterState = /* @__PURE__ */ new Map(), this._numberFilterState = /* @__PURE__ */ new Map(), this._dateFilterState = /* @__PURE__ */ new Map();
844
+ }
845
+ set selectionMode(t) {
846
+ this._rowSelection.mode = t, this.requestUpdate();
847
+ }
848
+ get selectionMode() {
849
+ return this._rowSelection.mode;
850
+ }
851
+ set maxUndoSize(t) {
852
+ this._undo.maxSize = t;
853
+ }
854
+ get maxUndoSize() {
855
+ return this._undo.maxSize;
856
+ }
857
+ get visibleColumns() {
858
+ return this.columns.filter((t) => !t.hidden);
859
+ }
860
+ get _prefixWidth() {
861
+ let t = 0;
862
+ return this.selectable && (t += 36), this.showRowNumbers && (t += 48), t;
863
+ }
864
+ /** Whether an undo operation is available. */
865
+ get canUndo() {
866
+ return this._undo.canUndo;
867
+ }
868
+ /** Whether a redo operation is available. */
869
+ get canRedo() {
870
+ return this._undo.canRedo;
871
+ }
872
+ get activeCell() {
873
+ return this._activeCell;
874
+ }
875
+ get editingCell() {
876
+ return this._editingCell;
877
+ }
878
+ get sortCriteria() {
879
+ return [...this._sortCriteria];
880
+ }
881
+ /** Number of rows after filtering (before pagination). */
882
+ get filteredRowCount() {
883
+ return this._filteredIndices.length;
884
+ }
885
+ // --- Public API: Row Selection ---
886
+ /** Get data indices of currently selected rows. */
887
+ getSelectedRows() {
888
+ const t = this._rowSelection.selectedIndices.map((e) => this._toDataIndex(e)).filter((e) => e >= 0 && e < this.data.length);
889
+ return {
890
+ selectedIndices: t,
891
+ selectedRows: t.map((e) => this.data[e])
892
+ };
893
+ }
894
+ /** Select all visible rows (multi mode only). */
895
+ selectAll() {
896
+ this.selectable && (this._rowSelection.selectAll(), this._rowSelectionVersion++, this._dispatchRowSelectionEvent());
897
+ }
898
+ /** Deselect all rows. */
899
+ deselectAll() {
900
+ this.selectable && (this._rowSelection.deselectAll(), this._rowSelectionVersion++, this._dispatchRowSelectionEvent());
901
+ }
902
+ _dispatchRowSelectionEvent() {
903
+ const { selectedIndices: t, selectedRows: e } = this.getSelectedRows();
904
+ this.dispatchEvent(new CustomEvent("selection-change", {
905
+ detail: { selectedIndices: t, selectedRows: e },
906
+ bubbles: !0,
907
+ composed: !0
908
+ }));
909
+ }
910
+ // --- Public API: Filtering ---
911
+ /**
912
+ * Set a filter for a column. Replaces any existing filter on the same key.
913
+ */
914
+ setFilter(t, e) {
915
+ this._filters = this._filters.filter((i) => i.key !== t), this._filters.push({ key: t, predicate: e }), this._recomputeView(), this.requestUpdate(), this._dispatchFilterEvent();
916
+ }
917
+ /**
918
+ * Remove the filter for a column.
919
+ */
920
+ removeFilter(t) {
921
+ const e = this._filters.length;
922
+ this._filters = this._filters.filter((i) => i.key !== t), this._filters.length !== e && (this._recomputeView(), this.requestUpdate(), this._dispatchFilterEvent());
923
+ }
924
+ /**
925
+ * Remove all filters.
926
+ */
927
+ clearFilters() {
928
+ this._filters.length !== 0 && (this._filters = [], this._recomputeView(), this.requestUpdate(), this._dispatchFilterEvent());
929
+ }
930
+ /**
931
+ * Get current active filter keys.
932
+ */
933
+ get filterKeys() {
934
+ return this._filters.map((t) => t.key);
935
+ }
936
+ /**
937
+ * Explicitly request a re-render after external data mutations.
938
+ * Useful when `data` array contents are mutated in-place without reassignment.
939
+ */
940
+ refreshData() {
941
+ this.requestUpdate("data");
942
+ }
943
+ _dispatchUndoStateEvent() {
944
+ this.dispatchEvent(new CustomEvent("undo-state-change", {
945
+ detail: { canUndo: this.canUndo, canRedo: this.canRedo },
946
+ bubbles: !0,
947
+ composed: !0
948
+ }));
949
+ }
950
+ _dispatchFilterEvent() {
951
+ this.dispatchEvent(new CustomEvent("filter-change", {
952
+ detail: { keys: this.filterKeys, filteredCount: this.filteredRowCount },
953
+ bubbles: !0,
954
+ composed: !0
955
+ }));
956
+ }
957
+ // --- Public API: Column Operations ---
958
+ /**
959
+ * Add a column at the specified index (default: end).
960
+ * Returns the added column definition.
961
+ */
962
+ addColumn(t, e) {
963
+ const i = e ?? this.columns.length;
964
+ return this.columns = [
965
+ ...this.columns.slice(0, i),
966
+ t,
967
+ ...this.columns.slice(i)
968
+ ], this._undo.push({
969
+ label: "column-add",
970
+ undo: () => {
971
+ this.columns = this.columns.filter((s) => s !== t), this.requestUpdate();
972
+ },
973
+ redo: () => {
974
+ this.columns = [
975
+ ...this.columns.slice(0, i),
976
+ t,
977
+ ...this.columns.slice(i)
978
+ ], this.requestUpdate();
979
+ }
980
+ }), this.requestUpdate(), this.dispatchEvent(new CustomEvent("column-add", {
981
+ detail: { column: t, index: i },
982
+ bubbles: !0,
983
+ composed: !0
984
+ })), this._dispatchUndoStateEvent(), t;
985
+ }
986
+ /**
987
+ * Delete a column by its key.
988
+ * Removes related filters, sort criteria, and column width overrides.
989
+ */
990
+ deleteColumn(t) {
991
+ const e = this.columns.findIndex((n) => n.key === t);
992
+ if (e === -1) return;
993
+ const i = this.columns[e], s = this._filters.find((n) => n.key === t), o = this._sortCriteria.find((n) => n.key === t), r = this._columnWidths.get(t);
994
+ this._filters = this._filters.filter((n) => n.key !== t), this._sortCriteria = this._sortCriteria.filter((n) => n.key !== t), this._columnWidths.delete(t), this.columns = this.columns.filter((n) => n.key !== t), this._undo.push({
995
+ label: "column-delete",
996
+ undo: () => {
997
+ this.columns = [
998
+ ...this.columns.slice(0, e),
999
+ i,
1000
+ ...this.columns.slice(e)
1001
+ ], s && this._filters.push(s), o && (this._sortCriteria = [...this._sortCriteria, o]), r !== void 0 && this._columnWidths.set(t, r), this.requestUpdate();
1002
+ },
1003
+ redo: () => {
1004
+ this._filters = this._filters.filter((n) => n.key !== t), this._sortCriteria = this._sortCriteria.filter((n) => n.key !== t), this._columnWidths.delete(t), this.columns = this.columns.filter((n) => n.key !== t), this.requestUpdate();
1005
+ }
1006
+ }), this._activeCell && this._activeCell.col >= this.visibleColumns.length && (this._selection.clear(), this._activeCell = null), this.requestUpdate(), this.dispatchEvent(new CustomEvent("column-delete", {
1007
+ detail: { column: i, key: t, index: e },
1008
+ bubbles: !0,
1009
+ composed: !0
1010
+ })), this._dispatchUndoStateEvent();
1011
+ }
1012
+ /**
1013
+ * Move a column to a new position.
1014
+ * @param key Column key to move.
1015
+ * @param newIndex Target index in the columns array.
1016
+ */
1017
+ moveColumn(t, e) {
1018
+ const i = this.columns.findIndex((n) => n.key === t);
1019
+ if (i === -1) return;
1020
+ const s = Math.max(0, Math.min(this.columns.length - 1, e));
1021
+ if (i === s) return;
1022
+ const o = this.columns[i], r = [...this.columns];
1023
+ r.splice(i, 1), r.splice(s, 0, o), this.columns = r, this._undo.push({
1024
+ label: "column-reorder",
1025
+ undo: () => {
1026
+ const n = [...this.columns];
1027
+ n.splice(s, 1), n.splice(i, 0, o), this.columns = n, this.requestUpdate();
1028
+ },
1029
+ redo: () => {
1030
+ const n = [...this.columns];
1031
+ n.splice(i, 1), n.splice(s, 0, o), this.columns = n, this.requestUpdate();
1032
+ }
1033
+ }), this.requestUpdate(), this.dispatchEvent(new CustomEvent("column-reorder", {
1034
+ detail: { key: t, oldIndex: i, newIndex: s },
1035
+ bubbles: !0,
1036
+ composed: !0
1037
+ })), this._dispatchUndoStateEvent();
1038
+ }
1039
+ // --- Public API: Row Operations ---
1040
+ /**
1041
+ * Add a row at the specified index (default: end).
1042
+ * Returns the new row.
1043
+ */
1044
+ addRow(t, e) {
1045
+ if (this.maxRows > 0 && this.data.length >= this.maxRows) return null;
1046
+ const i = t ?? this._createEmptyRow(), s = e ?? this.data.length;
1047
+ return this.data.splice(s, 0, i), this._undo.push({
1048
+ label: "row-add",
1049
+ undo: () => {
1050
+ this.data.splice(s, 1), this.requestUpdate();
1051
+ },
1052
+ redo: () => {
1053
+ this.data.splice(s, 0, i), this.requestUpdate();
1054
+ }
1055
+ }), this.requestUpdate(), this.dispatchEvent(new CustomEvent("row-add", {
1056
+ detail: { row: i, index: s },
1057
+ bubbles: !0,
1058
+ composed: !0
1059
+ })), this._dispatchUndoStateEvent(), i;
1060
+ }
1061
+ /**
1062
+ * Delete rows at the specified data indices.
1063
+ * If no indices provided, deletes the currently selected rows.
1064
+ */
1065
+ deleteRows(t) {
1066
+ const e = t ?? this._getSelectedDataRows();
1067
+ if (e.length === 0) return;
1068
+ const i = [...e].sort((o, r) => r - o), s = [];
1069
+ for (const o of i)
1070
+ o >= 0 && o < this.data.length && (s.push({ index: o, row: this.data[o] }), this.data.splice(o, 1));
1071
+ if (s.length !== 0) {
1072
+ if (s.reverse(), this._undo.push({
1073
+ label: "row-delete",
1074
+ undo: () => {
1075
+ for (const { index: o, row: r } of s)
1076
+ this.data.splice(o, 0, r);
1077
+ this.requestUpdate();
1078
+ },
1079
+ redo: () => {
1080
+ const o = [...s].reverse();
1081
+ for (const { index: r } of o)
1082
+ this.data.splice(r, 1);
1083
+ this.requestUpdate();
1084
+ }
1085
+ }), this._activeCell) {
1086
+ const o = this._toDataIndex(this._activeCell.row);
1087
+ e.includes(o) && (this._selection.clear(), this._activeCell = null);
1088
+ }
1089
+ this.requestUpdate(), this.dispatchEvent(new CustomEvent("row-delete", {
1090
+ detail: { indices: s.map((o) => o.index), rows: s.map((o) => o.row) },
1091
+ bubbles: !0,
1092
+ composed: !0
1093
+ })), this._dispatchUndoStateEvent();
1094
+ }
1095
+ }
1096
+ /**
1097
+ * Apply multiple cell changes as a single undo-able operation.
1098
+ * @param changes Array of { row (data index), key, value } objects.
1099
+ */
1100
+ updateRows(t) {
1101
+ if (t.length === 0) return;
1102
+ const e = [];
1103
+ for (const i of t) {
1104
+ if (i.row < 0 || i.row >= this.data.length) continue;
1105
+ const s = this.data[i.row][i.key];
1106
+ this.data[i.row][i.key] = i.value, e.push({ row: i.row, key: i.key, oldValue: s, newValue: i.value });
1107
+ }
1108
+ e.length !== 0 && (this._undo.push({
1109
+ label: "batch-update",
1110
+ undo: () => {
1111
+ for (const i of e)
1112
+ this.data[i.row][i.key] = i.oldValue;
1113
+ this.requestUpdate();
1114
+ },
1115
+ redo: () => {
1116
+ for (const i of e)
1117
+ this.data[i.row][i.key] = i.newValue;
1118
+ this.requestUpdate();
1119
+ }
1120
+ }), this.requestUpdate(), this.dispatchEvent(new CustomEvent("batch-update", {
1121
+ detail: { changes: e },
1122
+ bubbles: !0,
1123
+ composed: !0
1124
+ })), this._dispatchUndoStateEvent());
1125
+ }
1126
+ _createEmptyRow() {
1127
+ const t = {};
1128
+ for (const e of this.columns)
1129
+ switch (e.type) {
1130
+ case "number":
1131
+ t[e.key] = 0;
1132
+ break;
1133
+ case "boolean":
1134
+ t[e.key] = !1;
1135
+ break;
1136
+ default:
1137
+ t[e.key] = "";
1138
+ }
1139
+ return t;
1140
+ }
1141
+ // --- Public API: Export ---
1142
+ /**
1143
+ * Export table data to string in the specified format.
1144
+ * @param options.selectionOnly - Export only the currently selected range
1145
+ */
1146
+ exportToString(t, e) {
1147
+ if (e != null && e.selectionOnly) {
1148
+ const s = this._selection.getEffectiveRange();
1149
+ if (!s) return "";
1150
+ const o = this.visibleColumns.slice(s.startCol, s.endCol + 1), r = [];
1151
+ for (let n = s.startRow; n <= s.endRow; n++)
1152
+ r.push(this.data[this._toDataIndex(n)]);
1153
+ return z(r, o, t);
1154
+ }
1155
+ const i = this._sortedIndices.map((s) => this.data[s]);
1156
+ return z(i, this.visibleColumns, t);
1157
+ }
1158
+ /**
1159
+ * Export table data and trigger file download.
1160
+ */
1161
+ exportToFile(t, e) {
1162
+ const i = this.exportToString(t), s = e ?? `export${ct(t)}`;
1163
+ rt(i, s, at(t));
1164
+ }
1165
+ _getSelectedDataRows() {
1166
+ const t = this._selection.getEffectiveRange();
1167
+ if (!t) return [];
1168
+ const e = [];
1169
+ for (let i = t.startRow; i <= t.endRow; i++)
1170
+ e.push(this._toDataIndex(i));
1171
+ return e;
1172
+ }
1173
+ /**
1174
+ * Get the effective width for a column, checking internal overrides first.
1175
+ */
1176
+ getColumnWidth(t) {
1177
+ return this._columnWidths.get(t);
1178
+ }
1179
+ _getColWidth(t) {
1180
+ const e = this._columnWidths.get(t.key) ?? t.width ?? S;
1181
+ return Math.max(e, t.minWidth ?? E);
1182
+ }
1183
+ get headerHeight() {
1184
+ return this.rowHeight + 8;
1185
+ }
1186
+ /** Number of rows visible after filter + sort. */
1187
+ get _visibleRowCount() {
1188
+ return this._sortedIndices.length;
1189
+ }
1190
+ get totalBodyHeight() {
1191
+ return this._visibleRowCount * this.rowHeight;
1192
+ }
1193
+ get visibleRange() {
1194
+ const t = Math.max(0, this._scrollTop - this.headerHeight), e = Math.max(0, Math.floor(t / this.rowHeight) - $), i = Math.ceil(this._viewportHeight / this.rowHeight), s = Math.min(this._visibleRowCount, Math.floor(t / this.rowHeight) + i + $);
1195
+ return { start: e, end: s };
1196
+ }
1197
+ connectedCallback() {
1198
+ super.connectedCallback(), this._onScroll = this._onScroll.bind(this), this._onKeyDown = this._onKeyDown.bind(this), this._onDocumentClick = this._onDocumentClick.bind(this), this._onContextMenu = this._onContextMenu.bind(this), this.addEventListener("scroll", this._onScroll, { passive: !0 }), this.addEventListener("keydown", this._onKeyDown), this.addEventListener("contextmenu", this._onContextMenu), this.hasAttribute("tabindex") || this.setAttribute("tabindex", "0"), this.setAttribute("role", "grid");
1199
+ }
1200
+ disconnectedCallback() {
1201
+ super.disconnectedCallback(), this.removeEventListener("scroll", this._onScroll), this.removeEventListener("keydown", this._onKeyDown), this.removeEventListener("contextmenu", this._onContextMenu), document.removeEventListener("click", this._onDocumentClick), this._resizeCleanup && (this._resizeCleanup(), this._resizeCleanup = null);
1202
+ }
1203
+ firstUpdated() {
1204
+ this._measureViewport();
1205
+ }
1206
+ _updateColOffsets() {
1207
+ const t = this.visibleColumns, e = [];
1208
+ let i = this._prefixWidth;
1209
+ for (const s of t)
1210
+ e.push(i), i += this._getColWidth(s);
1211
+ this._colLeftOffsets = e, this._totalRowWidth = i;
1212
+ }
1213
+ get visibleColRange() {
1214
+ const t = this.visibleColumns;
1215
+ if (t.length === 0) return { start: 0, end: 0 };
1216
+ const e = this._colLeftOffsets;
1217
+ if (e.length === 0) return { start: 0, end: t.length };
1218
+ const i = this._scrollLeft, s = i + this._viewportWidth;
1219
+ let o = t.length;
1220
+ for (let n = 0; n < e.length; n++)
1221
+ if (e[n] + this._getColWidth(t[n]) > i) {
1222
+ o = n;
1223
+ break;
1224
+ }
1225
+ o = Math.max(0, o - $);
1226
+ let r = t.length;
1227
+ for (let n = o; n < e.length; n++)
1228
+ if (e[n] > s) {
1229
+ r = n;
1230
+ break;
1231
+ }
1232
+ return r = Math.min(t.length, r + $), { start: o, end: r };
1233
+ }
1234
+ willUpdate(t) {
1235
+ (!(t.size <= 2 && !t.has("data") && !t.has("columns") && !t.has("_openFilterKey") && !t.has("_editingCell") && !t.has("_activeCell") && (t.has("_scrollTop") || t.has("_scrollLeft"))) || this._viewDirty) && (this._recomputeView(), this._viewDirty = !1), this._updateColOffsets(), this._selection.setDimensions(this._visibleRowCount, this.visibleColumns.length), this._rowSelection.setRowCount(this._visibleRowCount);
1236
+ }
1237
+ updated() {
1238
+ this._measureViewport(), this._focusEditor(), this._adjustFilterDropdown(), this.setAttribute("aria-rowcount", String(this._visibleRowCount)), this.setAttribute("aria-colcount", String(this.visibleColumns.length));
1239
+ }
1240
+ /** Recompute filter → sort pipeline. */
1241
+ _recomputeView() {
1242
+ if (this.dataMode === "server") {
1243
+ this._filteredIndices = Array.from({ length: this.data.length }, (t, e) => e), this._sortedIndices = this._filteredIndices;
1244
+ return;
1245
+ }
1246
+ if (this._filteredIndices = Q(this.data, this._filters, (t, e, i) => {
1247
+ this.dispatchEvent(new CustomEvent("filter-error", {
1248
+ detail: { error: t, row: e, filterKey: i.key },
1249
+ bubbles: !0,
1250
+ composed: !0
1251
+ }));
1252
+ }), this._filters.length === 0 && this._sortCriteria.length === 0)
1253
+ this._sortedIndices = Array.from({ length: this.data.length }, (t, e) => e);
1254
+ else if (this._sortCriteria.length === 0)
1255
+ this._sortedIndices = [...this._filteredIndices];
1256
+ else {
1257
+ const t = this._filteredIndices.map((i) => this.data[i]), e = Y(t, this._sortCriteria, this.visibleColumns);
1258
+ this._sortedIndices = e.map((i) => this._filteredIndices[i]);
1259
+ }
1260
+ }
1261
+ /** Map visual row index to data row index */
1262
+ _toDataIndex(t) {
1263
+ return this._sortedIndices[t] ?? t;
1264
+ }
1265
+ _focusEditor() {
1266
+ var e;
1267
+ if (!this._editingCell) return;
1268
+ const t = (e = this.shadowRoot) == null ? void 0 : e.querySelector(".ft-editor");
1269
+ t && document.activeElement !== t && (t.focus(), (t.type === "text" || t.type === "number") && t.select());
1270
+ }
1271
+ _measureViewport() {
1272
+ const t = this.clientHeight, e = this.clientWidth;
1273
+ t !== this._viewportHeight && (this._viewportHeight = t), e !== this._viewportWidth && (this._viewportWidth = e);
1274
+ }
1275
+ _onScroll() {
1276
+ this._scrollTop = this.scrollTop, this._scrollLeft = this.scrollLeft;
1277
+ }
1278
+ _onDocumentClick() {
1279
+ this._openFilterKey && (this._openFilterKey = null);
1280
+ }
1281
+ _onContextMenu(t) {
1282
+ var f;
1283
+ const i = t.composedPath().find(
1284
+ (h) => h instanceof HTMLElement && h.classList.contains("ft-cell")
1285
+ );
1286
+ if (!i) return;
1287
+ const s = i.parentElement;
1288
+ if (!s || !s.classList.contains("ft-row")) return;
1289
+ const o = parseInt(i.dataset.colIndex ?? "-1", 10), r = s.style.top, n = parseInt(r, 10), l = Math.round(n / this.rowHeight);
1290
+ if (o < 0 || l < 0) return;
1291
+ const a = this._toDataIndex(l), d = this.visibleColumns[o];
1292
+ d && this.dispatchEvent(new CustomEvent("context-menu", {
1293
+ detail: {
1294
+ x: t.clientX,
1295
+ y: t.clientY,
1296
+ row: a,
1297
+ col: o,
1298
+ key: d.key,
1299
+ value: (f = this.data[a]) == null ? void 0 : f[d.key],
1300
+ rowData: this.data[a]
1301
+ },
1302
+ bubbles: !0,
1303
+ composed: !0
1304
+ }));
1305
+ }
1306
+ _onCellClickEvent(t, e, i) {
1307
+ this._editing.current && this._commitEdit(), t.shiftKey ? this._selection.setActiveWithRange(e, i) : this._selection.setActive(e, i), this._activeCell = this._selection.activeCell ? { ...this._selection.activeCell } : null, this._dispatchSelectionEvent(), this.requestUpdate();
1308
+ }
1309
+ _onRowNumberClick(t) {
1310
+ this._editing.current && this._commitEdit();
1311
+ const e = this.visibleColumns.length - 1;
1312
+ this._selection.setActive(t, 0), this._selection.setActiveWithRange(t, e), this._activeCell = this._selection.activeCell ? { ...this._selection.activeCell } : null, this._dispatchSelectionEvent(), this.requestUpdate();
1313
+ }
1314
+ _onCellDblClick(t, e) {
1315
+ this._editing.current && this._commitEdit(), this._selection.setActive(t, e), this._activeCell = this._selection.activeCell ? { ...this._selection.activeCell } : null, this._dispatchSelectionEvent(), this._startEdit();
1316
+ }
1317
+ // --- Editing ---
1318
+ /** Check if a column is editable based on global + per-column settings */
1319
+ _isCellEditable(t) {
1320
+ return !(!this.editable || t.editable === !1);
1321
+ }
1322
+ _startEdit() {
1323
+ if (!this._activeCell) return;
1324
+ const e = this.visibleColumns[this._activeCell.col];
1325
+ if (!e || !this._isCellEditable(e)) return;
1326
+ if (e.type === "boolean") {
1327
+ const r = this.data[this._toDataIndex(this._activeCell.row)][e.key];
1328
+ this._applyEdit(!r);
1329
+ return;
1330
+ }
1331
+ const i = this._toDataIndex(this._activeCell.row), s = this.data[i];
1332
+ this._editing.start(this._activeCell, s[e.key]), this._editingCell = { ...this._activeCell }, this.dispatchEvent(new CustomEvent("cell-edit-start", {
1333
+ detail: { row: i, col: this._activeCell.col, key: e.key, value: s[e.key] },
1334
+ bubbles: !0,
1335
+ composed: !0
1336
+ }));
1337
+ }
1338
+ _commitEdit() {
1339
+ var e;
1340
+ if (!this._editing.current) return;
1341
+ const t = (e = this.shadowRoot) == null ? void 0 : e.querySelector(".ft-editor");
1342
+ if (t) {
1343
+ const i = this.visibleColumns[this._editing.current.position.col], s = A(t.value, i);
1344
+ this._applyEdit(s);
1345
+ } else
1346
+ this._cancelEdit();
1347
+ }
1348
+ _applyEdit(t) {
1349
+ const e = this._editing.commit();
1350
+ if (this._editingCell = null, !e) return;
1351
+ const { row: i, col: s } = e.position, o = this._toDataIndex(i), r = this.visibleColumns[s], n = e.originalValue;
1352
+ if (r.validator) {
1353
+ const l = r.validator(t, this.data[o], r);
1354
+ if (l) {
1355
+ this._markCellInvalid(i, s, l), this.dispatchEvent(new CustomEvent("validation-error", {
1356
+ detail: { row: o, col: s, key: r.key, value: t, error: l },
1357
+ bubbles: !0,
1358
+ composed: !0
1359
+ }));
1360
+ return;
1361
+ }
1362
+ }
1363
+ this.data[o][r.key] = t, this._undo.push({
1364
+ label: "cell-edit",
1365
+ undo: () => {
1366
+ this.data[o][r.key] = n, this.requestUpdate();
1367
+ },
1368
+ redo: () => {
1369
+ this.data[o][r.key] = t, this.requestUpdate();
1370
+ }
1371
+ }), this.requestUpdate(), this.dispatchEvent(new CustomEvent("cell-edit-commit", {
1372
+ detail: { row: o, col: s, key: r.key, oldValue: n, newValue: t },
1373
+ bubbles: !0,
1374
+ composed: !0
1375
+ })), this._dispatchUndoStateEvent();
1376
+ }
1377
+ _cancelEdit() {
1378
+ const t = this._editing.cancel();
1379
+ this._editingCell = null, t && this.dispatchEvent(new CustomEvent("cell-edit-cancel", {
1380
+ detail: { row: t.position.row, col: t.position.col },
1381
+ bubbles: !0,
1382
+ composed: !0
1383
+ }));
1384
+ }
1385
+ _onEditorKeyDown(t) {
1386
+ t.key === "Enter" ? (t.preventDefault(), t.stopPropagation(), this._commitEdit(), this._selection.moveDown(), this._syncActiveCell()) : t.key === "Tab" ? (t.preventDefault(), t.stopPropagation(), this._commitEdit(), t.shiftKey ? this._selection.movePrev() : this._selection.moveNext(), this._syncActiveCell()) : t.key === "Escape" && (t.preventDefault(), t.stopPropagation(), this._cancelEdit());
1387
+ }
1388
+ _syncActiveCell() {
1389
+ this._activeCell = this._selection.activeCell ? { ...this._selection.activeCell } : null, this._scrollToActiveCell(), this._dispatchSelectionEvent();
1390
+ }
1391
+ // --- Navigation ---
1392
+ _onKeyDown(t) {
1393
+ if (this._editing.current) return;
1394
+ const e = this.visibleColumns;
1395
+ if (e.length === 0 || this._visibleRowCount === 0) return;
1396
+ if ((t.key === "Enter" || t.key === "F2") && this._activeCell) {
1397
+ t.preventDefault(), this._startEdit();
1398
+ return;
1399
+ }
1400
+ if (!this._selection.activeCell) {
1401
+ if (["ArrowDown", "ArrowUp", "ArrowLeft", "ArrowRight", "Tab", "Home", "End"].includes(t.key)) {
1402
+ this._selection.setActive(0, 0), this._syncActiveCell(), t.preventDefault();
1403
+ return;
1404
+ }
1405
+ return;
1406
+ }
1407
+ if (this._handleCtrlKey(t) || this._handleAltKey(t, e)) return;
1408
+ if (this._activeCell && t.key.length === 1 && !t.ctrlKey && !t.metaKey && !t.altKey) {
1409
+ const s = e[this._activeCell.col];
1410
+ s && this._isCellEditable(s) && this._startEdit();
1411
+ return;
1412
+ }
1413
+ this._handleNavigation(t) && (t.preventDefault(), this._syncActiveCell());
1414
+ }
1415
+ _handleCtrlKey(t) {
1416
+ if (!(t.ctrlKey || t.metaKey) || t.altKey) return !1;
1417
+ switch (t.key.toLowerCase()) {
1418
+ case "z":
1419
+ return t.preventDefault(), t.shiftKey ? this._undo.redo() : this._undo.undo(), this.requestUpdate(), this._dispatchUndoStateEvent(), !0;
1420
+ case "y":
1421
+ return t.preventDefault(), this._undo.redo(), this.requestUpdate(), this._dispatchUndoStateEvent(), !0;
1422
+ case "c":
1423
+ return t.preventDefault(), this._handleCopy(!1), !0;
1424
+ case "x":
1425
+ return t.preventDefault(), this._handleCopy(this.editable), !0;
1426
+ case "v":
1427
+ return t.preventDefault(), this.editable && this._handlePaste(), !0;
1428
+ default:
1429
+ return !1;
1430
+ }
1431
+ }
1432
+ _handleAltKey(t, e) {
1433
+ if (!t.altKey || !this._activeCell || t.key !== "ArrowLeft" && t.key !== "ArrowRight") return !1;
1434
+ t.preventDefault();
1435
+ const i = e[this._activeCell.col];
1436
+ if (!i) return !0;
1437
+ const s = this._columnWidths.get(i.key) ?? i.width ?? S, o = t.key === "ArrowRight" ? 20 : -20, r = i.minWidth ?? E, n = Math.max(r, s + o);
1438
+ return this._columnWidths.set(i.key, n), this.requestUpdate(), this.dispatchEvent(new CustomEvent("column-resize", {
1439
+ detail: { key: i.key, width: n, colIndex: this._activeCell.col },
1440
+ bubbles: !0,
1441
+ composed: !0
1442
+ })), !0;
1443
+ }
1444
+ _handleNavigation(t) {
1445
+ switch (t.key) {
1446
+ case "ArrowUp":
1447
+ return t.shiftKey ? this._selection.shiftMoveUp() : this._selection.moveUp(), !0;
1448
+ case "ArrowDown":
1449
+ return t.shiftKey ? this._selection.shiftMoveDown() : this._selection.moveDown(), !0;
1450
+ case "ArrowLeft":
1451
+ return t.shiftKey ? this._selection.shiftMoveLeft() : this._selection.moveLeft(), !0;
1452
+ case "ArrowRight":
1453
+ return t.shiftKey ? this._selection.shiftMoveRight() : this._selection.moveRight(), !0;
1454
+ case "Tab":
1455
+ return t.shiftKey ? this._selection.movePrev() : this._selection.moveNext(), !0;
1456
+ case "Home":
1457
+ return t.ctrlKey ? this._selection.moveToStart() : this._selection.moveToRowStart(), !0;
1458
+ case "End":
1459
+ return t.ctrlKey ? this._selection.moveToEnd() : this._selection.moveToRowEnd(), !0;
1460
+ case "Escape":
1461
+ return this._selection.clear(), !0;
1462
+ case "Delete":
1463
+ case "Backspace":
1464
+ return this.editable && this._handleDelete(), !0;
1465
+ default:
1466
+ return !1;
1467
+ }
1468
+ }
1469
+ // --- Clipboard ---
1470
+ async _handleCopy(t) {
1471
+ const e = this._selection.getEffectiveRange();
1472
+ if (!e) return;
1473
+ const i = this.visibleColumns, s = this._sortedIndices.map((r) => this.data[r]), o = et(s, i, e);
1474
+ try {
1475
+ await navigator.clipboard.writeText(o);
1476
+ } catch (r) {
1477
+ this.dispatchEvent(new CustomEvent("clipboard-error", {
1478
+ detail: { action: "copy", error: r },
1479
+ bubbles: !0,
1480
+ composed: !0
1481
+ }));
1482
+ }
1483
+ t && this._clearRange(e), this.dispatchEvent(new CustomEvent(t ? "clipboard-cut" : "clipboard-copy", {
1484
+ detail: { range: e, text: o },
1485
+ bubbles: !0,
1486
+ composed: !0
1487
+ }));
1488
+ }
1489
+ async _handlePaste() {
1490
+ if (!this._activeCell) return;
1491
+ const t = await this._readClipboardText();
1492
+ if (t == null) return;
1493
+ const e = it(t);
1494
+ if (e.length === 0) return;
1495
+ const i = this._expandRowsForPaste(this._activeCell.row, e.length), s = this._applyPasteData(this._activeCell, e);
1496
+ if (s.length > 0 || i.length > 0) {
1497
+ const o = i.length;
1498
+ this._undo.push({
1499
+ label: "paste",
1500
+ undo: () => {
1501
+ for (const r of s)
1502
+ this.data[r.row][r.key] = r.oldValue;
1503
+ o > 0 && this.data.splice(this.data.length - o, o), this.requestUpdate();
1504
+ },
1505
+ redo: () => {
1506
+ if (o > 0)
1507
+ for (let r = 0; r < o; r++)
1508
+ this.data.push(this._createEmptyRow());
1509
+ for (const r of s)
1510
+ this.data[r.row][r.key] = r.newValue;
1511
+ this.requestUpdate();
1512
+ }
1513
+ }), this._dispatchUndoStateEvent();
1514
+ }
1515
+ this.requestUpdate(), this.dispatchEvent(new CustomEvent("clipboard-paste", {
1516
+ detail: { changes: s, addedRows: i.length },
1517
+ bubbles: !0,
1518
+ composed: !0
1519
+ }));
1520
+ }
1521
+ async _readClipboardText() {
1522
+ try {
1523
+ return await navigator.clipboard.readText();
1524
+ } catch (t) {
1525
+ return this.dispatchEvent(new CustomEvent("clipboard-error", {
1526
+ detail: { action: "paste", error: t },
1527
+ bubbles: !0,
1528
+ composed: !0
1529
+ })), null;
1530
+ }
1531
+ }
1532
+ _expandRowsForPaste(t, e) {
1533
+ const i = [], s = t + e, o = this.maxRows > 0 ? this.maxRows : 1 / 0;
1534
+ for (; this.data.length < s && this.data.length < o; ) {
1535
+ const r = this.data.length;
1536
+ this.data.push(this._createEmptyRow()), i.push(r);
1537
+ }
1538
+ return i.length > 0 && this._recomputeView(), i;
1539
+ }
1540
+ _applyPasteData(t, e) {
1541
+ const i = this.visibleColumns, s = [];
1542
+ for (let o = 0; o < e.length; o++) {
1543
+ const r = t.row + o;
1544
+ if (r >= this._visibleRowCount) break;
1545
+ const n = this._toDataIndex(r);
1546
+ for (let l = 0; l < e[o].length; l++) {
1547
+ const a = t.col + l;
1548
+ if (a >= i.length) break;
1549
+ const d = i[a], f = this.data[n][d.key], h = A(e[o][l], d);
1550
+ this.data[n][d.key] = h, s.push({ row: n, col: a, key: d.key, oldValue: f, newValue: h });
1551
+ }
1552
+ }
1553
+ return s;
1554
+ }
1555
+ _handleDelete() {
1556
+ const t = this._selection.getEffectiveRange();
1557
+ t && this._clearRange(t);
1558
+ }
1559
+ _clearRange(t) {
1560
+ const e = this.visibleColumns, i = [];
1561
+ for (let s = t.startRow; s <= t.endRow; s++) {
1562
+ const o = this._toDataIndex(s);
1563
+ for (let r = t.startCol; r <= t.endCol; r++) {
1564
+ const n = e[r], l = this.data[o][n.key], a = n.type === "boolean" ? !1 : n.type === "number" ? 0 : "";
1565
+ this.data[o][n.key] = a, i.push({ dataRow: o, key: n.key, oldValue: l, clearValue: a });
1566
+ }
1567
+ }
1568
+ i.length > 0 && (this._undo.push({
1569
+ label: "clear",
1570
+ undo: () => {
1571
+ for (const s of i)
1572
+ this.data[s.dataRow][s.key] = s.oldValue;
1573
+ this.requestUpdate();
1574
+ },
1575
+ redo: () => {
1576
+ for (const s of i)
1577
+ this.data[s.dataRow][s.key] = s.clearValue;
1578
+ this.requestUpdate();
1579
+ }
1580
+ }), this._dispatchUndoStateEvent()), this.requestUpdate();
1581
+ }
1582
+ _scrollToActiveCell() {
1583
+ if (!this._activeCell) return;
1584
+ const t = this._activeCell.row * this.rowHeight + this.headerHeight, e = t + this.rowHeight;
1585
+ t < this.scrollTop + this.headerHeight ? this.scrollTop = t - this.headerHeight : e > this.scrollTop + this.clientHeight && (this.scrollTop = e - this.clientHeight);
1586
+ const i = this.visibleColumns, s = this._activeCell.col, o = this._colLeftOffsets[s] ?? 0, r = this._getColWidth(i[s]), n = o + r;
1587
+ o < this.scrollLeft ? this.scrollLeft = o : n > this.scrollLeft + this.clientWidth && (this.scrollLeft = n - this.clientWidth);
1588
+ }
1589
+ _dispatchSelectionEvent() {
1590
+ this.dispatchEvent(new CustomEvent("cell-select", {
1591
+ detail: this._activeCell ? { ...this._activeCell } : null,
1592
+ bubbles: !0,
1593
+ composed: !0
1594
+ }));
1595
+ }
1596
+ // --- Sorting ---
1597
+ _onHeaderClick(t, e) {
1598
+ const i = this.visibleColumns.indexOf(e);
1599
+ if (t.ctrlKey || t.metaKey) {
1600
+ this._selectColumn(i);
1601
+ return;
1602
+ }
1603
+ e.sortable !== !1 && (this._sortCriteria = G(this._sortCriteria, e.key, t.shiftKey), this.dataMode !== "server" && this._recomputeView(), this.requestUpdate(), this.dispatchEvent(new CustomEvent("sort-change", {
1604
+ detail: { criteria: [...this._sortCriteria] },
1605
+ bubbles: !0,
1606
+ composed: !0
1607
+ })));
1608
+ }
1609
+ _selectColumn(t) {
1610
+ var i;
1611
+ const e = this._visibleRowCount;
1612
+ e === 0 || t < 0 || (this._selection.setActive(0, t), this._selection.setActiveWithRange(e - 1, t), this._activeCell = { row: 0, col: t }, this.requestUpdate(), this.dispatchEvent(new CustomEvent("column-select", {
1613
+ detail: {
1614
+ colIndex: t,
1615
+ key: (i = this.visibleColumns[t]) == null ? void 0 : i.key,
1616
+ rowCount: e
1617
+ },
1618
+ bubbles: !0,
1619
+ composed: !0
1620
+ })));
1621
+ }
1622
+ /** Public API: select an entire column by index. */
1623
+ selectColumn(t) {
1624
+ this._selectColumn(t);
1625
+ }
1626
+ /** Calculate cumulative left offset for a left-pinned column */
1627
+ _getPinnedLeft(t) {
1628
+ const e = this.visibleColumns;
1629
+ let i = 0;
1630
+ this.selectable && (i += 36), this.showRowNumbers && (i += 48);
1631
+ for (let s = 0; s < t; s++)
1632
+ e[s].pinned === "left" && (i += this._getColWidth(e[s]));
1633
+ return i;
1634
+ }
1635
+ /** Calculate cumulative right offset for a right-pinned column */
1636
+ _getPinnedRight(t) {
1637
+ const e = this.visibleColumns;
1638
+ let i = 0;
1639
+ for (let s = e.length - 1; s > t; s--)
1640
+ e[s].pinned === "right" && (i += this._getColWidth(e[s]));
1641
+ return i;
1642
+ }
1643
+ _renderHeaderCell(t, e) {
1644
+ const i = t.sortable !== !1, s = this._sortCriteria.find((m) => m.key === t.key), o = this._sortCriteria.length > 1 ? this._sortCriteria.findIndex((m) => m.key === t.key) : -1, r = this._filters.some((m) => m.key === t.key), n = t.pinned === "left", l = t.pinned === "right", d = [
1645
+ "ft-header-cell",
1646
+ i ? "ft-sortable" : "",
1647
+ n || l ? "ft-pinned" : ""
1648
+ ].filter(Boolean).join(" "), f = i ? s ? s.direction === "asc" ? "ascending" : "descending" : "none" : void 0, h = this._getColWidth(t), g = this.headerHeight, p = this._colLeftOffsets[e] ?? 0;
1649
+ let c;
1650
+ return n ? c = `position: absolute; top: 0; left: ${this._scrollLeft + this._getPinnedLeft(e)}px; width: ${h}px; height: ${g}px; z-index: 4;` : l ? c = `position: absolute; top: 0; right: ${-this._scrollLeft + this._getPinnedRight(e)}px; width: ${h}px; height: ${g}px; z-index: 4;` : c = `left: ${p}px; width: ${h}px; height: ${g}px;`, u`
1651
+ <div class=${d}
1652
+ role="columnheader"
1653
+ data-col-index=${e}
1654
+ style=${c}
1655
+ aria-sort=${f ?? k}
1656
+ @click=${i ? (m) => this._onHeaderClick(m, t) : void 0}>
1657
+ <span>${t.header}</span>
1658
+ ${s ? u`<span class="ft-sort-indicator">${s.direction === "asc" ? "▲" : "▼"}</span>` : ""}
1659
+ ${o >= 0 ? u`<span class="ft-sort-order">${o + 1}</span>` : ""}
1660
+ ${this.showFilters ? u`
1661
+ <button class="ft-filter-btn ${r ? "ft-filter-active" : ""}"
1662
+ title="Filter"
1663
+ aria-label=${`Filter ${t.header}`}
1664
+ aria-expanded=${this._openFilterKey === t.key ? "true" : "false"}
1665
+ @click=${(m) => this._onFilterBtnClick(m, t)}>
1666
+ \u25BD
1667
+ </button>
1668
+ ` : ""}
1669
+ <div class="ft-resize-handle"
1670
+ @mousedown=${(m) => this._onResizeStart(m, e)}
1671
+ @dblclick=${(m) => this._onResizeAutoFit(m, e)}></div>
1672
+ </div>
1673
+ ${this._openFilterKey === t.key ? this._renderFilterDropdown(t) : ""}
1674
+ `;
1675
+ }
1676
+ // --- Filter UI ---
1677
+ _adjustFilterDropdown() {
1678
+ var s;
1679
+ if (!this._openFilterKey) return;
1680
+ const t = (s = this.shadowRoot) == null ? void 0 : s.querySelector(".ft-filter-dropdown");
1681
+ if (!t) return;
1682
+ t.style.top = "", t.style.bottom = "";
1683
+ const e = t.getBoundingClientRect(), i = window.innerHeight;
1684
+ e.bottom > i && (t.style.top = "auto", t.style.bottom = "100%");
1685
+ }
1686
+ _onFilterBtnClick(t, e) {
1687
+ t.preventDefault(), t.stopPropagation();
1688
+ const i = this._openFilterKey === e.key ? null : e.key;
1689
+ this._openFilterKey = i, i && requestAnimationFrame(() => {
1690
+ document.addEventListener("click", this._onDocumentClick, { once: !0 });
1691
+ });
1692
+ }
1693
+ _renderFilterDropdown(t) {
1694
+ const e = t.type ?? "text";
1695
+ return u`
1696
+ <div class="ft-filter-dropdown" @click=${(i) => i.stopPropagation()}>
1697
+ ${e === "boolean" ? this._renderBooleanFilter(t) : e === "number" ? this._renderNumberFilter(t) : e === "date" || e === "datetime" ? this._renderDateFilter(t) : this._renderTextFilter(t)}
1698
+ <div class="ft-filter-actions">
1699
+ <button class="ft-filter-clear" @click=${() => this._clearColumnFilter(t.key)}>Clear</button>
1700
+ </div>
1701
+ </div>
1702
+ `;
1703
+ }
1704
+ _renderTextFilter(t) {
1705
+ return u`
1706
+ <input class="ft-filter-input" type="text" placeholder="Search..."
1707
+ .value=${this._textFilterState.get(t.key) ?? ""}
1708
+ @input=${(e) => {
1709
+ const i = e.target.value;
1710
+ this._textFilterState.set(t.key, i), i ? this.setFilter(t.key, (s) => String(s ?? "").toLowerCase().includes(i.toLowerCase())) : this.removeFilter(t.key);
1711
+ }}
1712
+ @keydown=${(e) => {
1713
+ e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
1714
+ }}>
1715
+ `;
1716
+ }
1717
+ _renderNumberFilter(t) {
1718
+ const e = this._numberFilterState.get(t.key) ?? {};
1719
+ return u`
1720
+ <div class="ft-filter-range">
1721
+ <input class="ft-filter-input" type="number" placeholder="Min"
1722
+ .value=${e.min != null ? String(e.min) : ""}
1723
+ @input=${(i) => this._applyNumberFilter(t.key, i, "min")}
1724
+ @keydown=${(i) => {
1725
+ i.key === "Escape" && (this._openFilterKey = null), i.stopPropagation();
1726
+ }}>
1727
+ <input class="ft-filter-input" type="number" placeholder="Max"
1728
+ .value=${e.max != null ? String(e.max) : ""}
1729
+ @input=${(i) => this._applyNumberFilter(t.key, i, "max")}
1730
+ @keydown=${(i) => {
1731
+ i.key === "Escape" && (this._openFilterKey = null), i.stopPropagation();
1732
+ }}>
1733
+ </div>
1734
+ `;
1735
+ }
1736
+ _cellKey(t, e) {
1737
+ return `${t}:${e}`;
1738
+ }
1739
+ _markCellInvalid(t, e, i) {
1740
+ const s = this._cellKey(t, e), o = this._invalidCells.get(s);
1741
+ o && clearTimeout(o.timer);
1742
+ const r = setTimeout(() => {
1743
+ this._invalidCells.delete(s), this.requestUpdate();
1744
+ }, 3e3);
1745
+ this._invalidCells.set(s, { error: i, timer: r }), this.requestUpdate();
1746
+ }
1747
+ _isCellInvalid(t, e) {
1748
+ const i = this._invalidCells.get(this._cellKey(t, e));
1749
+ return i ? i.error : null;
1750
+ }
1751
+ _applyNumberFilter(t, e, i) {
1752
+ const s = e.target.value, o = this._numberFilterState.get(t) ?? {};
1753
+ s === "" ? delete o[i] : o[i] = Number(s), this._numberFilterState.set(t, o), o.min == null && o.max == null ? this.removeFilter(t) : this.setFilter(t, (r) => {
1754
+ const n = Number(r);
1755
+ return !(isNaN(n) || o.min != null && n < o.min || o.max != null && n > o.max);
1756
+ });
1757
+ }
1758
+ _renderDateFilter(t) {
1759
+ const e = t.type === "datetime" ? "datetime-local" : "date", i = this._dateFilterState.get(t.key) ?? {};
1760
+ return u`
1761
+ <div class="ft-filter-range">
1762
+ <input class="ft-filter-input" type=${e} placeholder="From"
1763
+ .value=${i.from ?? ""}
1764
+ @input=${(s) => this._applyDateFilter(t.key, s, "from")}
1765
+ @keydown=${(s) => {
1766
+ s.key === "Escape" && (this._openFilterKey = null), s.stopPropagation();
1767
+ }}>
1768
+ <input class="ft-filter-input" type=${e} placeholder="To"
1769
+ .value=${i.to ?? ""}
1770
+ @input=${(s) => this._applyDateFilter(t.key, s, "to")}
1771
+ @keydown=${(s) => {
1772
+ s.key === "Escape" && (this._openFilterKey = null), s.stopPropagation();
1773
+ }}>
1774
+ </div>
1775
+ `;
1776
+ }
1777
+ _applyDateFilter(t, e, i) {
1778
+ const s = e.target.value, o = this._dateFilterState.get(t) ?? {};
1779
+ s === "" ? delete o[i] : o[i] = s, this._dateFilterState.set(t, o), o.from == null && o.to == null ? this.removeFilter(t) : this.setFilter(t, (r) => {
1780
+ if (r == null || r === "") return !1;
1781
+ const n = r instanceof Date ? r : new Date(String(r));
1782
+ if (isNaN(n.getTime())) return !1;
1783
+ if (o.from) {
1784
+ const l = new Date(o.from);
1785
+ if (n < l) return !1;
1786
+ }
1787
+ if (o.to) {
1788
+ const l = new Date(o.to);
1789
+ if (o.to.length === 10 && l.setHours(23, 59, 59, 999), n > l) return !1;
1790
+ }
1791
+ return !0;
1792
+ });
1793
+ }
1794
+ _renderBooleanFilter(t) {
1795
+ return u`
1796
+ <select class="ft-filter-input"
1797
+ @change=${(e) => {
1798
+ const i = e.target.value;
1799
+ i === "all" ? this.removeFilter(t.key) : this.setFilter(t.key, (s) => !!s == (i === "true"));
1800
+ }}
1801
+ @keydown=${(e) => {
1802
+ e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
1803
+ }}>
1804
+ <option value="all">All</option>
1805
+ <option value="true">\u2714 True</option>
1806
+ <option value="false">\u2718 False</option>
1807
+ </select>
1808
+ `;
1809
+ }
1810
+ _clearColumnFilter(t) {
1811
+ this.removeFilter(t), this._textFilterState.delete(t), this._numberFilterState.delete(t), this._dateFilterState.delete(t), this._openFilterKey = null;
1812
+ }
1813
+ // --- Column Resize ---
1814
+ _onResizeAutoFit(t, e) {
1815
+ var a, d;
1816
+ t.preventDefault(), t.stopPropagation();
1817
+ const i = this.visibleColumns[e];
1818
+ if (!i) return;
1819
+ const s = (a = this.shadowRoot) == null ? void 0 : a.querySelectorAll(`.ft-cell[data-col-index="${e}"]`);
1820
+ let o = 0;
1821
+ const r = (d = this.shadowRoot) == null ? void 0 : d.querySelector(`.ft-header-cell[data-col-index="${e}"]`);
1822
+ if (r && (o = Math.max(o, r.scrollWidth)), s)
1823
+ for (const f of s)
1824
+ o = Math.max(o, f.scrollWidth);
1825
+ const n = i.minWidth ?? E, l = Math.max(n, o + 8);
1826
+ this._columnWidths.set(i.key, l), this.requestUpdate(), this.dispatchEvent(new CustomEvent("column-resize", {
1827
+ detail: { key: i.key, width: l, colIndex: e },
1828
+ bubbles: !0,
1829
+ composed: !0
1830
+ }));
1831
+ }
1832
+ _onResizeStart(t, e) {
1833
+ t.preventDefault(), t.stopPropagation();
1834
+ const i = this.visibleColumns[e], s = this._columnWidths.get(i.key) ?? i.width ?? S;
1835
+ this._resizing = { colIndex: e, startX: t.clientX, startWidth: s };
1836
+ const o = (l) => {
1837
+ if (!this._resizing) return;
1838
+ const a = l.clientX - this._resizing.startX, d = i.minWidth ?? E, f = Math.max(d, this._resizing.startWidth + a);
1839
+ this._columnWidths.set(i.key, f), this.requestUpdate();
1840
+ }, r = () => {
1841
+ document.removeEventListener("mousemove", o), document.removeEventListener("mouseup", n), this._resizeCleanup = null;
1842
+ }, n = () => {
1843
+ if (r(), this._resizing) {
1844
+ const l = this._columnWidths.get(i.key) ?? S;
1845
+ this.dispatchEvent(new CustomEvent("column-resize", {
1846
+ detail: { key: i.key, width: l, colIndex: e },
1847
+ bubbles: !0,
1848
+ composed: !0
1849
+ })), this._resizing = null;
1850
+ }
1851
+ };
1852
+ document.addEventListener("mousemove", o), document.addEventListener("mouseup", n), this._resizeCleanup = r;
1853
+ }
1854
+ // --- Rendering ---
1855
+ render() {
1856
+ const t = this.visibleColumns;
1857
+ if (t.length === 0)
1858
+ return u`<div class="ft-empty">No columns defined</div>`;
1859
+ const e = this.headerHeight, i = this._totalRowWidth, { start: s, end: o } = this.visibleColRange, r = [];
1860
+ for (let c = 0; c < t.length; c++)
1861
+ (t[c].pinned === "left" || t[c].pinned === "right") && (c < s || c >= o) && r.push(c);
1862
+ let n = 0;
1863
+ const l = this._scrollLeft, a = this.selectable ? u`<div class="ft-checkbox-header"
1864
+ style="position: absolute; top: 0; left: ${l + n}px; width: 36px; height: ${e}px; z-index: 4;">
1865
+ ${this._rowSelection.mode === "multi" ? u`
1866
+ <input type="checkbox"
1867
+ .checked=${this._rowSelection.isAllSelected}
1868
+ .indeterminate=${this._rowSelection.isSomeSelected}
1869
+ @change=${this._onSelectAllChange}>
1870
+ ` : ""}
1871
+ </div>` : "";
1872
+ this.selectable && (n += 36);
1873
+ const d = this.showRowNumbers ? u`<div class="ft-row-num-header"
1874
+ style="position: absolute; top: 0; left: ${l + n}px; width: 48px; height: ${e}px; z-index: 4;">#</div>` : "", f = [];
1875
+ for (const c of r)
1876
+ f.push(this._renderHeaderCell(t[c], c));
1877
+ for (let c = s; c < o; c++)
1878
+ f.push(this._renderHeaderCell(t[c], c));
1879
+ if (this.data.length === 0 || this._visibleRowCount === 0) {
1880
+ const c = this.data.length === 0 ? "No data" : "No matching data";
1881
+ return u`
1882
+ <div class="ft-header" role="row" style="width: ${i}px; height: ${e}px;">
1883
+ ${a}${d}
1884
+ ${f}
1885
+ </div>
1886
+ <div class="ft-empty">${c}</div>
1887
+ `;
1888
+ }
1889
+ const { start: h, end: g } = this.visibleRange, p = [];
1890
+ for (let c = h; c < g; c++)
1891
+ p.push(this._renderRow(c, s, o, r));
1892
+ return u`
1893
+ <div class="ft-header" role="row" style="width: ${i}px; height: ${e}px;">
1894
+ ${a}${d}
1895
+ ${f}
1896
+ </div>
1897
+ <div class="ft-body" style="height: ${this.totalBodyHeight}px; width: ${i}px;">
1898
+ ${p}
1899
+ </div>
1900
+ ${this.footerData ? this._renderFooter(s, o, r) : ""}
1901
+ `;
1902
+ }
1903
+ _onSelectAllChange(t) {
1904
+ t.target.checked ? this._rowSelection.selectAll() : this._rowSelection.deselectAll(), this._rowSelectionVersion++, this._dispatchRowSelectionEvent();
1905
+ }
1906
+ _onRowCheckboxChange(t, e) {
1907
+ t.stopPropagation(), this._rowSelection.toggle(e), this._rowSelectionVersion++, this._dispatchRowSelectionEvent();
1908
+ }
1909
+ _renderFooter(t, e, i) {
1910
+ if (!this.footerData) return "";
1911
+ const s = this.visibleColumns, o = this.rowHeight, r = this._totalRowWidth, n = this._scrollLeft;
1912
+ let l = 0;
1913
+ const a = this.selectable ? u`<div class="ft-footer-cell ft-checkbox-cell"
1914
+ style="position: absolute; top: 0; left: ${n + l}px; width: 36px; height: ${o}px; z-index: 2;"></div>` : "";
1915
+ this.selectable && (l += 36);
1916
+ const d = this.showRowNumbers ? u`<div class="ft-footer-cell ft-row-num"
1917
+ style="position: absolute; top: 0; left: ${n + l}px; width: 48px; height: ${o}px; z-index: 2;"></div>` : "", f = [];
1918
+ for (const h of i) {
1919
+ const g = s[h], p = this._getColWidth(g), c = g.pinned === "right" ? `position: absolute; top: 0; right: ${-n + this._getPinnedRight(h)}px; width: ${p}px; height: ${o}px; z-index: 2;` : `position: absolute; top: 0; left: ${n + this._getPinnedLeft(h)}px; width: ${p}px; height: ${o}px; z-index: 2;`;
1920
+ f.push(u`
1921
+ <div class="ft-footer-cell ft-pinned" style=${c}>
1922
+ ${this.footerData[g.key] ?? ""}</div>
1923
+ `);
1924
+ }
1925
+ for (let h = t; h < e; h++) {
1926
+ const g = s[h], p = this._getColWidth(g), c = this._colLeftOffsets[h] ?? 0, m = g.pinned === "left", y = g.pinned === "right", b = m || y;
1927
+ let x;
1928
+ m ? x = `position: absolute; top: 0; left: ${n + this._getPinnedLeft(h)}px; width: ${p}px; height: ${o}px; z-index: 2;` : y ? x = `position: absolute; top: 0; right: ${-n + this._getPinnedRight(h)}px; width: ${p}px; height: ${o}px; z-index: 2;` : x = `left: ${c}px; width: ${p}px; height: ${o}px;`, f.push(u`
1929
+ <div class="ft-footer-cell ${b ? "ft-pinned" : ""}" style=${x}>
1930
+ ${this.footerData[g.key] ?? ""}</div>
1931
+ `);
1932
+ }
1933
+ return u`
1934
+ <div class="ft-footer" role="row" style="width: ${r}px; height: ${o}px;">
1935
+ ${a}${d}
1936
+ ${f}
1937
+ </div>
1938
+ `;
1939
+ }
1940
+ _renderRow(t, e, i, s) {
1941
+ const o = this.visibleColumns, r = this._toDataIndex(t), n = this.data[r], l = t * this.rowHeight, a = this.rowHeight, d = this._totalRowWidth, f = t % 2 === 0 ? "ft-row-even" : "ft-row-odd", h = this.selectable && this._rowSelection.isSelected(t), g = this._scrollLeft;
1942
+ let p = 0;
1943
+ const c = this.selectable ? u`
1944
+ <div class="ft-checkbox-cell"
1945
+ style="position: absolute; top: 0; left: ${g + p}px; width: 36px; height: ${a}px; z-index: 2;">
1946
+ <input type="checkbox"
1947
+ .checked=${h}
1948
+ @change=${(b) => this._onRowCheckboxChange(b, t)}>
1949
+ </div>
1950
+ ` : "";
1951
+ this.selectable && (p += 36);
1952
+ const m = this.showRowNumbers ? u`
1953
+ <div class="ft-row-num"
1954
+ style="position: absolute; top: 0; left: ${g + p}px; width: 48px; height: ${a}px; z-index: 2;"
1955
+ @click=${() => this._onRowNumberClick(t)}>${r + 1}</div>
1956
+ ` : "", y = [];
1957
+ for (const b of s)
1958
+ y.push(this._renderCell(n, o[b], t, b));
1959
+ for (let b = e; b < i; b++)
1960
+ y.push(this._renderCell(n, o[b], t, b));
1961
+ return u`
1962
+ <div class="ft-row ${f} ${h ? "ft-row-selected" : ""}" role="row"
1963
+ style="top: ${l}px; height: ${a}px; width: ${d}px;">
1964
+ ${c}${m}
1965
+ ${y}
1966
+ </div>
1967
+ `;
1968
+ }
1969
+ _renderCell(t, e, i, s) {
1970
+ var x, R, D, F;
1971
+ const o = ((x = this._activeCell) == null ? void 0 : x.row) === i && ((R = this._activeCell) == null ? void 0 : R.col) === s, r = ((D = this._editingCell) == null ? void 0 : D.row) === i && ((F = this._editingCell) == null ? void 0 : F.col) === s, n = this._selection.isInRange(i, s), l = e.pinned === "left", a = e.pinned === "right", d = l || a, f = this._getColWidth(e), h = this.rowHeight, g = this._colLeftOffsets[s] ?? 0;
1972
+ let p;
1973
+ l ? p = `position: absolute; top: 0; left: ${this._scrollLeft + this._getPinnedLeft(s)}px; width: ${f}px; height: ${h}px; z-index: 2;` : a ? p = `position: absolute; top: 0; right: ${-this._scrollLeft + this._getPinnedRight(s)}px; width: ${f}px; height: ${h}px; z-index: 2;` : p = `left: ${g}px; width: ${f}px; height: ${h}px;`;
1974
+ const c = !this._isCellEditable(e);
1975
+ if (r)
1976
+ return u`
1977
+ <div class="ft-cell ft-editing ft-active ${d ? "ft-pinned" : ""}" role="gridcell"
1978
+ data-col-index=${s}
1979
+ aria-selected="true"
1980
+ aria-readonly=${c ? "true" : k}
1981
+ style=${p}>
1982
+ ${this._renderEditor(t, e)}
1983
+ </div>
1984
+ `;
1985
+ const m = o || n, y = this._isCellInvalid(i, s), b = [
1986
+ "ft-cell",
1987
+ `ft-type-${e.type ?? "text"}`,
1988
+ o ? "ft-active" : "",
1989
+ n ? "ft-selected" : "",
1990
+ d ? "ft-pinned" : "",
1991
+ y ? "ft-invalid" : ""
1992
+ ].filter(Boolean).join(" ");
1993
+ return u`
1994
+ <div class=${b}
1995
+ role="gridcell"
1996
+ data-col-index=${s}
1997
+ aria-selected=${m ? "true" : "false"}
1998
+ aria-readonly=${c ? "true" : k}
1999
+ aria-invalid=${y ? "true" : k}
2000
+ title=${y ?? k}
2001
+ style=${p}
2002
+ @click=${(N) => this._onCellClickEvent(N, i, s)}
2003
+ @dblclick=${() => this._onCellDblClick(i, s)}>
2004
+ ${H(t[e.key], t, e)}
2005
+ </div>
2006
+ `;
2007
+ }
2008
+ _renderEditor(t, e) {
2009
+ if (e.editor)
2010
+ return e.editor(t[e.key], t, e);
2011
+ const i = t[e.key], s = i == null ? "" : String(i);
2012
+ if (e.type === "number")
2013
+ return u`
2014
+ <input class="ft-editor ft-editor-number" type="number"
2015
+ .value=${s}
2016
+ @keydown=${this._onEditorKeyDown}
2017
+ @blur=${() => this._commitEdit()}>
2018
+ `;
2019
+ if (e.type === "date") {
2020
+ const o = this._toDateInputValue(i);
2021
+ return u`
2022
+ <input class="ft-editor" type="date"
2023
+ .value=${o}
2024
+ @keydown=${this._onEditorKeyDown}
2025
+ @blur=${() => this._commitEdit()}>
2026
+ `;
2027
+ }
2028
+ if (e.type === "datetime") {
2029
+ const o = this._toDateTimeInputValue(i);
2030
+ return u`
2031
+ <input class="ft-editor" type="datetime-local"
2032
+ .value=${o}
2033
+ @keydown=${this._onEditorKeyDown}
2034
+ @blur=${() => this._commitEdit()}>
2035
+ `;
2036
+ }
2037
+ return u`
2038
+ <input class="ft-editor" type="text"
2039
+ .value=${s}
2040
+ @keydown=${this._onEditorKeyDown}
2041
+ @blur=${() => this._commitEdit()}>
2042
+ `;
2043
+ }
2044
+ /** Convert value to YYYY-MM-DD for date input (local timezone) */
2045
+ _toDateInputValue(t) {
2046
+ if (!t) return "";
2047
+ const e = t instanceof Date ? t : new Date(String(t));
2048
+ if (isNaN(e.getTime())) return "";
2049
+ const i = e.getFullYear(), s = String(e.getMonth() + 1).padStart(2, "0"), o = String(e.getDate()).padStart(2, "0");
2050
+ return `${i}-${s}-${o}`;
2051
+ }
2052
+ /** Convert value to YYYY-MM-DDTHH:mm for datetime-local input (local timezone) */
2053
+ _toDateTimeInputValue(t) {
2054
+ if (!t) return "";
2055
+ const e = t instanceof Date ? t : new Date(String(t));
2056
+ if (isNaN(e.getTime())) return "";
2057
+ const i = e.getFullYear(), s = String(e.getMonth() + 1).padStart(2, "0"), o = String(e.getDate()).padStart(2, "0"), r = String(e.getHours()).padStart(2, "0"), n = String(e.getMinutes()).padStart(2, "0");
2058
+ return `${i}-${s}-${o}T${r}:${n}`;
2059
+ }
2060
+ };
2061
+ _.styles = K;
2062
+ v([
2063
+ w({ type: Array })
2064
+ ], _.prototype, "columns", 2);
2065
+ v([
2066
+ w({ type: Array, hasChanged: () => !0 })
2067
+ ], _.prototype, "data", 2);
2068
+ v([
2069
+ w({ type: Number, attribute: "row-height" })
2070
+ ], _.prototype, "rowHeight", 2);
2071
+ v([
2072
+ w({ type: Boolean, attribute: "show-row-numbers" })
2073
+ ], _.prototype, "showRowNumbers", 2);
2074
+ v([
2075
+ w({ type: String, reflect: !0 })
2076
+ ], _.prototype, "theme", 2);
2077
+ v([
2078
+ w({ type: Number, attribute: "max-rows" })
2079
+ ], _.prototype, "maxRows", 2);
2080
+ v([
2081
+ w({ type: Boolean })
2082
+ ], _.prototype, "editable", 2);
2083
+ v([
2084
+ w({ type: Boolean, attribute: "show-filters" })
2085
+ ], _.prototype, "showFilters", 2);
2086
+ v([
2087
+ w({ type: Boolean })
2088
+ ], _.prototype, "selectable", 2);
2089
+ v([
2090
+ w({ type: String, attribute: "selection-mode" })
2091
+ ], _.prototype, "selectionMode", 1);
2092
+ v([
2093
+ w({ type: String, attribute: "data-mode" })
2094
+ ], _.prototype, "dataMode", 2);
2095
+ v([
2096
+ w({ type: Object, attribute: "footer-data" })
2097
+ ], _.prototype, "footerData", 2);
2098
+ v([
2099
+ w({ type: Number, attribute: "max-undo-size" })
2100
+ ], _.prototype, "maxUndoSize", 1);
2101
+ v([
2102
+ C()
2103
+ ], _.prototype, "_scrollTop", 2);
2104
+ v([
2105
+ C()
2106
+ ], _.prototype, "_scrollLeft", 2);
2107
+ v([
2108
+ C()
2109
+ ], _.prototype, "_viewportHeight", 2);
2110
+ v([
2111
+ C()
2112
+ ], _.prototype, "_viewportWidth", 2);
2113
+ v([
2114
+ C()
2115
+ ], _.prototype, "_activeCell", 2);
2116
+ v([
2117
+ C()
2118
+ ], _.prototype, "_editingCell", 2);
2119
+ v([
2120
+ C()
2121
+ ], _.prototype, "_sortCriteria", 2);
2122
+ v([
2123
+ C()
2124
+ ], _.prototype, "_openFilterKey", 2);
2125
+ v([
2126
+ C()
2127
+ ], _.prototype, "_rowSelectionVersion", 2);
2128
+ _ = v([
2129
+ M("flex-table")
2130
+ ], _);
2131
+ export {
2132
+ _ as F,
2133
+ X as R,
2134
+ tt as U,
2135
+ z as e,
2136
+ H as r
2137
+ };