@iyulab/flex-table 0.10.2 → 0.12.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,2739 @@
1
+ import { LitElement as e, css as t, html as n, nothing as r } from "lit";
2
+ import { customElement as i, property as a, state as o } from "lit/decorators.js";
3
+ //#region src/styles/flex-table.styles.ts
4
+ var s = t`
5
+ /* --- Theme Variables (Light defaults) --- */
6
+ :host {
7
+ --ft-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
8
+ --ft-font-size: 14px;
9
+ --ft-border-color: #e0e0e0;
10
+ --ft-bg: #fff;
11
+ --ft-text-color: #202124;
12
+ --ft-header-bg: #f8f9fa;
13
+ --ft-header-hover-bg: #e8eaed;
14
+ --ft-header-text-color: #202124;
15
+ --ft-row-even-bg: #fff;
16
+ --ft-row-odd-bg: #fafafa;
17
+ --ft-row-hover-bg: #f0f4ff;
18
+ --ft-active-color: #1a73e8;
19
+ --ft-selection-bg: #e8f0fe;
20
+ --ft-bool-color: #2196f3;
21
+ --ft-sort-indicator-color: #5f6368;
22
+ --ft-editor-bg: #fff;
23
+ --ft-empty-color: #999;
24
+ }
25
+
26
+ /* --- Dark Theme (auto via prefers-color-scheme) --- */
27
+ @media (prefers-color-scheme: dark) {
28
+ :host(:not([theme="light"])) {
29
+ --ft-border-color: #3c4043;
30
+ --ft-bg: #1e1e1e;
31
+ --ft-text-color: #e8eaed;
32
+ --ft-header-bg: #292a2d;
33
+ --ft-header-hover-bg: #3c4043;
34
+ --ft-header-text-color: #e8eaed;
35
+ --ft-row-even-bg: #1e1e1e;
36
+ --ft-row-odd-bg: #252526;
37
+ --ft-row-hover-bg: #2a2d2e;
38
+ --ft-active-color: #4da3ff;
39
+ --ft-selection-bg: #264f78;
40
+ --ft-bool-color: #64b5f6;
41
+ --ft-sort-indicator-color: #9aa0a6;
42
+ --ft-editor-bg: #2d2d2d;
43
+ --ft-empty-color: #9aa0a6;
44
+ }
45
+ }
46
+
47
+ /* --- Force dark via attribute --- */
48
+ :host([theme="dark"]) {
49
+ --ft-border-color: #3c4043;
50
+ --ft-bg: #1e1e1e;
51
+ --ft-text-color: #e8eaed;
52
+ --ft-header-bg: #292a2d;
53
+ --ft-header-hover-bg: #3c4043;
54
+ --ft-header-text-color: #e8eaed;
55
+ --ft-row-even-bg: #1e1e1e;
56
+ --ft-row-odd-bg: #252526;
57
+ --ft-row-hover-bg: #2a2d2e;
58
+ --ft-active-color: #4da3ff;
59
+ --ft-selection-bg: #264f78;
60
+ --ft-bool-color: #64b5f6;
61
+ --ft-sort-indicator-color: #9aa0a6;
62
+ --ft-editor-bg: #2d2d2d;
63
+ --ft-empty-color: #9aa0a6;
64
+ }
65
+
66
+ /* --- Layout --- */
67
+ :host {
68
+ display: block;
69
+ position: relative;
70
+ overflow: auto;
71
+ font-family: var(--ft-font-family);
72
+ font-size: var(--ft-font-size);
73
+ color: var(--ft-text-color);
74
+ background: var(--ft-bg);
75
+ border: 1px solid var(--ft-border-color);
76
+ outline: none;
77
+ }
78
+
79
+ .ft-header {
80
+ display: block;
81
+ position: sticky;
82
+ top: 0;
83
+ z-index: 3;
84
+ }
85
+
86
+ .ft-header-cell {
87
+ position: absolute;
88
+ top: 0;
89
+ padding: 8px 12px;
90
+ background: var(--ft-header-bg);
91
+ color: var(--ft-header-text-color);
92
+ font-weight: 600;
93
+ user-select: none;
94
+ border-bottom: 2px solid var(--ft-border-color);
95
+ overflow: hidden;
96
+ text-overflow: ellipsis;
97
+ white-space: nowrap;
98
+ box-sizing: border-box;
99
+ display: flex;
100
+ align-items: center;
101
+ gap: 4px;
102
+ }
103
+
104
+ .ft-header-cell.ft-sortable { cursor: pointer; }
105
+ .ft-header-cell.ft-sortable:hover { background: var(--ft-header-hover-bg); }
106
+
107
+ .ft-resize-handle {
108
+ position: absolute;
109
+ right: 0; top: 0; bottom: 0;
110
+ width: 6px;
111
+ cursor: col-resize;
112
+ z-index: 3;
113
+ }
114
+
115
+ .ft-resize-handle:hover,
116
+ .ft-resize-handle.ft-resizing {
117
+ background: var(--ft-active-color);
118
+ opacity: 0.3;
119
+ }
120
+
121
+ .ft-header-cell.ft-col-dragging {
122
+ opacity: 0.5;
123
+ }
124
+
125
+ .ft-drop-indicator {
126
+ position: absolute;
127
+ top: 0;
128
+ bottom: 0;
129
+ width: 2px;
130
+ background: var(--ft-active-color);
131
+ pointer-events: none;
132
+ z-index: 5;
133
+ transform: translateX(-1px);
134
+ }
135
+
136
+ .ft-row-drop-indicator {
137
+ position: absolute;
138
+ left: 0;
139
+ height: 2px;
140
+ background: var(--ft-active-color);
141
+ pointer-events: none;
142
+ z-index: 5;
143
+ transform: translateY(-1px);
144
+ }
145
+
146
+ .ft-fill-handle {
147
+ position: absolute;
148
+ width: 8px;
149
+ height: 8px;
150
+ background: var(--ft-active-color);
151
+ cursor: crosshair;
152
+ z-index: 6;
153
+ border: 1px solid white;
154
+ }
155
+
156
+ .ft-fill-preview {
157
+ position: absolute;
158
+ border: 2px dashed var(--ft-active-color);
159
+ pointer-events: none;
160
+ z-index: 4;
161
+ box-sizing: border-box;
162
+ }
163
+
164
+ .ft-sort-indicator {
165
+ flex-shrink: 0;
166
+ font-size: 12px;
167
+ color: var(--ft-sort-indicator-color);
168
+ }
169
+
170
+ .ft-sort-order {
171
+ font-size: 10px;
172
+ color: var(--ft-sort-indicator-color);
173
+ }
174
+
175
+ .ft-body { position: relative; }
176
+
177
+ .ft-row {
178
+ display: block;
179
+ position: absolute;
180
+ left: 0;
181
+ }
182
+
183
+ .ft-cell {
184
+ position: absolute;
185
+ top: 0;
186
+ padding: 6px 12px;
187
+ border-bottom: 1px solid var(--ft-border-color);
188
+ overflow: hidden;
189
+ text-overflow: ellipsis;
190
+ white-space: nowrap;
191
+ box-sizing: border-box;
192
+ cursor: default;
193
+ }
194
+
195
+ .ft-row-even .ft-cell { background: var(--ft-row-even-bg); }
196
+ .ft-row-odd .ft-cell { background: var(--ft-row-odd-bg); }
197
+ .ft-row:hover .ft-cell { background: var(--ft-row-hover-bg); }
198
+
199
+ .ft-cell.ft-active {
200
+ outline: 2px solid var(--ft-active-color);
201
+ outline-offset: -2px;
202
+ z-index: 1;
203
+ }
204
+
205
+ .ft-cell.ft-selected {
206
+ background: var(--ft-selection-bg) !important;
207
+ }
208
+
209
+ .ft-cell.ft-invalid {
210
+ outline: 2px solid #d93025;
211
+ outline-offset: -2px;
212
+ background: rgba(217, 48, 37, 0.08);
213
+ }
214
+
215
+ .ft-cell.ft-editing { padding: 0; overflow: visible; }
216
+
217
+ .ft-editor {
218
+ width: 100%; height: 100%;
219
+ border: none; outline: none;
220
+ padding: 6px 12px;
221
+ font: inherit;
222
+ color: var(--ft-text-color);
223
+ background: var(--ft-editor-bg);
224
+ box-sizing: border-box;
225
+ }
226
+ .ft-editor:focus {
227
+ outline: 2px solid var(--ft-active-color);
228
+ outline-offset: -2px;
229
+ }
230
+
231
+ .ft-editor-number { text-align: right; }
232
+
233
+ select.ft-editor {
234
+ cursor: pointer;
235
+ padding: 4px 6px;
236
+ appearance: auto;
237
+ }
238
+
239
+ .ft-cell.ft-type-number {
240
+ text-align: right;
241
+ font-variant-numeric: tabular-nums;
242
+ }
243
+
244
+ .ft-cell.ft-type-boolean { text-align: center; }
245
+ .ft-bool { color: var(--ft-bool-color); }
246
+
247
+ .ft-empty {
248
+ padding: 24px;
249
+ text-align: center;
250
+ color: var(--ft-empty-color);
251
+ }
252
+
253
+ .ft-row-num-header,
254
+ .ft-row-num {
255
+ position: absolute;
256
+ top: 0;
257
+ display: flex;
258
+ align-items: center;
259
+ justify-content: center;
260
+ color: var(--ft-sort-indicator-color);
261
+ font-size: 12px;
262
+ padding: 6px 4px;
263
+ box-sizing: border-box;
264
+ user-select: none;
265
+ }
266
+
267
+ .ft-row-num-header {
268
+ background: var(--ft-header-bg);
269
+ font-weight: 600;
270
+ border-bottom: 2px solid var(--ft-border-color);
271
+ padding: 8px 4px;
272
+ }
273
+
274
+ .ft-row-num {
275
+ border-bottom: 1px solid var(--ft-border-color);
276
+ cursor: pointer;
277
+ background: var(--ft-row-even-bg);
278
+ }
279
+
280
+ .ft-row-odd .ft-row-num { background: var(--ft-row-odd-bg); }
281
+ .ft-row:hover .ft-row-num { background: var(--ft-row-hover-bg); }
282
+
283
+ .ft-row-num:hover {
284
+ background: var(--ft-header-hover-bg);
285
+ }
286
+
287
+ /* --- Pinned Columns --- */
288
+
289
+ .ft-pinned {
290
+ background: var(--ft-bg);
291
+ }
292
+
293
+ .ft-header-cell.ft-pinned {
294
+ background: var(--ft-header-bg);
295
+ }
296
+
297
+ .ft-row-even .ft-cell.ft-pinned { background: var(--ft-row-even-bg); }
298
+ .ft-row-odd .ft-cell.ft-pinned { background: var(--ft-row-odd-bg); }
299
+ .ft-row:hover .ft-cell.ft-pinned { background: var(--ft-row-hover-bg); }
300
+ .ft-cell.ft-pinned.ft-selected { background: var(--ft-selection-bg) !important; }
301
+
302
+ /* --- Filter UI --- */
303
+
304
+ .ft-filter-btn {
305
+ all: unset;
306
+ cursor: pointer;
307
+ font-size: 10px;
308
+ color: var(--ft-sort-indicator-color);
309
+ padding: 0 2px;
310
+ margin-left: auto;
311
+ opacity: 0.7;
312
+ flex-shrink: 0;
313
+ }
314
+
315
+ .ft-filter-btn:hover { opacity: 1; }
316
+
317
+ .ft-filter-btn.ft-filter-active {
318
+ color: var(--ft-active-color);
319
+ opacity: 1;
320
+ }
321
+
322
+ .ft-filter-dropdown {
323
+ position: absolute;
324
+ top: 100%;
325
+ left: 0;
326
+ min-width: 160px;
327
+ background: var(--ft-bg);
328
+ border: 1px solid var(--ft-border-color);
329
+ border-radius: 4px;
330
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
331
+ padding: 8px;
332
+ z-index: 10;
333
+ box-sizing: border-box;
334
+ }
335
+
336
+ .ft-filter-input {
337
+ width: 100%;
338
+ padding: 4px 8px;
339
+ font: inherit;
340
+ font-size: 13px;
341
+ border: 1px solid var(--ft-border-color);
342
+ border-radius: 3px;
343
+ color: var(--ft-text-color);
344
+ background: var(--ft-editor-bg);
345
+ box-sizing: border-box;
346
+ }
347
+
348
+ .ft-filter-input:focus {
349
+ outline: 1px solid var(--ft-active-color);
350
+ }
351
+
352
+ .ft-filter-range {
353
+ display: flex;
354
+ gap: 4px;
355
+ }
356
+
357
+ .ft-filter-range .ft-filter-input {
358
+ width: 50%;
359
+ }
360
+
361
+ .ft-filter-actions {
362
+ margin-top: 6px;
363
+ text-align: right;
364
+ }
365
+
366
+ .ft-filter-clear {
367
+ all: unset;
368
+ cursor: pointer;
369
+ font-size: 12px;
370
+ color: var(--ft-sort-indicator-color);
371
+ padding: 2px 8px;
372
+ border-radius: 3px;
373
+ }
374
+
375
+ .ft-filter-clear:hover {
376
+ background: var(--ft-header-hover-bg);
377
+ color: var(--ft-text-color);
378
+ }
379
+
380
+ /* --- Row Selection (Checkbox) --- */
381
+
382
+ .ft-checkbox-header,
383
+ .ft-checkbox-cell {
384
+ position: absolute;
385
+ top: 0;
386
+ display: flex;
387
+ align-items: center;
388
+ justify-content: center;
389
+ padding: 0 4px;
390
+ box-sizing: border-box;
391
+ user-select: none;
392
+ }
393
+
394
+ .ft-checkbox-header {
395
+ background: var(--ft-header-bg);
396
+ border-bottom: 2px solid var(--ft-border-color);
397
+ }
398
+
399
+ .ft-checkbox-cell {
400
+ border-bottom: 1px solid var(--ft-border-color);
401
+ background: var(--ft-row-even-bg);
402
+ }
403
+
404
+ .ft-row-odd .ft-checkbox-cell { background: var(--ft-row-odd-bg); }
405
+ .ft-row:hover .ft-checkbox-cell { background: var(--ft-row-hover-bg); }
406
+ .ft-row-selected .ft-checkbox-cell { background: var(--ft-selection-bg); }
407
+ .ft-row-selected .ft-cell { background: var(--ft-selection-bg) !important; }
408
+ .ft-row-selected .ft-row-num { background: var(--ft-selection-bg); }
409
+
410
+ .ft-checkbox-header input[type="checkbox"],
411
+ .ft-checkbox-cell input[type="checkbox"] {
412
+ width: 16px;
413
+ height: 16px;
414
+ cursor: pointer;
415
+ accent-color: var(--ft-active-color);
416
+ }
417
+
418
+ /* --- Footer Row --- */
419
+
420
+ .ft-footer {
421
+ display: block;
422
+ position: sticky;
423
+ bottom: 0;
424
+ z-index: 2;
425
+ background: var(--ft-header-bg);
426
+ border-top: 2px solid var(--ft-border-color);
427
+ }
428
+
429
+ .ft-footer-cell {
430
+ position: absolute;
431
+ top: 0;
432
+ padding: 6px 12px;
433
+ font-weight: 600;
434
+ font-size: 13px;
435
+ color: var(--ft-header-text-color);
436
+ overflow: hidden;
437
+ text-overflow: ellipsis;
438
+ white-space: nowrap;
439
+ box-sizing: border-box;
440
+ }
441
+
442
+ /* Find / Replace panel */
443
+ .ft-find-panel {
444
+ position: sticky;
445
+ top: 0;
446
+ right: 0;
447
+ z-index: 20;
448
+ background: var(--ft-header-bg);
449
+ border-bottom: 1px solid var(--ft-border-color);
450
+ padding: 4px 8px;
451
+ display: flex;
452
+ flex-direction: column;
453
+ gap: 4px;
454
+ box-shadow: 0 2px 8px rgba(0,0,0,0.15);
455
+ }
456
+
457
+ .ft-find-row {
458
+ display: flex;
459
+ align-items: center;
460
+ gap: 4px;
461
+ }
462
+
463
+ .ft-find-input, .ft-find-replace-input {
464
+ flex: 1;
465
+ min-width: 120px;
466
+ padding: 3px 6px;
467
+ border: 1px solid var(--ft-border-color);
468
+ border-radius: 3px;
469
+ font: inherit;
470
+ font-size: 13px;
471
+ background: var(--ft-editor-bg);
472
+ color: var(--ft-text-color);
473
+ }
474
+
475
+ .ft-find-input:focus, .ft-find-replace-input:focus {
476
+ outline: 2px solid var(--ft-active-color);
477
+ outline-offset: -1px;
478
+ }
479
+
480
+ .ft-find-count {
481
+ font-size: 12px;
482
+ color: var(--ft-sort-indicator-color);
483
+ min-width: 60px;
484
+ text-align: center;
485
+ }
486
+
487
+ .ft-find-panel button {
488
+ padding: 2px 8px;
489
+ border: 1px solid var(--ft-border-color);
490
+ border-radius: 3px;
491
+ cursor: pointer;
492
+ font-size: 12px;
493
+ background: var(--ft-header-bg);
494
+ color: var(--ft-text-color);
495
+ }
496
+
497
+ .ft-find-panel button:hover:not(:disabled) {
498
+ background: var(--ft-header-hover-bg);
499
+ }
500
+
501
+ .ft-find-panel button:disabled {
502
+ opacity: 0.4;
503
+ cursor: default;
504
+ }
505
+
506
+ .ft-find-panel label {
507
+ display: flex;
508
+ align-items: center;
509
+ gap: 2px;
510
+ font-size: 12px;
511
+ cursor: pointer;
512
+ user-select: none;
513
+ }
514
+
515
+ /* Find highlight */
516
+ .ft-cell.ft-find-match {
517
+ background: rgba(255, 200, 0, 0.25) !important;
518
+ }
519
+
520
+ .ft-cell.ft-find-current {
521
+ background: rgba(255, 160, 0, 0.5) !important;
522
+ outline: 2px solid orange;
523
+ outline-offset: -2px;
524
+ }
525
+ `;
526
+ //#endregion
527
+ //#region src/renderers/cell-renderer.ts
528
+ function c(e, t, n) {
529
+ return n.renderer ? n.renderer(e, t, n) : l(e, n);
530
+ }
531
+ function l(e, t) {
532
+ if (e == null) return "";
533
+ switch (t.type) {
534
+ case "number": return d(e);
535
+ case "boolean": return n`<span class="ft-bool">${e ? "✔" : ""}</span>`;
536
+ case "date": return f(e);
537
+ case "datetime": return p(e);
538
+ case "select": return u(e, t);
539
+ default: return String(e);
540
+ }
541
+ }
542
+ function u(e, t) {
543
+ if (!t.options || t.options.length === 0 || typeof t.options[0] == "string") return e == null ? "" : String(e);
544
+ let n = t.options.find((t) => t.value === e);
545
+ return n ? n.label : e == null ? "" : String(e);
546
+ }
547
+ function d(e) {
548
+ return typeof e == "number" ? Number.isInteger(e) ? e.toLocaleString() : e.toLocaleString(void 0, { minimumFractionDigits: 1 }) : String(e);
549
+ }
550
+ function f(e) {
551
+ if (e instanceof Date) return e.toLocaleDateString();
552
+ if (typeof e == "string") {
553
+ let t = new Date(e);
554
+ return isNaN(t.getTime()) ? e : t.toLocaleDateString();
555
+ }
556
+ return String(e);
557
+ }
558
+ function p(e) {
559
+ if (e instanceof Date) return e.toLocaleString();
560
+ if (typeof e == "string") {
561
+ let t = new Date(e);
562
+ return isNaN(t.getTime()) ? e : t.toLocaleString();
563
+ }
564
+ return String(e);
565
+ }
566
+ //#endregion
567
+ //#region src/core/selection.ts
568
+ function m(e) {
569
+ return {
570
+ startRow: Math.min(e.startRow, e.endRow),
571
+ startCol: Math.min(e.startCol, e.endCol),
572
+ endRow: Math.max(e.startRow, e.endRow),
573
+ endCol: Math.max(e.startCol, e.endCol)
574
+ };
575
+ }
576
+ var h = class {
577
+ constructor() {
578
+ this.activeCell = null, this.rangeAnchor = null, this.range = null, this.extraRanges = [], this._rowCount = 0, this._colCount = 0;
579
+ }
580
+ setDimensions(e, t) {
581
+ this._rowCount = e, this._colCount = t;
582
+ }
583
+ setActive(e, t) {
584
+ return e < 0 || e >= this._rowCount || t < 0 || t >= this._colCount ? this.activeCell : (this.activeCell = {
585
+ row: e,
586
+ col: t
587
+ }, this.rangeAnchor = null, this.range = null, this.extraRanges = [], this.activeCell);
588
+ }
589
+ toggleCell(e, t) {
590
+ if (e < 0 || e >= this._rowCount || t < 0 || t >= this._colCount) return;
591
+ let n = this.extraRanges.findIndex((n) => n.startRow === e && n.endRow === e && n.startCol === t && n.endCol === t);
592
+ n >= 0 ? this.extraRanges.splice(n, 1) : this.extraRanges.push({
593
+ startRow: e,
594
+ startCol: t,
595
+ endRow: e,
596
+ endCol: t
597
+ });
598
+ }
599
+ setActiveWithRange(e, t) {
600
+ return e < 0 || e >= this._rowCount || t < 0 || t >= this._colCount ? this.activeCell : (!this.rangeAnchor && this.activeCell && (this.rangeAnchor = { ...this.activeCell }), this.activeCell = {
601
+ row: e,
602
+ col: t
603
+ }, this.rangeAnchor && (this.range = m({
604
+ startRow: this.rangeAnchor.row,
605
+ startCol: this.rangeAnchor.col,
606
+ endRow: e,
607
+ endCol: t
608
+ })), this.activeCell);
609
+ }
610
+ isInRange(e, t) {
611
+ if (this.range) {
612
+ let n = this.range;
613
+ if (e >= n.startRow && e <= n.endRow && t >= n.startCol && t <= n.endCol) return !0;
614
+ }
615
+ return this.extraRanges.some((n) => e >= n.startRow && e <= n.endRow && t >= n.startCol && t <= n.endCol);
616
+ }
617
+ getEffectiveRange() {
618
+ return this.range ? this.range : this.activeCell ? {
619
+ startRow: this.activeCell.row,
620
+ startCol: this.activeCell.col,
621
+ endRow: this.activeCell.row,
622
+ endCol: this.activeCell.col
623
+ } : null;
624
+ }
625
+ clear() {
626
+ this.activeCell = null, this.rangeAnchor = null, this.range = null, this.extraRanges = [];
627
+ }
628
+ moveUp() {
629
+ return this.activeCell ? this.setActive(this.activeCell.row - 1, this.activeCell.col) : null;
630
+ }
631
+ moveDown() {
632
+ return this.activeCell ? this.setActive(this.activeCell.row + 1, this.activeCell.col) : null;
633
+ }
634
+ moveLeft() {
635
+ return this.activeCell ? this.setActive(this.activeCell.row, this.activeCell.col - 1) : null;
636
+ }
637
+ moveRight() {
638
+ return this.activeCell ? this.setActive(this.activeCell.row, this.activeCell.col + 1) : null;
639
+ }
640
+ moveNext() {
641
+ if (!this.activeCell) return null;
642
+ let { row: e, col: t } = this.activeCell;
643
+ return t++, t >= this._colCount && (t = 0, e++), e >= this._rowCount ? this.activeCell : this.setActive(e, t);
644
+ }
645
+ movePrev() {
646
+ if (!this.activeCell) return null;
647
+ let { row: e, col: t } = this.activeCell;
648
+ return t--, t < 0 && (t = this._colCount - 1, e--), e < 0 ? this.activeCell : this.setActive(e, t);
649
+ }
650
+ moveToStart() {
651
+ return this.setActive(0, 0);
652
+ }
653
+ moveToEnd() {
654
+ return this.setActive(this._rowCount - 1, this._colCount - 1);
655
+ }
656
+ moveToRowStart() {
657
+ return this.activeCell ? this.setActive(this.activeCell.row, 0) : null;
658
+ }
659
+ moveToRowEnd() {
660
+ return this.activeCell ? this.setActive(this.activeCell.row, this._colCount - 1) : null;
661
+ }
662
+ shiftMoveUp() {
663
+ return this.activeCell ? this.setActiveWithRange(this.activeCell.row - 1, this.activeCell.col) : null;
664
+ }
665
+ shiftMoveDown() {
666
+ return this.activeCell ? this.setActiveWithRange(this.activeCell.row + 1, this.activeCell.col) : null;
667
+ }
668
+ shiftMoveLeft() {
669
+ return this.activeCell ? this.setActiveWithRange(this.activeCell.row, this.activeCell.col - 1) : null;
670
+ }
671
+ shiftMoveRight() {
672
+ return this.activeCell ? this.setActiveWithRange(this.activeCell.row, this.activeCell.col + 1) : null;
673
+ }
674
+ }, g = class {
675
+ constructor() {
676
+ this.current = null;
677
+ }
678
+ start(e, t) {
679
+ this.current = {
680
+ position: e,
681
+ originalValue: t
682
+ };
683
+ }
684
+ isEditing(e, t) {
685
+ return this.current !== null && this.current.position.row === e && this.current.position.col === t;
686
+ }
687
+ cancel() {
688
+ let e = this.current;
689
+ return this.current = null, e;
690
+ }
691
+ commit() {
692
+ let e = this.current;
693
+ return this.current = null, e;
694
+ }
695
+ }, _ = class {
696
+ constructor() {
697
+ this._selected = /* @__PURE__ */ new Set(), this._mode = "multi", this._rowCount = 0;
698
+ }
699
+ get mode() {
700
+ return this._mode;
701
+ }
702
+ set mode(e) {
703
+ if (this._mode = e, e === "single" && this._selected.size > 1) {
704
+ let e = this._selected.values().next().value;
705
+ this._selected.clear(), e !== void 0 && this._selected.add(e);
706
+ }
707
+ }
708
+ setRowCount(e) {
709
+ this._rowCount = e;
710
+ for (let t of this._selected) t >= e && this._selected.delete(t);
711
+ }
712
+ get selectedIndices() {
713
+ return [...this._selected].sort((e, t) => e - t);
714
+ }
715
+ get selectedCount() {
716
+ return this._selected.size;
717
+ }
718
+ get isAllSelected() {
719
+ return this._rowCount > 0 && this._selected.size === this._rowCount;
720
+ }
721
+ get isSomeSelected() {
722
+ return this._selected.size > 0 && this._selected.size < this._rowCount;
723
+ }
724
+ isSelected(e) {
725
+ return this._selected.has(e);
726
+ }
727
+ toggle(e) {
728
+ 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);
729
+ }
730
+ select(e) {
731
+ this._mode === "single" && this._selected.clear(), this._selected.add(e);
732
+ }
733
+ deselect(e) {
734
+ this._selected.delete(e);
735
+ }
736
+ selectAll() {
737
+ if (this._mode !== "single") {
738
+ this._selected.clear();
739
+ for (let e = 0; e < this._rowCount; e++) this._selected.add(e);
740
+ }
741
+ }
742
+ deselectAll() {
743
+ this._selected.clear();
744
+ }
745
+ };
746
+ //#endregion
747
+ //#region src/core/sorting.ts
748
+ function v(e, t, n) {
749
+ let r = Array.from({ length: e.length }, (e, t) => t);
750
+ if (t.length === 0) return r;
751
+ let i = /* @__PURE__ */ new Map();
752
+ for (let e of n) i.set(e.key, e.type ?? "text");
753
+ return r.sort((n, r) => {
754
+ for (let { key: a, direction: o } of t) {
755
+ let t = e[n][a], s = e[r][a], c = t == null, l = s == null;
756
+ if (c && l) continue;
757
+ if (c) return 1;
758
+ if (l) return -1;
759
+ let u = y(t, s, i.get(a) ?? "text");
760
+ if (u !== 0) return o === "asc" ? u : -u;
761
+ }
762
+ return n - r;
763
+ }), r;
764
+ }
765
+ function y(e, t, n) {
766
+ switch (n) {
767
+ case "number": {
768
+ let n = Number(e), r = Number(t);
769
+ return isNaN(n) && isNaN(r) ? 0 : isNaN(n) ? 1 : isNaN(r) ? -1 : n - r;
770
+ }
771
+ case "boolean": return !!e - +!!t;
772
+ case "date":
773
+ case "datetime": {
774
+ let n = new Date(e).getTime(), r = new Date(t).getTime();
775
+ return (isNaN(n) ? 0 : n) - (isNaN(r) ? 0 : r);
776
+ }
777
+ default: return String(e).localeCompare(String(t));
778
+ }
779
+ }
780
+ function b(e, t, n) {
781
+ let r = e.find((e) => e.key === t);
782
+ return n ? r ? r.direction === "asc" ? e.map((e) => e.key === t ? {
783
+ ...e,
784
+ direction: "desc"
785
+ } : e) : e.filter((e) => e.key !== t) : [...e, {
786
+ key: t,
787
+ direction: "asc"
788
+ }] : r ? r.direction === "asc" ? [{
789
+ key: t,
790
+ direction: "desc"
791
+ }] : [] : [{
792
+ key: t,
793
+ direction: "asc"
794
+ }];
795
+ }
796
+ //#endregion
797
+ //#region src/core/filtering.ts
798
+ function x(e, t, n) {
799
+ if (t.length === 0) return Array.from({ length: e.length }, (e, t) => t);
800
+ let r = [];
801
+ for (let i = 0; i < e.length; i++) {
802
+ let a = e[i], o = !0;
803
+ for (let e of t) try {
804
+ if (!e.predicate(a[e.key], a)) {
805
+ o = !1;
806
+ break;
807
+ }
808
+ } catch (t) {
809
+ console.warn("Filter predicate error for key \"%s\":", e.key, t), n && n(t, a, e);
810
+ }
811
+ o && r.push(i);
812
+ }
813
+ return r;
814
+ }
815
+ //#endregion
816
+ //#region src/core/undo.ts
817
+ var S = 100, C = class {
818
+ constructor() {
819
+ this._undoStack = [], this._redoStack = [], this._maxSize = S;
820
+ }
821
+ get maxSize() {
822
+ return this._maxSize;
823
+ }
824
+ set maxSize(e) {
825
+ for (this._maxSize = Math.max(1, e); this._undoStack.length > this._maxSize;) this._undoStack.shift();
826
+ }
827
+ get canUndo() {
828
+ return this._undoStack.length > 0;
829
+ }
830
+ get canRedo() {
831
+ return this._redoStack.length > 0;
832
+ }
833
+ get undoCount() {
834
+ return this._undoStack.length;
835
+ }
836
+ get redoCount() {
837
+ return this._redoStack.length;
838
+ }
839
+ push(e) {
840
+ this._undoStack.push(e), this._undoStack.length > this._maxSize && this._undoStack.shift(), this._redoStack.length = 0;
841
+ }
842
+ undo() {
843
+ let e = this._undoStack.pop();
844
+ return e ? (e.undo(), this._redoStack.push(e), e.label) : null;
845
+ }
846
+ redo() {
847
+ let e = this._redoStack.pop();
848
+ return e ? (e.redo(), this._undoStack.push(e), e.label) : null;
849
+ }
850
+ clear() {
851
+ this._undoStack.length = 0, this._redoStack.length = 0;
852
+ }
853
+ };
854
+ //#endregion
855
+ //#region src/clipboard/clipboard.ts
856
+ function w(e, t, n) {
857
+ let r = [];
858
+ for (let i = n.startRow; i <= n.endRow; i++) {
859
+ let a = e[i], o = [];
860
+ for (let e = n.startCol; e <= n.endCol; e++) {
861
+ let n = a[t[e].key];
862
+ o.push(n == null ? "" : String(n));
863
+ }
864
+ r.push(o.join(" "));
865
+ }
866
+ return r.join("\n");
867
+ }
868
+ function T(e) {
869
+ let t = e.replace(/\r\n/g, "\n").replace(/\r/g, "\n"), n = [], r = [], i = 0, a = t.length;
870
+ for (; i <= a;) {
871
+ if (i === a) {
872
+ (r.length > 0 || n.length > 0) && n.push(r);
873
+ break;
874
+ }
875
+ if (t[i] === "\"") {
876
+ let e = "";
877
+ for (i++; i < a;) if (t[i] === "\"") if (i + 1 < a && t[i + 1] === "\"") e += "\"", i += 2;
878
+ else {
879
+ i++;
880
+ break;
881
+ }
882
+ else e += t[i], i++;
883
+ r.push(e), i < a && t[i] === " " ? i++ : i < a && t[i] === "\n" && (n.push(r), r = [], i++);
884
+ } else {
885
+ let e = "";
886
+ for (; i < a && t[i] !== " " && t[i] !== "\n";) e += t[i], i++;
887
+ r.push(e), i < a && t[i] === " " ? i++ : i < a && t[i] === "\n" && (n.push(r), r = [], i++);
888
+ }
889
+ }
890
+ for (; n.length > 0;) {
891
+ let e = n[n.length - 1];
892
+ if (e.length === 0 || e.length === 1 && e[0] === "") n.pop();
893
+ else break;
894
+ }
895
+ return n;
896
+ }
897
+ function E(e, t) {
898
+ if (e === "") return null;
899
+ switch (t.type) {
900
+ case "number": {
901
+ let t = Number(e);
902
+ return isNaN(t) ? e : t;
903
+ }
904
+ case "boolean": return e.toLowerCase() === "true" || e === "1";
905
+ default: return e;
906
+ }
907
+ }
908
+ //#endregion
909
+ //#region src/export/export.ts
910
+ function D(e, t, n) {
911
+ switch (n) {
912
+ case "csv": return k(e, t, ",");
913
+ case "tsv": return k(e, t, " ");
914
+ case "json": return j(e, t);
915
+ }
916
+ }
917
+ function O(e, t) {
918
+ return e == null ? "" : (t.type === "date" || t.type === "datetime") && e instanceof Date ? e.toISOString() : String(e);
919
+ }
920
+ function k(e, t, n) {
921
+ return [t.map((e) => A(e.header, n)).join(n), ...e.map((e) => t.map((t) => A(O(e[t.key], t), n)).join(n))].join("\n");
922
+ }
923
+ function A(e, t) {
924
+ return e.includes(t) || e.includes("\"") || e.includes("\n") || e.includes("\r") ? "\"" + e.replace(/"/g, "\"\"") + "\"" : e;
925
+ }
926
+ function j(e, t) {
927
+ let n = e.map((e) => {
928
+ let n = {};
929
+ for (let r of t) {
930
+ let t = e[r.key];
931
+ (r.type === "date" || r.type === "datetime") && t instanceof Date ? n[r.key] = t.toISOString() : n[r.key] = t ?? null;
932
+ }
933
+ return n;
934
+ });
935
+ return JSON.stringify(n, null, 2);
936
+ }
937
+ function M(e, t, n) {
938
+ let r = new Blob([e], { type: n }), i = URL.createObjectURL(r), a = document.createElement("a");
939
+ a.href = i, a.download = t, a.style.display = "none", document.body.appendChild(a), a.click(), document.body.removeChild(a), setTimeout(() => URL.revokeObjectURL(i), 100);
940
+ }
941
+ var N = {
942
+ csv: "text/csv;charset=utf-8",
943
+ tsv: "text/tab-separated-values;charset=utf-8",
944
+ json: "application/json;charset=utf-8"
945
+ }, P = {
946
+ csv: ".csv",
947
+ tsv: ".tsv",
948
+ json: ".json"
949
+ };
950
+ function F(e) {
951
+ return N[e];
952
+ }
953
+ function I(e) {
954
+ return P[e];
955
+ }
956
+ //#endregion
957
+ //#region \0@oxc-project+runtime@0.130.0/helpers/decorate.js
958
+ function L(e, t, n, r) {
959
+ var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
960
+ if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
961
+ else for (var s = e.length - 1; s >= 0; s--) (o = e[s]) && (a = (i < 3 ? o(a) : i > 3 ? o(t, n, a) : o(t, n)) || a);
962
+ return i > 3 && a && Object.defineProperty(t, n, a), a;
963
+ }
964
+ //#endregion
965
+ //#region src/flex-table.ts
966
+ var R = 120, z = 40, B = 32, V = 5, H = class extends e {
967
+ constructor(...e) {
968
+ super(...e), this.columns = [], this.data = [], this.rowHeight = B, 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 h(), this._editing = new g(), this._rowSelection = new _(), this._undo = new C(), this._filters = [], this._filteredIndices = [], this._sortedIndices = [], this._openFilterKey = null, this._rowSelectionVersion = 0, this._viewDirty = !0, this._isDragging = !1, this._wasDrag = !1, this._resizing = null, this._resizeCleanup = null, this._colDrag = null, this._colDragIndicatorLeft = null, this._fillDrag = null, this._rowDrag = null, this._rowDragIndicatorY = null, this._findState = null, this._columnWidths = /* @__PURE__ */ new Map(), this._hostResizeObserver = null, this._invalidCells = /* @__PURE__ */ new Map(), this._textFilterState = /* @__PURE__ */ new Map(), this._numberFilterState = /* @__PURE__ */ new Map(), this._dateFilterState = /* @__PURE__ */ new Map();
969
+ }
970
+ static {
971
+ this.styles = s;
972
+ }
973
+ set selectionMode(e) {
974
+ this._rowSelection.mode = e, this.requestUpdate();
975
+ }
976
+ get selectionMode() {
977
+ return this._rowSelection.mode;
978
+ }
979
+ set maxUndoSize(e) {
980
+ this._undo.maxSize = e;
981
+ }
982
+ get maxUndoSize() {
983
+ return this._undo.maxSize;
984
+ }
985
+ get visibleColumns() {
986
+ return this.columns.filter((e) => !e.hidden);
987
+ }
988
+ get _prefixWidth() {
989
+ let e = 0;
990
+ return this.selectable && (e += 36), this.showRowNumbers && (e += 48), e;
991
+ }
992
+ get canUndo() {
993
+ return this._undo.canUndo;
994
+ }
995
+ get canRedo() {
996
+ return this._undo.canRedo;
997
+ }
998
+ get activeCell() {
999
+ return this._activeCell;
1000
+ }
1001
+ get editingCell() {
1002
+ return this._editingCell;
1003
+ }
1004
+ get sortCriteria() {
1005
+ return [...this._sortCriteria];
1006
+ }
1007
+ get filteredRowCount() {
1008
+ return this._filteredIndices.length;
1009
+ }
1010
+ getSelectedRows() {
1011
+ let e = this._rowSelection.selectedIndices.map((e) => this._toDataIndex(e)).filter((e) => e >= 0 && e < this.data.length);
1012
+ return {
1013
+ selectedIndices: e,
1014
+ selectedRows: e.map((e) => this.data[e])
1015
+ };
1016
+ }
1017
+ selectAll() {
1018
+ this.selectable && (this._rowSelection.selectAll(), this._rowSelectionVersion++, this._dispatchRowSelectionEvent());
1019
+ }
1020
+ deselectAll() {
1021
+ this.selectable && (this._rowSelection.deselectAll(), this._rowSelectionVersion++, this._dispatchRowSelectionEvent());
1022
+ }
1023
+ _dispatchRowSelectionEvent() {
1024
+ let { selectedIndices: e, selectedRows: t } = this.getSelectedRows();
1025
+ this.dispatchEvent(new CustomEvent("selection-change", {
1026
+ detail: {
1027
+ selectedIndices: e,
1028
+ selectedRows: t
1029
+ },
1030
+ bubbles: !0,
1031
+ composed: !0
1032
+ }));
1033
+ }
1034
+ setFilter(e, t) {
1035
+ this._filters = this._filters.filter((t) => t.key !== e), this._filters.push({
1036
+ key: e,
1037
+ predicate: t
1038
+ }), this._recomputeView(), this.requestUpdate(), this._dispatchFilterEvent();
1039
+ }
1040
+ removeFilter(e) {
1041
+ let t = this._filters.length;
1042
+ this._filters = this._filters.filter((t) => t.key !== e), this._filters.length !== t && (this._recomputeView(), this.requestUpdate(), this._dispatchFilterEvent());
1043
+ }
1044
+ clearFilters() {
1045
+ this._filters.length !== 0 && (this._filters = [], this._recomputeView(), this.requestUpdate(), this._dispatchFilterEvent());
1046
+ }
1047
+ get filterKeys() {
1048
+ return this._filters.map((e) => e.key);
1049
+ }
1050
+ refreshData() {
1051
+ this.requestUpdate("data");
1052
+ }
1053
+ _dispatchUndoStateEvent() {
1054
+ this.dispatchEvent(new CustomEvent("undo-state-change", {
1055
+ detail: {
1056
+ canUndo: this.canUndo,
1057
+ canRedo: this.canRedo
1058
+ },
1059
+ bubbles: !0,
1060
+ composed: !0
1061
+ }));
1062
+ }
1063
+ _dispatchFilterEvent() {
1064
+ this.dispatchEvent(new CustomEvent("filter-change", {
1065
+ detail: {
1066
+ keys: this.filterKeys,
1067
+ filteredCount: this.filteredRowCount
1068
+ },
1069
+ bubbles: !0,
1070
+ composed: !0
1071
+ }));
1072
+ }
1073
+ addColumn(e, t) {
1074
+ let n = t ?? this.columns.length;
1075
+ return this.columns = [
1076
+ ...this.columns.slice(0, n),
1077
+ e,
1078
+ ...this.columns.slice(n)
1079
+ ], this._undo.push({
1080
+ label: "column-add",
1081
+ undo: () => {
1082
+ this.columns = this.columns.filter((t) => t !== e), this.requestUpdate();
1083
+ },
1084
+ redo: () => {
1085
+ this.columns = [
1086
+ ...this.columns.slice(0, n),
1087
+ e,
1088
+ ...this.columns.slice(n)
1089
+ ], this.requestUpdate();
1090
+ }
1091
+ }), this.requestUpdate(), this.dispatchEvent(new CustomEvent("column-add", {
1092
+ detail: {
1093
+ column: e,
1094
+ index: n
1095
+ },
1096
+ bubbles: !0,
1097
+ composed: !0
1098
+ })), this._dispatchUndoStateEvent(), e;
1099
+ }
1100
+ deleteColumn(e) {
1101
+ let t = this.columns.findIndex((t) => t.key === e);
1102
+ if (t === -1) return;
1103
+ let n = this.columns[t], r = this._filters.find((t) => t.key === e), i = this._sortCriteria.find((t) => t.key === e), a = this._columnWidths.get(e);
1104
+ this._filters = this._filters.filter((t) => t.key !== e), this._sortCriteria = this._sortCriteria.filter((t) => t.key !== e), this._columnWidths.delete(e), this.columns = this.columns.filter((t) => t.key !== e), this._undo.push({
1105
+ label: "column-delete",
1106
+ undo: () => {
1107
+ this.columns = [
1108
+ ...this.columns.slice(0, t),
1109
+ n,
1110
+ ...this.columns.slice(t)
1111
+ ], r && this._filters.push(r), i && (this._sortCriteria = [...this._sortCriteria, i]), a !== void 0 && this._columnWidths.set(e, a), this.requestUpdate();
1112
+ },
1113
+ redo: () => {
1114
+ this._filters = this._filters.filter((t) => t.key !== e), this._sortCriteria = this._sortCriteria.filter((t) => t.key !== e), this._columnWidths.delete(e), this.columns = this.columns.filter((t) => t.key !== e), this.requestUpdate();
1115
+ }
1116
+ }), this._activeCell && this._activeCell.col >= this.visibleColumns.length && (this._selection.clear(), this._activeCell = null), this.requestUpdate(), this.dispatchEvent(new CustomEvent("column-delete", {
1117
+ detail: {
1118
+ column: n,
1119
+ key: e,
1120
+ index: t
1121
+ },
1122
+ bubbles: !0,
1123
+ composed: !0
1124
+ })), this._dispatchUndoStateEvent();
1125
+ }
1126
+ moveColumn(e, t) {
1127
+ let n = this.columns.findIndex((t) => t.key === e);
1128
+ if (n === -1) return;
1129
+ let r = Math.max(0, Math.min(this.columns.length - 1, t));
1130
+ if (n === r) return;
1131
+ let i = this.columns[n], a = [...this.columns];
1132
+ a.splice(n, 1), a.splice(r, 0, i), this.columns = a, this._undo.push({
1133
+ label: "column-reorder",
1134
+ undo: () => {
1135
+ let e = [...this.columns];
1136
+ e.splice(r, 1), e.splice(n, 0, i), this.columns = e, this.requestUpdate();
1137
+ },
1138
+ redo: () => {
1139
+ let e = [...this.columns];
1140
+ e.splice(n, 1), e.splice(r, 0, i), this.columns = e, this.requestUpdate();
1141
+ }
1142
+ }), this.requestUpdate(), this.dispatchEvent(new CustomEvent("column-reorder", {
1143
+ detail: {
1144
+ key: e,
1145
+ oldIndex: n,
1146
+ newIndex: r
1147
+ },
1148
+ bubbles: !0,
1149
+ composed: !0
1150
+ })), this._dispatchUndoStateEvent();
1151
+ }
1152
+ addRow(e, t) {
1153
+ if (this.maxRows > 0 && this.data.length >= this.maxRows) return null;
1154
+ let n = e ?? this._createEmptyRow(), r = t ?? this.data.length;
1155
+ return this.data.splice(r, 0, n), this._undo.push({
1156
+ label: "row-add",
1157
+ undo: () => {
1158
+ this.data.splice(r, 1), this.requestUpdate();
1159
+ },
1160
+ redo: () => {
1161
+ this.data.splice(r, 0, n), this.requestUpdate();
1162
+ }
1163
+ }), this.requestUpdate(), this.dispatchEvent(new CustomEvent("row-add", {
1164
+ detail: {
1165
+ row: n,
1166
+ index: r
1167
+ },
1168
+ bubbles: !0,
1169
+ composed: !0
1170
+ })), this._dispatchUndoStateEvent(), n;
1171
+ }
1172
+ deleteRows(e) {
1173
+ let t = e ?? this._getSelectedDataRows();
1174
+ if (t.length === 0) return;
1175
+ let n = [...t].sort((e, t) => t - e), r = [];
1176
+ for (let e of n) e >= 0 && e < this.data.length && (r.push({
1177
+ index: e,
1178
+ row: this.data[e]
1179
+ }), this.data.splice(e, 1));
1180
+ if (r.length !== 0) {
1181
+ if (r.reverse(), this._undo.push({
1182
+ label: "row-delete",
1183
+ undo: () => {
1184
+ for (let { index: e, row: t } of r) this.data.splice(e, 0, t);
1185
+ this.requestUpdate();
1186
+ },
1187
+ redo: () => {
1188
+ let e = [...r].reverse();
1189
+ for (let { index: t } of e) this.data.splice(t, 1);
1190
+ this.requestUpdate();
1191
+ }
1192
+ }), this._activeCell) {
1193
+ let e = this._toDataIndex(this._activeCell.row);
1194
+ t.includes(e) && (this._selection.clear(), this._activeCell = null);
1195
+ }
1196
+ this.requestUpdate(), this.dispatchEvent(new CustomEvent("row-delete", {
1197
+ detail: {
1198
+ indices: r.map((e) => e.index),
1199
+ rows: r.map((e) => e.row)
1200
+ },
1201
+ bubbles: !0,
1202
+ composed: !0
1203
+ })), this._dispatchUndoStateEvent();
1204
+ }
1205
+ }
1206
+ updateRows(e) {
1207
+ if (e.length === 0) return;
1208
+ let t = [];
1209
+ for (let n of e) {
1210
+ if (n.row < 0 || n.row >= this.data.length) continue;
1211
+ let e = this.data[n.row][n.key];
1212
+ this.data[n.row][n.key] = n.value, t.push({
1213
+ row: n.row,
1214
+ key: n.key,
1215
+ oldValue: e,
1216
+ newValue: n.value
1217
+ });
1218
+ }
1219
+ t.length !== 0 && (this._undo.push({
1220
+ label: "batch-update",
1221
+ undo: () => {
1222
+ for (let e of t) this.data[e.row][e.key] = e.oldValue;
1223
+ this.requestUpdate();
1224
+ },
1225
+ redo: () => {
1226
+ for (let e of t) this.data[e.row][e.key] = e.newValue;
1227
+ this.requestUpdate();
1228
+ }
1229
+ }), this.requestUpdate(), this.dispatchEvent(new CustomEvent("batch-update", {
1230
+ detail: { changes: t },
1231
+ bubbles: !0,
1232
+ composed: !0
1233
+ })), this._dispatchUndoStateEvent());
1234
+ }
1235
+ _createEmptyRow() {
1236
+ let e = {};
1237
+ for (let t of this.columns) switch (t.type) {
1238
+ case "number":
1239
+ e[t.key] = 0;
1240
+ break;
1241
+ case "boolean":
1242
+ e[t.key] = !1;
1243
+ break;
1244
+ default: e[t.key] = "";
1245
+ }
1246
+ return e;
1247
+ }
1248
+ exportToString(e, t) {
1249
+ if (t?.selectionOnly) {
1250
+ let t = this._selection.getEffectiveRange();
1251
+ if (!t) return "";
1252
+ let n = this.visibleColumns.slice(t.startCol, t.endCol + 1), r = [];
1253
+ for (let e = t.startRow; e <= t.endRow; e++) r.push(this.data[this._toDataIndex(e)]);
1254
+ return D(r, n, e);
1255
+ }
1256
+ return D(this._sortedIndices.map((e) => this.data[e]), this.visibleColumns, e);
1257
+ }
1258
+ exportToFile(e, t) {
1259
+ M(this.exportToString(e), t ?? `export${I(e)}`, F(e));
1260
+ }
1261
+ _getSelectedDataRows() {
1262
+ let e = this._selection.getEffectiveRange();
1263
+ if (!e) return [];
1264
+ let t = [];
1265
+ for (let n = e.startRow; n <= e.endRow; n++) t.push(this._toDataIndex(n));
1266
+ return t;
1267
+ }
1268
+ getColumnWidth(e) {
1269
+ return this._columnWidths.get(e);
1270
+ }
1271
+ _getColWidth(e) {
1272
+ let t = this._columnWidths.get(e.key) ?? e.width ?? R;
1273
+ return Math.max(t, e.minWidth ?? z);
1274
+ }
1275
+ get headerHeight() {
1276
+ return this.rowHeight + 8;
1277
+ }
1278
+ get _visibleRowCount() {
1279
+ return this._sortedIndices.length;
1280
+ }
1281
+ get totalBodyHeight() {
1282
+ return this._visibleRowCount * this.rowHeight;
1283
+ }
1284
+ get visibleRange() {
1285
+ let e = Math.max(0, this._scrollTop - this.headerHeight), t = Math.max(0, Math.floor(e / this.rowHeight) - V), n = Math.ceil(this._viewportHeight / this.rowHeight);
1286
+ return {
1287
+ start: t,
1288
+ end: Math.min(this._visibleRowCount, Math.floor(e / this.rowHeight) + n + V)
1289
+ };
1290
+ }
1291
+ connectedCallback() {
1292
+ 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"), typeof ResizeObserver < "u" && (this._hostResizeObserver = new ResizeObserver(() => this._measureViewport()), this._hostResizeObserver.observe(this));
1293
+ }
1294
+ disconnectedCallback() {
1295
+ super.disconnectedCallback(), this.removeEventListener("scroll", this._onScroll), this.removeEventListener("keydown", this._onKeyDown), this.removeEventListener("contextmenu", this._onContextMenu), document.removeEventListener("click", this._onDocumentClick), this._isDragging = !1, this._wasDrag = !1, this._resizeCleanup &&= (this._resizeCleanup(), null), this._hostResizeObserver &&= (this._hostResizeObserver.disconnect(), null);
1296
+ }
1297
+ firstUpdated() {
1298
+ this._measureViewport();
1299
+ }
1300
+ _updateColOffsets() {
1301
+ let e = this.visibleColumns, t = [], n = this._prefixWidth;
1302
+ for (let r of e) t.push(n), n += this._getColWidth(r);
1303
+ this._colLeftOffsets = t, this._totalRowWidth = n;
1304
+ }
1305
+ get visibleColRange() {
1306
+ let e = this.visibleColumns;
1307
+ if (e.length === 0) return {
1308
+ start: 0,
1309
+ end: 0
1310
+ };
1311
+ let t = this._colLeftOffsets;
1312
+ if (t.length === 0) return {
1313
+ start: 0,
1314
+ end: e.length
1315
+ };
1316
+ let n = this._scrollLeft, r = n + this._viewportWidth, i = e.length;
1317
+ for (let r = 0; r < t.length; r++) if (t[r] + this._getColWidth(e[r]) > n) {
1318
+ i = r;
1319
+ break;
1320
+ }
1321
+ i = Math.max(0, i - V);
1322
+ let a = e.length;
1323
+ for (let e = i; e < t.length; e++) if (t[e] > r) {
1324
+ a = e;
1325
+ break;
1326
+ }
1327
+ return a = Math.min(e.length, a + V), {
1328
+ start: i,
1329
+ end: a
1330
+ };
1331
+ }
1332
+ willUpdate(e) {
1333
+ (!(e.size <= 2 && !e.has("data") && !e.has("columns") && !e.has("_openFilterKey") && !e.has("_editingCell") && !e.has("_activeCell") && (e.has("_scrollTop") || e.has("_scrollLeft"))) || this._viewDirty) && (this._recomputeView(), this._viewDirty = !1), this._updateColOffsets(), this._selection.setDimensions(this._visibleRowCount, this.visibleColumns.length), this._rowSelection.setRowCount(this._visibleRowCount);
1334
+ }
1335
+ updated() {
1336
+ this._focusEditor(), this._adjustFilterDropdown(), this.setAttribute("aria-rowcount", String(this._visibleRowCount)), this.setAttribute("aria-colcount", String(this.visibleColumns.length));
1337
+ }
1338
+ _recomputeView() {
1339
+ if (this.dataMode === "server") {
1340
+ this._filteredIndices = Array.from({ length: this.data.length }, (e, t) => t), this._sortedIndices = this._filteredIndices;
1341
+ return;
1342
+ }
1343
+ if (this._filteredIndices = x(this.data, this._filters, (e, t, n) => {
1344
+ this.dispatchEvent(new CustomEvent("filter-error", {
1345
+ detail: {
1346
+ error: e,
1347
+ row: t,
1348
+ filterKey: n.key
1349
+ },
1350
+ bubbles: !0,
1351
+ composed: !0
1352
+ }));
1353
+ }), this._filters.length === 0 && this._sortCriteria.length === 0) this._sortedIndices = Array.from({ length: this.data.length }, (e, t) => t);
1354
+ else if (this._sortCriteria.length === 0) this._sortedIndices = [...this._filteredIndices];
1355
+ else {
1356
+ let e = v(this._filteredIndices.map((e) => this.data[e]), this._sortCriteria, this.visibleColumns);
1357
+ this._sortedIndices = e.map((e) => this._filteredIndices[e]);
1358
+ }
1359
+ }
1360
+ _toDataIndex(e) {
1361
+ return this._sortedIndices[e] ?? e;
1362
+ }
1363
+ _focusEditor() {
1364
+ if (!this._editingCell) return;
1365
+ let e = this.shadowRoot?.querySelector(".ft-editor");
1366
+ e && document.activeElement !== e && (e.focus(), (e.type === "text" || e.type === "number") && e.select());
1367
+ }
1368
+ _measureViewport() {
1369
+ let e = this.clientHeight, t = this.clientWidth;
1370
+ e !== this._viewportHeight && (this._viewportHeight = e), t !== this._viewportWidth && (this._viewportWidth = t);
1371
+ }
1372
+ _onScroll() {
1373
+ this._scrollTop = this.scrollTop, this._scrollLeft = this.scrollLeft;
1374
+ }
1375
+ _onDocumentClick() {
1376
+ this._openFilterKey &&= null;
1377
+ }
1378
+ _onContextMenu(e) {
1379
+ let t = e.composedPath().find((e) => e instanceof HTMLElement && e.classList.contains("ft-cell"));
1380
+ if (!t) return;
1381
+ let n = t.parentElement;
1382
+ if (!n || !n.classList.contains("ft-row")) return;
1383
+ let r = parseInt(t.dataset.colIndex ?? "-1", 10), i = n.style.top, a = Math.round(parseInt(i, 10) / this.rowHeight);
1384
+ if (r < 0 || a < 0) return;
1385
+ let o = this._toDataIndex(a), s = this.visibleColumns[r];
1386
+ s && this.dispatchEvent(new CustomEvent("context-menu", {
1387
+ detail: {
1388
+ x: e.clientX,
1389
+ y: e.clientY,
1390
+ row: o,
1391
+ col: r,
1392
+ key: s.key,
1393
+ value: this.data[o]?.[s.key],
1394
+ rowData: this.data[o]
1395
+ },
1396
+ bubbles: !0,
1397
+ composed: !0
1398
+ }));
1399
+ }
1400
+ _onCellClickEvent(e, t, n) {
1401
+ if (this._wasDrag) {
1402
+ this._wasDrag = !1;
1403
+ return;
1404
+ }
1405
+ this._isDragging = !1, this._editing.current && this._commitEdit(), e.shiftKey ? this._selection.setActiveWithRange(t, n) : e.ctrlKey || e.metaKey ? this._selection.toggleCell(t, n) : this._selection.setActive(t, n), this._activeCell = this._selection.activeCell ? { ...this._selection.activeCell } : null, this._dispatchSelectionEvent(), this.requestUpdate();
1406
+ }
1407
+ _onCellMouseDown(e, t, n) {
1408
+ if (e.button !== 0 || e.shiftKey) return;
1409
+ if (e.ctrlKey || e.metaKey) {
1410
+ this.focus({ preventScroll: !0 }), e.preventDefault();
1411
+ return;
1412
+ }
1413
+ this._isDragging = !0, this._wasDrag = !1, this._editing.current && this._commitEdit(), this._selection.setActive(t, n), this._activeCell = {
1414
+ row: t,
1415
+ col: n
1416
+ }, this.focus({ preventScroll: !0 }), e.preventDefault();
1417
+ let r = () => {
1418
+ this._isDragging = !1, document.removeEventListener("mouseup", r);
1419
+ };
1420
+ document.addEventListener("mouseup", r), this.requestUpdate();
1421
+ }
1422
+ _onCellMouseEnter(e, t) {
1423
+ this._isDragging && (this._wasDrag = !0, this._selection.setActiveWithRange(e, t), this._activeCell = this._selection.activeCell ? { ...this._selection.activeCell } : null, this._dispatchSelectionEvent(), this.requestUpdate());
1424
+ }
1425
+ _onRowNumberClick(e) {
1426
+ this._editing.current && this._commitEdit();
1427
+ let t = this.visibleColumns.length - 1;
1428
+ this._selection.setActive(e, 0), this._selection.setActiveWithRange(e, t), this._activeCell = this._selection.activeCell ? { ...this._selection.activeCell } : null, this._dispatchSelectionEvent(), this.requestUpdate();
1429
+ }
1430
+ _onCellDblClick(e, t) {
1431
+ this._editing.current && this._commitEdit(), this._selection.setActive(e, t), this._activeCell = this._selection.activeCell ? { ...this._selection.activeCell } : null, this._dispatchSelectionEvent(), this._startEdit();
1432
+ }
1433
+ _isCellEditable(e) {
1434
+ return !(!this.editable || e.editable === !1);
1435
+ }
1436
+ _startEdit() {
1437
+ if (!this._activeCell) return;
1438
+ let e = this.visibleColumns[this._activeCell.col];
1439
+ if (!e || !this._isCellEditable(e)) return;
1440
+ if (e.type === "boolean") {
1441
+ let t = this.data[this._toDataIndex(this._activeCell.row)][e.key];
1442
+ this._applyEdit(!t);
1443
+ return;
1444
+ }
1445
+ let t = this._toDataIndex(this._activeCell.row), n = this.data[t];
1446
+ this._editing.start(this._activeCell, n[e.key]), this._editingCell = { ...this._activeCell }, this.dispatchEvent(new CustomEvent("cell-edit-start", {
1447
+ detail: {
1448
+ row: t,
1449
+ col: this._activeCell.col,
1450
+ key: e.key,
1451
+ value: n[e.key]
1452
+ },
1453
+ bubbles: !0,
1454
+ composed: !0
1455
+ }));
1456
+ }
1457
+ _commitEdit() {
1458
+ if (!this._editing.current) return;
1459
+ let e = this.visibleColumns[this._editing.current.position.col];
1460
+ if (e.type === "select") {
1461
+ let t = this.shadowRoot?.querySelector("select.ft-editor");
1462
+ if (t) {
1463
+ let n = e.options?.find((e) => typeof e != "string" && String(e.value) === t.value);
1464
+ this._applyEdit(n ? n.value : t.value);
1465
+ } else this._cancelEdit();
1466
+ return;
1467
+ }
1468
+ let t = this.shadowRoot?.querySelector(".ft-editor");
1469
+ if (t) {
1470
+ let n = E(t.value, e);
1471
+ this._applyEdit(n);
1472
+ } else this._cancelEdit();
1473
+ }
1474
+ _applyEdit(e) {
1475
+ let t = this._editing.commit();
1476
+ if (this._editingCell = null, !t) return;
1477
+ let { row: n, col: r } = t.position, i = this._toDataIndex(n), a = this.visibleColumns[r], o = t.originalValue;
1478
+ if (a.validator) {
1479
+ let t = a.validator(e, this.data[i], a);
1480
+ if (t) {
1481
+ this._markCellInvalid(n, r, t), this.dispatchEvent(new CustomEvent("validation-error", {
1482
+ detail: {
1483
+ row: i,
1484
+ col: r,
1485
+ key: a.key,
1486
+ value: e,
1487
+ error: t
1488
+ },
1489
+ bubbles: !0,
1490
+ composed: !0
1491
+ }));
1492
+ return;
1493
+ }
1494
+ }
1495
+ this.data[i][a.key] = e, this._undo.push({
1496
+ label: "cell-edit",
1497
+ undo: () => {
1498
+ this.data[i][a.key] = o, this.requestUpdate();
1499
+ },
1500
+ redo: () => {
1501
+ this.data[i][a.key] = e, this.requestUpdate();
1502
+ }
1503
+ }), this.requestUpdate(), this.dispatchEvent(new CustomEvent("cell-edit-commit", {
1504
+ detail: {
1505
+ row: i,
1506
+ col: r,
1507
+ key: a.key,
1508
+ oldValue: o,
1509
+ newValue: e
1510
+ },
1511
+ bubbles: !0,
1512
+ composed: !0
1513
+ })), this._dispatchUndoStateEvent();
1514
+ }
1515
+ _cancelEdit() {
1516
+ let e = this._editing.cancel();
1517
+ this._editingCell = null, e && this.dispatchEvent(new CustomEvent("cell-edit-cancel", {
1518
+ detail: {
1519
+ row: e.position.row,
1520
+ col: e.position.col
1521
+ },
1522
+ bubbles: !0,
1523
+ composed: !0
1524
+ }));
1525
+ }
1526
+ _onEditorKeyDown(e) {
1527
+ e.key === "Enter" ? (e.preventDefault(), e.stopPropagation(), this._commitEdit(), this._selection.moveDown(), this._syncActiveCell()) : e.key === "Tab" ? (e.preventDefault(), e.stopPropagation(), this._commitEdit(), e.shiftKey ? this._selection.movePrev() : this._selection.moveNext(), this._syncActiveCell()) : e.key === "Escape" && (e.preventDefault(), e.stopPropagation(), this._cancelEdit());
1528
+ }
1529
+ _syncActiveCell() {
1530
+ this._activeCell = this._selection.activeCell ? { ...this._selection.activeCell } : null, this._scrollToActiveCell(), this._dispatchSelectionEvent();
1531
+ }
1532
+ _onKeyDown(e) {
1533
+ if (this._editing.current) return;
1534
+ let t = this.visibleColumns;
1535
+ if ((e.ctrlKey || e.metaKey) && !e.altKey) {
1536
+ let t = e.key.toLowerCase();
1537
+ if ([
1538
+ "f",
1539
+ "h",
1540
+ "z",
1541
+ "y"
1542
+ ].includes(t) && this._handleCtrlKey(e)) return;
1543
+ }
1544
+ if (!(t.length === 0 || this._visibleRowCount === 0)) {
1545
+ if ((e.key === "Enter" || e.key === "F2") && this._activeCell) {
1546
+ e.preventDefault(), this._startEdit();
1547
+ return;
1548
+ }
1549
+ if (!this._selection.activeCell) {
1550
+ if ([
1551
+ "ArrowDown",
1552
+ "ArrowUp",
1553
+ "ArrowLeft",
1554
+ "ArrowRight",
1555
+ "Tab",
1556
+ "Home",
1557
+ "End"
1558
+ ].includes(e.key)) {
1559
+ this._selection.setActive(0, 0), this._syncActiveCell(), e.preventDefault();
1560
+ return;
1561
+ }
1562
+ if (e.key === "Escape" && this._findState) {
1563
+ this._closeFindPanel(), e.preventDefault();
1564
+ return;
1565
+ }
1566
+ return;
1567
+ }
1568
+ if (!this._handleCtrlKey(e) && !this._handleAltKey(e, t)) {
1569
+ if (this._activeCell && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
1570
+ let e = t[this._activeCell.col];
1571
+ e && this._isCellEditable(e) && this._startEdit();
1572
+ return;
1573
+ }
1574
+ this._handleNavigation(e) && (e.preventDefault(), this._syncActiveCell());
1575
+ }
1576
+ }
1577
+ }
1578
+ _handleCtrlKey(e) {
1579
+ if (!(e.ctrlKey || e.metaKey) || e.altKey) return !1;
1580
+ switch (e.key.toLowerCase()) {
1581
+ case "z": return e.preventDefault(), e.shiftKey ? this._undo.redo() : this._undo.undo(), this.requestUpdate(), this._dispatchUndoStateEvent(), !0;
1582
+ case "y": return e.preventDefault(), this._undo.redo(), this.requestUpdate(), this._dispatchUndoStateEvent(), !0;
1583
+ case "c": return e.preventDefault(), this._handleCopy(!1), !0;
1584
+ case "x": return e.preventDefault(), this._handleCopy(this.editable), !0;
1585
+ case "v": return e.preventDefault(), this.editable && this._handlePaste(), !0;
1586
+ case "d": return e.preventDefault(), this.editable && this._handleFillDown(), !0;
1587
+ case "r": return e.preventDefault(), this.editable && this._handleFillRight(), !0;
1588
+ case "f": return e.preventDefault(), this._toggleFindPanel("find"), !0;
1589
+ case "h": return e.preventDefault(), this._toggleFindPanel("replace"), !0;
1590
+ default: return !1;
1591
+ }
1592
+ }
1593
+ _handleAltKey(e, t) {
1594
+ if (!e.altKey || !this._activeCell || e.key !== "ArrowLeft" && e.key !== "ArrowRight") return !1;
1595
+ e.preventDefault();
1596
+ let n = t[this._activeCell.col];
1597
+ if (!n) return !0;
1598
+ let r = this._columnWidths.get(n.key) ?? n.width ?? R, i = e.key === "ArrowRight" ? 20 : -20, a = n.minWidth ?? z, o = Math.max(a, r + i);
1599
+ return this._columnWidths.set(n.key, o), this.requestUpdate(), this.dispatchEvent(new CustomEvent("column-resize", {
1600
+ detail: {
1601
+ key: n.key,
1602
+ width: o,
1603
+ colIndex: this._activeCell.col
1604
+ },
1605
+ bubbles: !0,
1606
+ composed: !0
1607
+ })), !0;
1608
+ }
1609
+ _handleNavigation(e) {
1610
+ switch (e.key) {
1611
+ case "ArrowUp": return e.shiftKey ? this._selection.shiftMoveUp() : this._selection.moveUp(), !0;
1612
+ case "ArrowDown": return e.shiftKey ? this._selection.shiftMoveDown() : this._selection.moveDown(), !0;
1613
+ case "ArrowLeft": return e.shiftKey ? this._selection.shiftMoveLeft() : this._selection.moveLeft(), !0;
1614
+ case "ArrowRight": return e.shiftKey ? this._selection.shiftMoveRight() : this._selection.moveRight(), !0;
1615
+ case "Tab": return e.shiftKey ? this._selection.movePrev() : this._selection.moveNext(), !0;
1616
+ case "Home": return e.ctrlKey ? this._selection.moveToStart() : this._selection.moveToRowStart(), !0;
1617
+ case "End": return e.ctrlKey ? this._selection.moveToEnd() : this._selection.moveToRowEnd(), !0;
1618
+ case "Escape": return this._findState ? (this._closeFindPanel(), !0) : (this._selection.clear(), !0);
1619
+ case "Delete":
1620
+ case "Backspace": return this.editable && this._handleDelete(), !0;
1621
+ default: return !1;
1622
+ }
1623
+ }
1624
+ async _handleCopy(e) {
1625
+ let t = this._selection.getEffectiveRange();
1626
+ if (!t) return;
1627
+ let n = this.visibleColumns, r = w(this._sortedIndices.map((e) => this.data[e]), n, t);
1628
+ try {
1629
+ await navigator.clipboard.writeText(r);
1630
+ } catch (e) {
1631
+ this.dispatchEvent(new CustomEvent("clipboard-error", {
1632
+ detail: {
1633
+ action: "copy",
1634
+ error: e
1635
+ },
1636
+ bubbles: !0,
1637
+ composed: !0
1638
+ }));
1639
+ }
1640
+ e && this._clearRange(t), this.dispatchEvent(new CustomEvent(e ? "clipboard-cut" : "clipboard-copy", {
1641
+ detail: {
1642
+ range: t,
1643
+ text: r
1644
+ },
1645
+ bubbles: !0,
1646
+ composed: !0
1647
+ }));
1648
+ }
1649
+ async _handlePaste() {
1650
+ if (!this._activeCell) return;
1651
+ let e = await this._readClipboardText();
1652
+ if (e == null) return;
1653
+ let t = T(e);
1654
+ if (t.length === 0) return;
1655
+ let n = this._expandRowsForPaste(this._activeCell.row, t.length), r = this._applyPasteData(this._activeCell, t);
1656
+ if (r.length > 0 || n.length > 0) {
1657
+ let e = n.length;
1658
+ this._undo.push({
1659
+ label: "paste",
1660
+ undo: () => {
1661
+ for (let e of r) this.data[e.row][e.key] = e.oldValue;
1662
+ e > 0 && this.data.splice(this.data.length - e, e), this.requestUpdate();
1663
+ },
1664
+ redo: () => {
1665
+ if (e > 0) for (let t = 0; t < e; t++) this.data.push(this._createEmptyRow());
1666
+ for (let e of r) this.data[e.row][e.key] = e.newValue;
1667
+ this.requestUpdate();
1668
+ }
1669
+ }), this._dispatchUndoStateEvent();
1670
+ }
1671
+ this.requestUpdate(), this.dispatchEvent(new CustomEvent("clipboard-paste", {
1672
+ detail: {
1673
+ changes: r,
1674
+ addedRows: n.length
1675
+ },
1676
+ bubbles: !0,
1677
+ composed: !0
1678
+ }));
1679
+ }
1680
+ async _readClipboardText() {
1681
+ try {
1682
+ return await navigator.clipboard.readText();
1683
+ } catch (e) {
1684
+ return this.dispatchEvent(new CustomEvent("clipboard-error", {
1685
+ detail: {
1686
+ action: "paste",
1687
+ error: e
1688
+ },
1689
+ bubbles: !0,
1690
+ composed: !0
1691
+ })), null;
1692
+ }
1693
+ }
1694
+ _expandRowsForPaste(e, t) {
1695
+ let n = [], r = e + t, i = this.maxRows > 0 ? this.maxRows : Infinity;
1696
+ for (; this.data.length < r && this.data.length < i;) {
1697
+ let e = this.data.length;
1698
+ this.data.push(this._createEmptyRow()), n.push(e);
1699
+ }
1700
+ return n.length > 0 && this._recomputeView(), n;
1701
+ }
1702
+ _applyPasteData(e, t) {
1703
+ let n = this.visibleColumns, r = [];
1704
+ for (let i = 0; i < t.length; i++) {
1705
+ let a = e.row + i;
1706
+ if (a >= this._visibleRowCount) break;
1707
+ let o = this._toDataIndex(a);
1708
+ for (let a = 0; a < t[i].length; a++) {
1709
+ let s = e.col + a;
1710
+ if (s >= n.length) break;
1711
+ let c = n[s], l = this.data[o][c.key], u = E(t[i][a], c);
1712
+ this.data[o][c.key] = u, r.push({
1713
+ row: o,
1714
+ col: s,
1715
+ key: c.key,
1716
+ oldValue: l,
1717
+ newValue: u
1718
+ });
1719
+ }
1720
+ }
1721
+ return r;
1722
+ }
1723
+ _handleFillDown() {
1724
+ let e = this._selection.getEffectiveRange();
1725
+ if (!e) return;
1726
+ let t = this.visibleColumns;
1727
+ if (e.startRow === e.endRow && e.startCol === e.endCol) {
1728
+ if (e.startRow === 0) return;
1729
+ let n = t[e.startCol];
1730
+ if (!n || !this._isCellEditable(n)) return;
1731
+ let r = this._toDataIndex(e.startRow - 1), i = this._toDataIndex(e.startRow);
1732
+ this.updateRows([{
1733
+ row: i,
1734
+ key: n.key,
1735
+ value: this.data[r][n.key]
1736
+ }]);
1737
+ return;
1738
+ }
1739
+ let n = [];
1740
+ for (let r = e.startCol; r <= e.endCol; r++) {
1741
+ let i = t[r];
1742
+ if (!i || !this._isCellEditable(i)) continue;
1743
+ let a = this.data[this._toDataIndex(e.startRow)][i.key];
1744
+ for (let t = e.startRow + 1; t <= e.endRow; t++) n.push({
1745
+ row: this._toDataIndex(t),
1746
+ key: i.key,
1747
+ value: a
1748
+ });
1749
+ }
1750
+ n.length > 0 && this.updateRows(n);
1751
+ }
1752
+ _handleFillRight() {
1753
+ let e = this._selection.getEffectiveRange();
1754
+ if (!e) return;
1755
+ let t = this.visibleColumns;
1756
+ if (e.startRow === e.endRow && e.startCol === e.endCol) {
1757
+ if (e.startCol === 0) return;
1758
+ let n = t[e.startCol], r = t[e.startCol - 1];
1759
+ if (!n || !this._isCellEditable(n) || !r) return;
1760
+ let i = this._toDataIndex(e.startRow);
1761
+ this.updateRows([{
1762
+ row: i,
1763
+ key: n.key,
1764
+ value: this.data[i][r.key]
1765
+ }]);
1766
+ return;
1767
+ }
1768
+ let n = [];
1769
+ for (let r = e.startRow; r <= e.endRow; r++) {
1770
+ let i = this._toDataIndex(r), a = t[e.startCol];
1771
+ if (!a) continue;
1772
+ let o = this.data[i][a.key];
1773
+ for (let r = e.startCol + 1; r <= e.endCol; r++) {
1774
+ let e = t[r];
1775
+ if (!e || !this._isCellEditable(e)) continue;
1776
+ let a = E(o == null ? "" : String(o), e);
1777
+ n.push({
1778
+ row: i,
1779
+ key: e.key,
1780
+ value: a
1781
+ });
1782
+ }
1783
+ }
1784
+ n.length > 0 && this.updateRows(n);
1785
+ }
1786
+ _handleDelete() {
1787
+ let e = this._selection.getEffectiveRange(), t = this._selection.extraRanges;
1788
+ if (!e && t.length === 0) return;
1789
+ let n = e ? [e, ...t] : [...t];
1790
+ this._clearRanges(n);
1791
+ }
1792
+ _clearRanges(e) {
1793
+ let t = this.visibleColumns, n = [], r = /* @__PURE__ */ new Set();
1794
+ for (let i of e) for (let e = i.startRow; e <= i.endRow; e++) {
1795
+ let a = this._toDataIndex(e);
1796
+ for (let e = i.startCol; e <= i.endCol; e++) {
1797
+ let i = `${a}:${e}`;
1798
+ if (r.has(i)) continue;
1799
+ r.add(i);
1800
+ let o = t[e], s = this.data[a][o.key], c = o.type === "boolean" ? !1 : o.type === "number" ? 0 : "";
1801
+ this.data[a][o.key] = c, n.push({
1802
+ dataRow: a,
1803
+ key: o.key,
1804
+ oldValue: s,
1805
+ clearValue: c
1806
+ });
1807
+ }
1808
+ }
1809
+ n.length > 0 && (this._undo.push({
1810
+ label: "clear",
1811
+ undo: () => {
1812
+ for (let e of n) this.data[e.dataRow][e.key] = e.oldValue;
1813
+ this.requestUpdate();
1814
+ },
1815
+ redo: () => {
1816
+ for (let e of n) this.data[e.dataRow][e.key] = e.clearValue;
1817
+ this.requestUpdate();
1818
+ }
1819
+ }), this._dispatchUndoStateEvent()), this.requestUpdate();
1820
+ }
1821
+ _clearRange(e) {
1822
+ let t = this.visibleColumns, n = [];
1823
+ for (let r = e.startRow; r <= e.endRow; r++) {
1824
+ let i = this._toDataIndex(r);
1825
+ for (let r = e.startCol; r <= e.endCol; r++) {
1826
+ let e = t[r], a = this.data[i][e.key], o = e.type === "boolean" ? !1 : e.type === "number" ? 0 : "";
1827
+ this.data[i][e.key] = o, n.push({
1828
+ dataRow: i,
1829
+ key: e.key,
1830
+ oldValue: a,
1831
+ clearValue: o
1832
+ });
1833
+ }
1834
+ }
1835
+ n.length > 0 && (this._undo.push({
1836
+ label: "clear",
1837
+ undo: () => {
1838
+ for (let e of n) this.data[e.dataRow][e.key] = e.oldValue;
1839
+ this.requestUpdate();
1840
+ },
1841
+ redo: () => {
1842
+ for (let e of n) this.data[e.dataRow][e.key] = e.clearValue;
1843
+ this.requestUpdate();
1844
+ }
1845
+ }), this._dispatchUndoStateEvent()), this.requestUpdate();
1846
+ }
1847
+ _scrollToActiveCell() {
1848
+ if (!this._activeCell) return;
1849
+ let e = this._activeCell.row * this.rowHeight + this.headerHeight, t = e + this.rowHeight;
1850
+ e < this.scrollTop + this.headerHeight ? this.scrollTop = e - this.headerHeight : t > this.scrollTop + this.clientHeight && (this.scrollTop = t - this.clientHeight);
1851
+ let n = this.visibleColumns, r = this._activeCell.col, i = this._colLeftOffsets[r] ?? 0, a = i + this._getColWidth(n[r]);
1852
+ i < this.scrollLeft ? this.scrollLeft = i : a > this.scrollLeft + this.clientWidth && (this.scrollLeft = a - this.clientWidth);
1853
+ }
1854
+ _dispatchSelectionEvent() {
1855
+ this.dispatchEvent(new CustomEvent("cell-select", {
1856
+ detail: this._activeCell ? { ...this._activeCell } : null,
1857
+ bubbles: !0,
1858
+ composed: !0
1859
+ }));
1860
+ }
1861
+ _onHeaderClick(e, t) {
1862
+ let n = this.visibleColumns.indexOf(t);
1863
+ if (e.ctrlKey || e.metaKey) {
1864
+ this._selectColumn(n);
1865
+ return;
1866
+ }
1867
+ t.sortable !== !1 && (this._sortCriteria = b(this._sortCriteria, t.key, e.shiftKey), this.dataMode !== "server" && this._recomputeView(), this.requestUpdate(), this.dispatchEvent(new CustomEvent("sort-change", {
1868
+ detail: { criteria: [...this._sortCriteria] },
1869
+ bubbles: !0,
1870
+ composed: !0
1871
+ })));
1872
+ }
1873
+ _selectColumn(e) {
1874
+ let t = this._visibleRowCount;
1875
+ t === 0 || e < 0 || (this._selection.setActive(0, e), this._selection.setActiveWithRange(t - 1, e), this._activeCell = {
1876
+ row: 0,
1877
+ col: e
1878
+ }, this.requestUpdate(), this.dispatchEvent(new CustomEvent("column-select", {
1879
+ detail: {
1880
+ colIndex: e,
1881
+ key: this.visibleColumns[e]?.key,
1882
+ rowCount: t
1883
+ },
1884
+ bubbles: !0,
1885
+ composed: !0
1886
+ })));
1887
+ }
1888
+ selectColumn(e) {
1889
+ this._selectColumn(e);
1890
+ }
1891
+ _getPinnedLeft(e) {
1892
+ let t = this.visibleColumns, n = 0;
1893
+ this.selectable && (n += 36), this.showRowNumbers && (n += 48);
1894
+ for (let r = 0; r < e; r++) t[r].pinned === "left" && (n += this._getColWidth(t[r]));
1895
+ return n;
1896
+ }
1897
+ _getPinnedRight(e) {
1898
+ let t = this.visibleColumns, n = 0;
1899
+ for (let r = t.length - 1; r > e; r--) t[r].pinned === "right" && (n += this._getColWidth(t[r]));
1900
+ return n;
1901
+ }
1902
+ _renderHeaderCell(e, t) {
1903
+ let i = e.sortable !== !1, a = this._sortCriteria.find((t) => t.key === e.key), o = this._sortCriteria.length > 1 ? this._sortCriteria.findIndex((t) => t.key === e.key) : -1, s = this._filters.some((t) => t.key === e.key), c = e.pinned === "left", l = e.pinned === "right", u = [
1904
+ "ft-header-cell",
1905
+ i ? "ft-sortable" : "",
1906
+ c || l ? "ft-pinned" : ""
1907
+ ].filter(Boolean).join(" "), d = i ? a ? a.direction === "asc" ? "ascending" : "descending" : "none" : void 0, f = this._getColWidth(e), p = this.headerHeight, m = this._colLeftOffsets[t] ?? 0, h;
1908
+ h = c ? `position: absolute; top: 0; left: ${this._scrollLeft + this._getPinnedLeft(t)}px; width: ${f}px; height: ${p}px; z-index: 4;` : l ? `position: absolute; top: 0; right: ${-this._scrollLeft + this._getPinnedRight(t)}px; width: ${f}px; height: ${p}px; z-index: 4;` : `left: ${m}px; width: ${f}px; height: ${p}px;`;
1909
+ let g = this._colDrag?.active && this._colDrag.colIndex === t;
1910
+ return n`
1911
+ <div class=${[...u.split(" "), g ? "ft-col-dragging" : ""].filter(Boolean).join(" ")}
1912
+ role="columnheader"
1913
+ data-col-index=${t}
1914
+ style=${h}
1915
+ aria-sort=${d ?? r}
1916
+ @mousedown=${(n) => this._onHeaderMouseDown(n, e, t)}
1917
+ @click=${i ? (t) => this._onHeaderClick(t, e) : void 0}>
1918
+ <span>${e.header}</span>
1919
+ ${a ? n`<span class="ft-sort-indicator">${a.direction === "asc" ? "▲" : "▼"}</span>` : ""}
1920
+ ${o >= 0 ? n`<span class="ft-sort-order">${o + 1}</span>` : ""}
1921
+ ${this.showFilters ? n`
1922
+ <button class="ft-filter-btn ${s ? "ft-filter-active" : ""}"
1923
+ title="Filter"
1924
+ aria-label=${`Filter ${e.header}`}
1925
+ aria-expanded=${this._openFilterKey === e.key ? "true" : "false"}
1926
+ @click=${(t) => this._onFilterBtnClick(t, e)}>
1927
+ \u25BD
1928
+ </button>
1929
+ ` : ""}
1930
+ <div class="ft-resize-handle"
1931
+ @mousedown=${(e) => {
1932
+ e.stopPropagation(), this._onResizeStart(e, t);
1933
+ }}
1934
+ @dblclick=${(e) => this._onResizeAutoFit(e, t)}></div>
1935
+ </div>
1936
+ ${this._openFilterKey === e.key ? this._renderFilterDropdown(e) : ""}
1937
+ `;
1938
+ }
1939
+ _adjustFilterDropdown() {
1940
+ if (!this._openFilterKey) return;
1941
+ let e = this.shadowRoot?.querySelector(".ft-filter-dropdown");
1942
+ if (!e) return;
1943
+ e.style.top = "", e.style.bottom = "";
1944
+ let t = e.getBoundingClientRect(), n = window.innerHeight;
1945
+ t.bottom > n && (e.style.top = "auto", e.style.bottom = "100%");
1946
+ }
1947
+ _onFilterBtnClick(e, t) {
1948
+ e.preventDefault(), e.stopPropagation();
1949
+ let n = this._openFilterKey === t.key ? null : t.key;
1950
+ this._openFilterKey = n, n && requestAnimationFrame(() => {
1951
+ document.addEventListener("click", this._onDocumentClick, { once: !0 });
1952
+ });
1953
+ }
1954
+ _renderFilterDropdown(e) {
1955
+ let t = e.type ?? "text";
1956
+ return n`
1957
+ <div class="ft-filter-dropdown" @click=${(e) => e.stopPropagation()}>
1958
+ ${t === "boolean" ? this._renderBooleanFilter(e) : t === "number" ? this._renderNumberFilter(e) : t === "date" || t === "datetime" ? this._renderDateFilter(e) : this._renderTextFilter(e)}
1959
+ <div class="ft-filter-actions">
1960
+ <button class="ft-filter-clear" @click=${() => this._clearColumnFilter(e.key)}>Clear</button>
1961
+ </div>
1962
+ </div>
1963
+ `;
1964
+ }
1965
+ _renderTextFilter(e) {
1966
+ return n`
1967
+ <input class="ft-filter-input" type="text" placeholder="Search..."
1968
+ .value=${this._textFilterState.get(e.key) ?? ""}
1969
+ @input=${(t) => {
1970
+ let n = t.target.value;
1971
+ this._textFilterState.set(e.key, n), n ? this.setFilter(e.key, (e) => String(e ?? "").toLowerCase().includes(n.toLowerCase())) : this.removeFilter(e.key);
1972
+ }}
1973
+ @keydown=${(e) => {
1974
+ e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
1975
+ }}>
1976
+ `;
1977
+ }
1978
+ _renderNumberFilter(e) {
1979
+ let t = this._numberFilterState.get(e.key) ?? {};
1980
+ return n`
1981
+ <div class="ft-filter-range">
1982
+ <input class="ft-filter-input" type="number" placeholder="Min"
1983
+ .value=${t.min == null ? "" : String(t.min)}
1984
+ @input=${(t) => this._applyNumberFilter(e.key, t, "min")}
1985
+ @keydown=${(e) => {
1986
+ e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
1987
+ }}>
1988
+ <input class="ft-filter-input" type="number" placeholder="Max"
1989
+ .value=${t.max == null ? "" : String(t.max)}
1990
+ @input=${(t) => this._applyNumberFilter(e.key, t, "max")}
1991
+ @keydown=${(e) => {
1992
+ e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
1993
+ }}>
1994
+ </div>
1995
+ `;
1996
+ }
1997
+ _cellKey(e, t) {
1998
+ return `${e}:${t}`;
1999
+ }
2000
+ _markCellInvalid(e, t, n) {
2001
+ let r = this._cellKey(e, t), i = this._invalidCells.get(r);
2002
+ i && clearTimeout(i.timer);
2003
+ let a = setTimeout(() => {
2004
+ this._invalidCells.delete(r), this.requestUpdate();
2005
+ }, 3e3);
2006
+ this._invalidCells.set(r, {
2007
+ error: n,
2008
+ timer: a
2009
+ }), this.requestUpdate();
2010
+ }
2011
+ _isCellInvalid(e, t) {
2012
+ let n = this._invalidCells.get(this._cellKey(e, t));
2013
+ return n ? n.error : null;
2014
+ }
2015
+ _applyNumberFilter(e, t, n) {
2016
+ let r = t.target.value, i = this._numberFilterState.get(e) ?? {};
2017
+ r === "" ? delete i[n] : i[n] = Number(r), this._numberFilterState.set(e, i), i.min == null && i.max == null ? this.removeFilter(e) : this.setFilter(e, (e) => {
2018
+ let t = Number(e);
2019
+ return !(isNaN(t) || i.min != null && t < i.min || i.max != null && t > i.max);
2020
+ });
2021
+ }
2022
+ _renderDateFilter(e) {
2023
+ let t = e.type === "datetime" ? "datetime-local" : "date", r = this._dateFilterState.get(e.key) ?? {};
2024
+ return n`
2025
+ <div class="ft-filter-range">
2026
+ <input class="ft-filter-input" type=${t} placeholder="From"
2027
+ .value=${r.from ?? ""}
2028
+ @input=${(t) => this._applyDateFilter(e.key, t, "from")}
2029
+ @keydown=${(e) => {
2030
+ e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
2031
+ }}>
2032
+ <input class="ft-filter-input" type=${t} placeholder="To"
2033
+ .value=${r.to ?? ""}
2034
+ @input=${(t) => this._applyDateFilter(e.key, t, "to")}
2035
+ @keydown=${(e) => {
2036
+ e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
2037
+ }}>
2038
+ </div>
2039
+ `;
2040
+ }
2041
+ _applyDateFilter(e, t, n) {
2042
+ let r = t.target.value, i = this._dateFilterState.get(e) ?? {};
2043
+ r === "" ? delete i[n] : i[n] = r, this._dateFilterState.set(e, i), i.from == null && i.to == null ? this.removeFilter(e) : this.setFilter(e, (e) => {
2044
+ if (e == null || e === "") return !1;
2045
+ let t = e instanceof Date ? e : new Date(String(e));
2046
+ if (isNaN(t.getTime()) || i.from && t < new Date(i.from)) return !1;
2047
+ if (i.to) {
2048
+ let e = new Date(i.to);
2049
+ if (i.to.length === 10 && e.setHours(23, 59, 59, 999), t > e) return !1;
2050
+ }
2051
+ return !0;
2052
+ });
2053
+ }
2054
+ _renderBooleanFilter(e) {
2055
+ return n`
2056
+ <select class="ft-filter-input"
2057
+ @change=${(t) => {
2058
+ let n = t.target.value;
2059
+ n === "all" ? this.removeFilter(e.key) : this.setFilter(e.key, (e) => !!e == (n === "true"));
2060
+ }}
2061
+ @keydown=${(e) => {
2062
+ e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
2063
+ }}>
2064
+ <option value="all">All</option>
2065
+ <option value="true">\u2714 True</option>
2066
+ <option value="false">\u2718 False</option>
2067
+ </select>
2068
+ `;
2069
+ }
2070
+ _clearColumnFilter(e) {
2071
+ this.removeFilter(e), this._textFilterState.delete(e), this._numberFilterState.delete(e), this._dateFilterState.delete(e), this._openFilterKey = null;
2072
+ }
2073
+ _onResizeAutoFit(e, t) {
2074
+ e.preventDefault(), e.stopPropagation();
2075
+ let n = this.visibleColumns[t];
2076
+ if (!n) return;
2077
+ let r = this.shadowRoot?.querySelectorAll(`.ft-cell[data-col-index="${t}"]`), i = 0, a = this.shadowRoot?.querySelector(`.ft-header-cell[data-col-index="${t}"]`);
2078
+ if (a && (i = Math.max(i, a.scrollWidth)), r) for (let e of r) i = Math.max(i, e.scrollWidth);
2079
+ let o = n.minWidth ?? z, s = Math.max(o, i + 8);
2080
+ this._columnWidths.set(n.key, s), this.requestUpdate(), this.dispatchEvent(new CustomEvent("column-resize", {
2081
+ detail: {
2082
+ key: n.key,
2083
+ width: s,
2084
+ colIndex: t
2085
+ },
2086
+ bubbles: !0,
2087
+ composed: !0
2088
+ }));
2089
+ }
2090
+ _onResizeStart(e, t) {
2091
+ e.preventDefault(), e.stopPropagation();
2092
+ let n = this.visibleColumns[t], r = this._columnWidths.get(n.key) ?? n.width ?? R;
2093
+ this._resizing = {
2094
+ colIndex: t,
2095
+ startX: e.clientX,
2096
+ startWidth: r
2097
+ };
2098
+ let i = (e) => {
2099
+ if (!this._resizing) return;
2100
+ let t = e.clientX - this._resizing.startX, r = n.minWidth ?? z, i = Math.max(r, this._resizing.startWidth + t);
2101
+ this._columnWidths.set(n.key, i), this.requestUpdate();
2102
+ }, a = () => {
2103
+ document.removeEventListener("mousemove", i), document.removeEventListener("mouseup", o), this._resizeCleanup = null;
2104
+ }, o = () => {
2105
+ if (a(), this._resizing) {
2106
+ let e = this._columnWidths.get(n.key) ?? R;
2107
+ this.dispatchEvent(new CustomEvent("column-resize", {
2108
+ detail: {
2109
+ key: n.key,
2110
+ width: e,
2111
+ colIndex: t
2112
+ },
2113
+ bubbles: !0,
2114
+ composed: !0
2115
+ })), this._resizing = null;
2116
+ }
2117
+ };
2118
+ document.addEventListener("mousemove", i), document.addEventListener("mouseup", o), this._resizeCleanup = a;
2119
+ }
2120
+ _onHeaderMouseDown(e, t, n) {
2121
+ if (e.button !== 0) return;
2122
+ e.preventDefault(), this._colDrag = {
2123
+ col: t,
2124
+ colIndex: n,
2125
+ startX: e.clientX,
2126
+ ghost: null,
2127
+ active: !1,
2128
+ targetIndex: n
2129
+ };
2130
+ let r = (e) => {
2131
+ if (!this._colDrag) return;
2132
+ let t = Math.abs(e.clientX - this._colDrag.startX);
2133
+ !this._colDrag.active && t > 5 && (this._colDrag.active = !0, this._startColumnGhost(e), this.requestUpdate()), this._colDrag.active && this._updateColumnDrag(e);
2134
+ }, i = (e) => {
2135
+ document.removeEventListener("mousemove", r), document.removeEventListener("mouseup", i), this._colDrag?.active && this._finishColumnDrag(), this._colDrag?.ghost && this._colDrag.ghost.remove(), this._colDrag = null, this._colDragIndicatorLeft = null, this.requestUpdate();
2136
+ };
2137
+ document.addEventListener("mousemove", r), document.addEventListener("mouseup", i);
2138
+ }
2139
+ _startColumnGhost(e) {
2140
+ let t = document.createElement("div");
2141
+ t.textContent = this._colDrag.col.header ?? this._colDrag.col.key, t.style.cssText = [
2142
+ "position:fixed",
2143
+ "pointer-events:none",
2144
+ "z-index:9999",
2145
+ "opacity:0.85",
2146
+ `background:${getComputedStyle(this).getPropertyValue("--ft-header-bg") || "#f0f0f0"}`,
2147
+ `border:2px solid ${getComputedStyle(this).getPropertyValue("--ft-active-color") || "#3b82f6"}`,
2148
+ "padding:4px 10px",
2149
+ "border-radius:4px",
2150
+ "font-size:13px",
2151
+ "font-weight:600",
2152
+ "white-space:nowrap",
2153
+ `left:${e.clientX + 12}px`,
2154
+ `top:${e.clientY - 14}px`
2155
+ ].join(";"), document.body.appendChild(t), this._colDrag.ghost = t;
2156
+ }
2157
+ _updateColumnDrag(e) {
2158
+ if (!this._colDrag) return;
2159
+ this._colDrag.ghost && (this._colDrag.ghost.style.left = `${e.clientX + 12}px`, this._colDrag.ghost.style.top = `${e.clientY - 14}px`);
2160
+ let t = this.getBoundingClientRect(), n = this._scrollLeft, r = this.visibleColumns, i = e.clientX - t.left + n, a = r.length;
2161
+ for (let e = 0; e < r.length; e++) if (i < (this._colLeftOffsets[e] ?? 0) + this._getColWidth(r[e]) / 2) {
2162
+ a = e;
2163
+ break;
2164
+ }
2165
+ this._colDrag.colIndex < a && a--, this._colDrag.targetIndex = a;
2166
+ let o = a < r.length ? a : r.length - 1, s = a < r.length ? this._colLeftOffsets[o] ?? 0 : (this._colLeftOffsets[o] ?? 0) + this._getColWidth(r[o]);
2167
+ this._colDragIndicatorLeft = s - n + this._prefixWidth, this.requestUpdate();
2168
+ }
2169
+ _finishColumnDrag() {
2170
+ if (!this._colDrag) return;
2171
+ let { col: e, colIndex: t, targetIndex: n } = this._colDrag;
2172
+ n !== t && this.moveColumn(e.key, n);
2173
+ }
2174
+ _onFillHandleMouseDown(e) {
2175
+ if (e.button !== 0) return;
2176
+ e.preventDefault(), e.stopPropagation();
2177
+ let t = this._selection.getEffectiveRange();
2178
+ if (!t) return;
2179
+ this._fillDrag = {
2180
+ sourceRange: t,
2181
+ targetRange: null,
2182
+ active: !1
2183
+ };
2184
+ let n = (e) => {
2185
+ this._fillDrag && (this._fillDrag.active = !0, this._updateFillDrag(e));
2186
+ }, r = () => {
2187
+ document.removeEventListener("mousemove", n), document.removeEventListener("mouseup", r), this._fillDrag?.active && this._fillDrag.targetRange && this._applyFillHandle(this._fillDrag.sourceRange, this._fillDrag.targetRange), this._fillDrag = null, this.requestUpdate();
2188
+ };
2189
+ document.addEventListener("mousemove", n), document.addEventListener("mouseup", r);
2190
+ }
2191
+ _updateFillDrag(e) {
2192
+ if (!this._fillDrag) return;
2193
+ let t = this.getBoundingClientRect(), n = e.clientX - t.left + this._scrollLeft - this._prefixWidth, r = e.clientY - t.top + this._scrollTop - this.headerHeight, i = this.visibleColumns, a = 0;
2194
+ for (let e = 0; e < i.length; e++) (this._colLeftOffsets[e] ?? 0) <= n && (a = e);
2195
+ let o = Math.max(0, Math.min(this._visibleRowCount - 1, Math.floor(r / this.rowHeight))), { sourceRange: s } = this._fillDrag, c = o - s.endRow, l = a - s.endCol, u;
2196
+ u = Math.abs(c) >= Math.abs(l) ? c >= 0 ? {
2197
+ ...s,
2198
+ endRow: o
2199
+ } : {
2200
+ ...s,
2201
+ startRow: Math.min(o, s.startRow)
2202
+ } : l >= 0 ? {
2203
+ ...s,
2204
+ endCol: a
2205
+ } : {
2206
+ ...s,
2207
+ startCol: Math.min(a, s.startCol)
2208
+ }, this._fillDrag.targetRange = u, this.requestUpdate();
2209
+ }
2210
+ _applyFillHandle(e, t) {
2211
+ let n = this.visibleColumns, r = [];
2212
+ for (let i = t.startCol; i <= t.endCol; i++) {
2213
+ let a = n[i], o = [];
2214
+ for (let t = e.startRow; t <= e.endRow; t++) o.push(this.data[this._toDataIndex(t)][a.key]);
2215
+ let s = this._detectNumericSeries(o);
2216
+ for (let n = t.startRow; n <= t.endRow; n++) {
2217
+ if (n >= e.startRow && n <= e.endRow) continue;
2218
+ let t = this._toDataIndex(n), i = this.data[t][a.key], c;
2219
+ if (s && n > e.endRow) {
2220
+ let t = n - e.endRow, r = s.last + s.diff * t;
2221
+ c = a.type === "number" ? r : String(r);
2222
+ } else {
2223
+ let t = (n - e.startRow) % o.length;
2224
+ c = o[t < 0 ? t + o.length : t];
2225
+ }
2226
+ this.data[t][a.key] = c, r.push({
2227
+ dataRow: t,
2228
+ key: a.key,
2229
+ oldValue: i,
2230
+ newValue: c
2231
+ });
2232
+ }
2233
+ }
2234
+ r.length > 0 && (this._undo.push({
2235
+ label: "fill-handle",
2236
+ undo: () => {
2237
+ for (let e of r) this.data[e.dataRow][e.key] = e.oldValue;
2238
+ this.requestUpdate();
2239
+ },
2240
+ redo: () => {
2241
+ for (let e of r) this.data[e.dataRow][e.key] = e.newValue;
2242
+ this.requestUpdate();
2243
+ }
2244
+ }), this._dispatchUndoStateEvent(), this.dispatchEvent(new CustomEvent("fill-handle-apply", {
2245
+ detail: {
2246
+ sourceRange: e,
2247
+ targetRange: t,
2248
+ cells: r
2249
+ },
2250
+ bubbles: !0,
2251
+ composed: !0
2252
+ }))), this.requestUpdate();
2253
+ }
2254
+ _detectNumericSeries(e) {
2255
+ if (e.length < 2) return null;
2256
+ let t = e.map((e) => Number(e));
2257
+ if (t.some((e) => isNaN(e))) return null;
2258
+ let n = t[1] - t[0];
2259
+ for (let e = 2; e < t.length; e++) if (Math.abs(t[e] - t[e - 1] - n) > 1e-9) return null;
2260
+ return {
2261
+ last: t[t.length - 1],
2262
+ diff: n
2263
+ };
2264
+ }
2265
+ _renderFillHandle() {
2266
+ if (!this.editable) return "";
2267
+ let e = this._selection.getEffectiveRange();
2268
+ if (!e) return "";
2269
+ let t = this.visibleColumns;
2270
+ if (e.endCol >= t.length || e.endRow >= this._visibleRowCount) return "";
2271
+ let r = this._prefixWidth + (this._colLeftOffsets[e.endCol] ?? 0) + this._getColWidth(t[e.endCol]) - this._scrollLeft - 4, i = this.headerHeight + (e.endRow + 1) * this.rowHeight - this._scrollTop - 4;
2272
+ return r < 0 || i < this.headerHeight ? "" : n`
2273
+ ${this._fillDrag?.active && this._fillDrag.targetRange ? this._renderFillPreview(this._fillDrag.targetRange) : ""}
2274
+ <div class="ft-fill-handle"
2275
+ style="left:${r}px;top:${i}px;"
2276
+ @mousedown=${(e) => this._onFillHandleMouseDown(e)}>
2277
+ </div>
2278
+ `;
2279
+ }
2280
+ _renderFillPreview(e) {
2281
+ let t = this.visibleColumns;
2282
+ return e.endCol >= t.length || e.endRow >= this._visibleRowCount ? "" : n`<div class="ft-fill-preview" style="left:${this._prefixWidth + (this._colLeftOffsets[e.startCol] ?? 0) - this._scrollLeft}px;top:${this.headerHeight + e.startRow * this.rowHeight - this._scrollTop}px;width:${(this._colLeftOffsets[e.endCol] ?? 0) + this._getColWidth(t[e.endCol]) - (this._colLeftOffsets[e.startCol] ?? 0)}px;height:${(e.endRow - e.startRow + 1) * this.rowHeight}px;"></div>`;
2283
+ }
2284
+ _onRowNumMouseDown(e, t) {
2285
+ if (e.button !== 0) return;
2286
+ e.preventDefault(), e.stopPropagation(), this._rowDrag = {
2287
+ rowIndex: t,
2288
+ startY: e.clientY,
2289
+ ghost: null,
2290
+ active: !1,
2291
+ targetIndex: t
2292
+ };
2293
+ let n = (e) => {
2294
+ if (!this._rowDrag) return;
2295
+ let n = Math.abs(e.clientY - this._rowDrag.startY);
2296
+ !this._rowDrag.active && n > 5 && (this._rowDrag.active = !0, this._startRowGhost(e, t), this.requestUpdate()), this._rowDrag.active && this._updateRowDrag(e);
2297
+ }, r = () => {
2298
+ document.removeEventListener("mousemove", n), document.removeEventListener("mouseup", r), this._rowDrag?.active && this._finishRowDrag(), this._rowDrag?.ghost && this._rowDrag.ghost.remove(), this._rowDrag = null, this._rowDragIndicatorY = null, this.requestUpdate();
2299
+ };
2300
+ document.addEventListener("mousemove", n), document.addEventListener("mouseup", r);
2301
+ }
2302
+ _startRowGhost(e, t) {
2303
+ let n = this._toDataIndex(t), r = this.data[n], i = this.visibleColumns[0] ? String(r[this.visibleColumns[0].key] ?? n + 1) : String(n + 1), a = document.createElement("div");
2304
+ a.textContent = i, a.style.cssText = [
2305
+ "position:fixed",
2306
+ "pointer-events:none",
2307
+ "z-index:9999",
2308
+ "opacity:0.85",
2309
+ "background:#e8f0fe",
2310
+ "border:2px solid #3b82f6",
2311
+ "padding:3px 10px",
2312
+ "border-radius:3px",
2313
+ "font-size:12px",
2314
+ "white-space:nowrap",
2315
+ `left:${e.clientX + 12}px`,
2316
+ `top:${e.clientY - 10}px`
2317
+ ].join(";"), document.body.appendChild(a), this._rowDrag.ghost = a;
2318
+ }
2319
+ _updateRowDrag(e) {
2320
+ if (!this._rowDrag) return;
2321
+ this._rowDrag.ghost && (this._rowDrag.ghost.style.left = `${e.clientX + 12}px`, this._rowDrag.ghost.style.top = `${e.clientY - 10}px`);
2322
+ let t = this.getBoundingClientRect(), n = e.clientY - t.top + this._scrollTop - this.headerHeight, r = this.rowHeight, i = Math.round(n / r);
2323
+ i = Math.max(0, Math.min(this._visibleRowCount, i)), this._rowDrag.rowIndex < i && i--, this._rowDrag.targetIndex = i;
2324
+ let a = this.headerHeight + i * r - this._scrollTop;
2325
+ this._rowDragIndicatorY = Math.max(this.headerHeight, Math.min(a, t.height)), this.requestUpdate();
2326
+ }
2327
+ _finishRowDrag() {
2328
+ if (!this._rowDrag) return;
2329
+ let { rowIndex: e, targetIndex: t } = this._rowDrag;
2330
+ if (t === e) return;
2331
+ let n = this._toDataIndex(e), r = this._toDataIndex(t), i = [...this.data], a = [...this.data], [o] = a.splice(n, 1);
2332
+ a.splice(r, 0, o), this.data = a, this._undo.push({
2333
+ label: "row-reorder",
2334
+ undo: () => {
2335
+ this.data = [...i], this.requestUpdate();
2336
+ },
2337
+ redo: () => {
2338
+ this.data = [...a], this.requestUpdate();
2339
+ }
2340
+ }), this._dispatchUndoStateEvent(), this.dispatchEvent(new CustomEvent("row-reorder", {
2341
+ detail: {
2342
+ from: n,
2343
+ to: r
2344
+ },
2345
+ bubbles: !0,
2346
+ composed: !0
2347
+ }));
2348
+ }
2349
+ _toggleFindPanel(e) {
2350
+ if (this._findState?.mode === e) {
2351
+ this._closeFindPanel();
2352
+ return;
2353
+ }
2354
+ this._openFindPanel(e);
2355
+ }
2356
+ _openFindPanel(e) {
2357
+ this._findState = {
2358
+ mode: e,
2359
+ query: this._findState?.query ?? "",
2360
+ replaceWith: this._findState?.replaceWith ?? "",
2361
+ matchCase: !1,
2362
+ wholeCell: !1,
2363
+ results: [],
2364
+ currentIndex: 0
2365
+ }, this._findState.query && this._findSearch(), this.requestUpdate(), requestAnimationFrame(() => {
2366
+ this.shadowRoot?.querySelector(".ft-find-input")?.focus();
2367
+ });
2368
+ }
2369
+ _closeFindPanel() {
2370
+ this._findState = null, this.requestUpdate();
2371
+ }
2372
+ _findSearch() {
2373
+ if (!this._findState) return;
2374
+ let { query: e, matchCase: t, wholeCell: n } = this._findState;
2375
+ if (!e) {
2376
+ this._findState.results = [], this._findState.currentIndex = 0, this.requestUpdate();
2377
+ return;
2378
+ }
2379
+ let r = t ? e : e.toLowerCase(), i = this.visibleColumns, a = [];
2380
+ for (let e = 0; e < this._visibleRowCount; e++) {
2381
+ let o = this._toDataIndex(e);
2382
+ for (let s = 0; s < i.length; s++) {
2383
+ let c = String(this.data[o][i[s].key] ?? ""), l = t ? c : c.toLowerCase();
2384
+ (n ? l === r : l.includes(r)) && a.push({
2385
+ row: e,
2386
+ col: s
2387
+ });
2388
+ }
2389
+ }
2390
+ this._findState.results = a, this._findState.currentIndex = 0, this.requestUpdate();
2391
+ }
2392
+ _findGoTo(e) {
2393
+ if (!this._findState || this._findState.results.length === 0) return;
2394
+ let t = this._findState.results.length;
2395
+ this._findState.currentIndex = (e % t + t) % t;
2396
+ let { row: n, col: r } = this._findState.results[this._findState.currentIndex];
2397
+ this._selection.setActive(n, r), this._activeCell = {
2398
+ row: n,
2399
+ col: r
2400
+ }, this._scrollToActiveCell(), this.requestUpdate();
2401
+ }
2402
+ _findNext() {
2403
+ this._findState && this._findGoTo(this._findState.currentIndex + 1);
2404
+ }
2405
+ _findPrev() {
2406
+ this._findState && this._findGoTo(this._findState.currentIndex - 1);
2407
+ }
2408
+ _replaceAll() {
2409
+ if (!this._findState || this._findState.results.length === 0) return;
2410
+ let { results: e, replaceWith: t } = this._findState, n = this.visibleColumns, r = [];
2411
+ for (let { row: i, col: a } of e) {
2412
+ let e = this._toDataIndex(i), o = n[a].key, s = this.data[e][o];
2413
+ this.data[e][o] = t, r.push({
2414
+ dataRow: e,
2415
+ key: o,
2416
+ oldValue: s,
2417
+ newValue: t
2418
+ });
2419
+ }
2420
+ r.length > 0 && (this._undo.push({
2421
+ label: "replace-all",
2422
+ undo: () => {
2423
+ for (let e of r) this.data[e.dataRow][e.key] = e.oldValue;
2424
+ this.requestUpdate();
2425
+ },
2426
+ redo: () => {
2427
+ for (let e of r) this.data[e.dataRow][e.key] = e.newValue;
2428
+ this.requestUpdate();
2429
+ }
2430
+ }), this._dispatchUndoStateEvent(), this.dispatchEvent(new CustomEvent("find-replace", {
2431
+ detail: {
2432
+ type: "replace-all",
2433
+ cells: r.map((e) => ({
2434
+ row: e.dataRow,
2435
+ col: e.key,
2436
+ oldValue: e.oldValue,
2437
+ newValue: e.newValue
2438
+ }))
2439
+ },
2440
+ bubbles: !0,
2441
+ composed: !0
2442
+ }))), this._findState.results = [], this._findState.currentIndex = 0, this.requestUpdate();
2443
+ }
2444
+ _replaceOne() {
2445
+ if (!this._findState || this._findState.results.length === 0) return;
2446
+ let { currentIndex: e, results: t, replaceWith: n } = this._findState, { row: r, col: i } = t[e], a = this._toDataIndex(r), o = this.visibleColumns[i].key, s = this.data[a][o];
2447
+ this.data[a][o] = n, this._undo.push({
2448
+ label: "replace",
2449
+ undo: () => {
2450
+ this.data[a][o] = s, this.requestUpdate();
2451
+ },
2452
+ redo: () => {
2453
+ this.data[a][o] = n, this.requestUpdate();
2454
+ }
2455
+ }), this._dispatchUndoStateEvent(), this.dispatchEvent(new CustomEvent("find-replace", {
2456
+ detail: {
2457
+ type: "replace",
2458
+ cells: [{
2459
+ row: a,
2460
+ col: o,
2461
+ oldValue: s,
2462
+ newValue: n
2463
+ }]
2464
+ },
2465
+ bubbles: !0,
2466
+ composed: !0
2467
+ })), this._findSearch(), this._findGoTo(Math.min(e, this._findState.results.length - 1));
2468
+ }
2469
+ _renderFindPanel() {
2470
+ if (!this._findState) return "";
2471
+ let { mode: e, query: t, replaceWith: r, matchCase: i, wholeCell: a, results: o, currentIndex: s } = this._findState, c = o.length, l = c > 0 ? s + 1 : 0;
2472
+ return n`
2473
+ <div class="ft-find-panel"
2474
+ @keydown=${(e) => {
2475
+ if (e.stopPropagation(), e.key === "Escape") {
2476
+ this._closeFindPanel();
2477
+ return;
2478
+ }
2479
+ e.key === "Enter" && e.target instanceof HTMLInputElement && e.target.classList.contains("ft-find-input") && (e.shiftKey ? this._findPrev() : this._findNext());
2480
+ }}>
2481
+ <div class="ft-find-row">
2482
+ <input class="ft-find-input" type="text" placeholder="Find..."
2483
+ .value=${t}
2484
+ @input=${(e) => {
2485
+ this._findState.query = e.target.value, this._findSearch();
2486
+ }}>
2487
+ <span class="ft-find-count">${c > 0 ? `${l}/${c}` : t ? "0 results" : ""}</span>
2488
+ <button @click=${() => this._findPrev()} title="Previous (Shift+Enter)">◀</button>
2489
+ <button @click=${() => this._findNext()} title="Next (Enter)">▶</button>
2490
+ <label title="Match case"><input type="checkbox" ?checked=${i} @change=${(e) => {
2491
+ this._findState.matchCase = e.target.checked, this._findSearch();
2492
+ }}> Aa</label>
2493
+ <label title="Whole cell"><input type="checkbox" ?checked=${a} @change=${(e) => {
2494
+ this._findState.wholeCell = e.target.checked, this._findSearch();
2495
+ }}> [ ]</label>
2496
+ <button @click=${() => this._closeFindPanel()} title="Close (Escape)">✕</button>
2497
+ </div>
2498
+ ${e === "replace" ? n`
2499
+ <div class="ft-find-row">
2500
+ <input class="ft-find-replace-input" type="text" placeholder="Replace with..."
2501
+ .value=${r}
2502
+ @input=${(e) => {
2503
+ this._findState.replaceWith = e.target.value;
2504
+ }}>
2505
+ <button @click=${() => this._replaceOne()} ?disabled=${c === 0}>Replace</button>
2506
+ <button @click=${() => this._replaceAll()} ?disabled=${c === 0}>Replace All</button>
2507
+ </div>
2508
+ ` : ""}
2509
+ </div>
2510
+ `;
2511
+ }
2512
+ render() {
2513
+ let e = this.visibleColumns;
2514
+ if (e.length === 0) return n`<div class="ft-empty">No columns defined</div>`;
2515
+ let t = this.headerHeight, r = this._totalRowWidth, { start: i, end: a } = this.visibleColRange, o = [];
2516
+ for (let t = 0; t < e.length; t++) (e[t].pinned === "left" || e[t].pinned === "right") && (t < i || t >= a) && o.push(t);
2517
+ let s = 0, c = this._scrollLeft, l = this.selectable ? n`<div class="ft-checkbox-header"
2518
+ style="position: absolute; top: 0; left: ${c + s}px; width: 36px; height: ${t}px; z-index: 4;">
2519
+ ${this._rowSelection.mode === "multi" ? n`
2520
+ <input type="checkbox"
2521
+ .checked=${this._rowSelection.isAllSelected}
2522
+ .indeterminate=${this._rowSelection.isSomeSelected}
2523
+ @change=${this._onSelectAllChange}>
2524
+ ` : ""}
2525
+ </div>` : "";
2526
+ this.selectable && (s += 36);
2527
+ let u = this.showRowNumbers ? n`<div class="ft-row-num-header"
2528
+ style="position: absolute; top: 0; left: ${c + s}px; width: 48px; height: ${t}px; z-index: 4;">#</div>` : "", d = [];
2529
+ for (let t of o) d.push(this._renderHeaderCell(e[t], t));
2530
+ for (let t = i; t < a; t++) d.push(this._renderHeaderCell(e[t], t));
2531
+ let f = this._colDragIndicatorLeft == null ? "" : n`<div class="ft-drop-indicator" style="left:${this._colDragIndicatorLeft}px"></div>`;
2532
+ if (this.data.length === 0 || this._visibleRowCount === 0) return n`
2533
+ <div class="ft-header" role="row" style="width: ${r}px; height: ${t}px;">
2534
+ ${l}${u}
2535
+ ${d}
2536
+ ${f}
2537
+ </div>
2538
+ <div class="ft-empty">${this.data.length === 0 ? "No data" : "No matching data"}</div>
2539
+ `;
2540
+ let { start: p, end: m } = this.visibleRange, h = [];
2541
+ for (let e = p; e < m; e++) h.push(this._renderRow(e, i, a, o));
2542
+ let g = this._renderFillHandle(), _ = this._rowDragIndicatorY == null ? "" : n`<div class="ft-row-drop-indicator" style="top:${this._rowDragIndicatorY}px;width:${r + this._prefixWidth}px;"></div>`;
2543
+ return n`
2544
+ ${this._renderFindPanel()}
2545
+ <div class="ft-header" role="row" style="width: ${r}px; height: ${t}px;">
2546
+ ${l}${u}
2547
+ ${d}
2548
+ ${f}
2549
+ </div>
2550
+ <div class="ft-body" style="height: ${this.totalBodyHeight}px; width: ${r}px;">
2551
+ ${h}
2552
+ </div>
2553
+ ${this.footerData ? this._renderFooter(i, a, o) : ""}
2554
+ ${_}
2555
+ ${g}
2556
+ `;
2557
+ }
2558
+ _onSelectAllChange(e) {
2559
+ e.target.checked ? this._rowSelection.selectAll() : this._rowSelection.deselectAll(), this._rowSelectionVersion++, this._dispatchRowSelectionEvent();
2560
+ }
2561
+ _onRowCheckboxChange(e, t) {
2562
+ e.stopPropagation(), this._rowSelection.toggle(t), this._rowSelectionVersion++, this._dispatchRowSelectionEvent();
2563
+ }
2564
+ _renderFooter(e, t, r) {
2565
+ if (!this.footerData) return "";
2566
+ let i = this.visibleColumns, a = this.rowHeight, o = this._totalRowWidth, s = this._scrollLeft, c = 0, l = this.selectable ? n`<div class="ft-footer-cell ft-checkbox-cell"
2567
+ style="position: absolute; top: 0; left: ${s + c}px; width: 36px; height: ${a}px; z-index: 2;"></div>` : "";
2568
+ this.selectable && (c += 36);
2569
+ let u = this.showRowNumbers ? n`<div class="ft-footer-cell ft-row-num"
2570
+ style="position: absolute; top: 0; left: ${s + c}px; width: 48px; height: ${a}px; z-index: 2;"></div>` : "", d = [];
2571
+ for (let e of r) {
2572
+ let t = i[e], r = this._getColWidth(t), o = t.pinned === "right" ? `position: absolute; top: 0; right: ${-s + this._getPinnedRight(e)}px; width: ${r}px; height: ${a}px; z-index: 2;` : `position: absolute; top: 0; left: ${s + this._getPinnedLeft(e)}px; width: ${r}px; height: ${a}px; z-index: 2;`;
2573
+ d.push(n`
2574
+ <div class="ft-footer-cell ft-pinned" style=${o}>
2575
+ ${this.footerData[t.key] ?? ""}</div>
2576
+ `);
2577
+ }
2578
+ for (let r = e; r < t; r++) {
2579
+ let e = i[r], t = this._getColWidth(e), o = this._colLeftOffsets[r] ?? 0, c = e.pinned === "left", l = e.pinned === "right", u = c || l, f;
2580
+ f = c ? `position: absolute; top: 0; left: ${s + this._getPinnedLeft(r)}px; width: ${t}px; height: ${a}px; z-index: 2;` : l ? `position: absolute; top: 0; right: ${-s + this._getPinnedRight(r)}px; width: ${t}px; height: ${a}px; z-index: 2;` : `left: ${o}px; width: ${t}px; height: ${a}px;`, d.push(n`
2581
+ <div class="ft-footer-cell ${u ? "ft-pinned" : ""}" style=${f}>
2582
+ ${this.footerData[e.key] ?? ""}</div>
2583
+ `);
2584
+ }
2585
+ return n`
2586
+ <div class="ft-footer" role="row" style="width: ${o}px; height: ${a}px;">
2587
+ ${l}${u}
2588
+ ${d}
2589
+ </div>
2590
+ `;
2591
+ }
2592
+ _renderRow(e, t, r, i) {
2593
+ let a = this.visibleColumns, o = this._toDataIndex(e), s = this.data[o], c = e * this.rowHeight, l = this.rowHeight, u = this._totalRowWidth, d = e % 2 == 0 ? "ft-row-even" : "ft-row-odd", f = this.selectable && this._rowSelection.isSelected(e), p = this._scrollLeft, m = 0, h = this.selectable ? n`
2594
+ <div class="ft-checkbox-cell"
2595
+ style="position: absolute; top: 0; left: ${p + m}px; width: 36px; height: ${l}px; z-index: 2;">
2596
+ <input type="checkbox"
2597
+ .checked=${f}
2598
+ @change=${(t) => this._onRowCheckboxChange(t, e)}>
2599
+ </div>
2600
+ ` : "";
2601
+ this.selectable && (m += 36);
2602
+ let g = this._rowDrag?.active && this._rowDrag.rowIndex === e, _ = this.showRowNumbers ? n`
2603
+ <div class="ft-row-num ${g ? "ft-col-dragging" : ""}"
2604
+ style="position: absolute; top: 0; left: ${p + m}px; width: 48px; height: ${l}px; z-index: 2; cursor: grab;"
2605
+ @mousedown=${(t) => this._onRowNumMouseDown(t, e)}
2606
+ @click=${() => this._onRowNumberClick(e)}>${o + 1}</div>
2607
+ ` : "", v = [];
2608
+ for (let t of i) v.push(this._renderCell(s, a[t], e, t));
2609
+ for (let n = t; n < r; n++) v.push(this._renderCell(s, a[n], e, n));
2610
+ return n`
2611
+ <div class="ft-row ${d} ${f ? "ft-row-selected" : ""}" role="row"
2612
+ style="top: ${c}px; height: ${l}px; width: ${u}px;">
2613
+ ${h}${_}
2614
+ ${v}
2615
+ </div>
2616
+ `;
2617
+ }
2618
+ _renderCell(e, t, i, a) {
2619
+ let o = this._activeCell?.row === i && this._activeCell?.col === a, s = this._editingCell?.row === i && this._editingCell?.col === a, l = this._selection.isInRange(i, a), u = t.pinned === "left", d = t.pinned === "right", f = u || d, p = this._getColWidth(t), m = this.rowHeight, h = this._colLeftOffsets[a] ?? 0, g;
2620
+ g = u ? `position: absolute; top: 0; left: ${this._scrollLeft + this._getPinnedLeft(a)}px; width: ${p}px; height: ${m}px; z-index: 2;` : d ? `position: absolute; top: 0; right: ${-this._scrollLeft + this._getPinnedRight(a)}px; width: ${p}px; height: ${m}px; z-index: 2;` : `left: ${h}px; width: ${p}px; height: ${m}px;`;
2621
+ let _ = !this._isCellEditable(t);
2622
+ if (s) return n`
2623
+ <div class="ft-cell ft-editing ft-active ${f ? "ft-pinned" : ""}" role="gridcell"
2624
+ data-col-index=${a}
2625
+ aria-selected="true"
2626
+ aria-readonly=${_ ? "true" : r}
2627
+ style=${g}>
2628
+ ${this._renderEditor(e, t)}
2629
+ </div>
2630
+ `;
2631
+ let v = o || l, y = this._isCellInvalid(i, a), b = (this._findState?.results ?? []).findIndex((e) => e.row === i && e.col === a), x = b >= 0, S = x && b === this._findState.currentIndex;
2632
+ return n`
2633
+ <div class=${[
2634
+ "ft-cell",
2635
+ `ft-type-${t.type ?? "text"}`,
2636
+ o ? "ft-active" : "",
2637
+ l ? "ft-selected" : "",
2638
+ f ? "ft-pinned" : "",
2639
+ y ? "ft-invalid" : "",
2640
+ S ? "ft-find-current" : x ? "ft-find-match" : ""
2641
+ ].filter(Boolean).join(" ")}
2642
+ role="gridcell"
2643
+ data-col-index=${a}
2644
+ aria-selected=${v ? "true" : "false"}
2645
+ aria-readonly=${_ ? "true" : r}
2646
+ aria-invalid=${y ? "true" : r}
2647
+ title=${y ?? r}
2648
+ style=${g}
2649
+ @mousedown=${(e) => this._onCellMouseDown(e, i, a)}
2650
+ @mouseenter=${() => this._onCellMouseEnter(i, a)}
2651
+ @click=${(e) => this._onCellClickEvent(e, i, a)}
2652
+ @dblclick=${() => this._onCellDblClick(i, a)}>
2653
+ ${c(e[t.key], e, t)}
2654
+ </div>
2655
+ `;
2656
+ }
2657
+ _renderEditor(e, t) {
2658
+ if (t.editor) return t.editor(e[t.key], e, t);
2659
+ let r = e[t.key], i = r == null ? "" : String(r);
2660
+ if (t.type === "number") return n`
2661
+ <input class="ft-editor ft-editor-number" type="number"
2662
+ .value=${i}
2663
+ @keydown=${this._onEditorKeyDown}
2664
+ @blur=${() => this._commitEdit()}>
2665
+ `;
2666
+ if (t.type === "date") return n`
2667
+ <input class="ft-editor" type="date"
2668
+ .value=${this._toDateInputValue(r)}
2669
+ @keydown=${this._onEditorKeyDown}
2670
+ @blur=${() => this._commitEdit()}>
2671
+ `;
2672
+ if (t.type === "datetime") return n`
2673
+ <input class="ft-editor" type="datetime-local"
2674
+ .value=${this._toDateTimeInputValue(r)}
2675
+ @keydown=${this._onEditorKeyDown}
2676
+ @blur=${() => this._commitEdit()}>
2677
+ `;
2678
+ if (t.type === "select" && t.options && t.options.length > 0) {
2679
+ let e = t.options, i = typeof e[0] == "string";
2680
+ return n`
2681
+ <select class="ft-editor"
2682
+ @keydown=${this._onEditorKeyDown}
2683
+ @blur=${() => this._commitEdit()}
2684
+ @change=${() => this._commitEdit()}>
2685
+ ${i ? e.map((e) => n`<option value=${e} ?selected=${e === r}>${e}</option>`) : e.map((e) => n`<option value=${String(e.value)} ?selected=${e.value === r}>${e.label}</option>`)}
2686
+ </select>
2687
+ `;
2688
+ }
2689
+ return n`
2690
+ <input class="ft-editor" type="text"
2691
+ .value=${i}
2692
+ @keydown=${this._onEditorKeyDown}
2693
+ @blur=${() => this._commitEdit()}>
2694
+ `;
2695
+ }
2696
+ _toDateInputValue(e) {
2697
+ if (!e) return "";
2698
+ let t = e instanceof Date ? e : new Date(String(e));
2699
+ return isNaN(t.getTime()) ? "" : `${t.getFullYear()}-${String(t.getMonth() + 1).padStart(2, "0")}-${String(t.getDate()).padStart(2, "0")}`;
2700
+ }
2701
+ _toDateTimeInputValue(e) {
2702
+ if (!e) return "";
2703
+ let t = e instanceof Date ? e : new Date(String(e));
2704
+ return isNaN(t.getTime()) ? "" : `${t.getFullYear()}-${String(t.getMonth() + 1).padStart(2, "0")}-${String(t.getDate()).padStart(2, "0")}T${String(t.getHours()).padStart(2, "0")}:${String(t.getMinutes()).padStart(2, "0")}`;
2705
+ }
2706
+ };
2707
+ L([a({ type: Array })], H.prototype, "columns", void 0), L([a({
2708
+ type: Array,
2709
+ hasChanged: () => !0
2710
+ })], H.prototype, "data", void 0), L([a({
2711
+ type: Number,
2712
+ attribute: "row-height"
2713
+ })], H.prototype, "rowHeight", void 0), L([a({
2714
+ type: Boolean,
2715
+ attribute: "show-row-numbers"
2716
+ })], H.prototype, "showRowNumbers", void 0), L([a({
2717
+ type: String,
2718
+ reflect: !0
2719
+ })], H.prototype, "theme", void 0), L([a({
2720
+ type: Number,
2721
+ attribute: "max-rows"
2722
+ })], H.prototype, "maxRows", void 0), L([a({ type: Boolean })], H.prototype, "editable", void 0), L([a({
2723
+ type: Boolean,
2724
+ attribute: "show-filters"
2725
+ })], H.prototype, "showFilters", void 0), L([a({ type: Boolean })], H.prototype, "selectable", void 0), L([a({
2726
+ type: String,
2727
+ attribute: "selection-mode"
2728
+ })], H.prototype, "selectionMode", null), L([a({
2729
+ type: String,
2730
+ attribute: "data-mode"
2731
+ })], H.prototype, "dataMode", void 0), L([a({
2732
+ type: Object,
2733
+ attribute: "footer-data"
2734
+ })], H.prototype, "footerData", void 0), L([a({
2735
+ type: Number,
2736
+ attribute: "max-undo-size"
2737
+ })], H.prototype, "maxUndoSize", null), L([o()], H.prototype, "_scrollTop", void 0), L([o()], H.prototype, "_scrollLeft", void 0), L([o()], H.prototype, "_viewportHeight", void 0), L([o()], H.prototype, "_viewportWidth", void 0), L([o()], H.prototype, "_activeCell", void 0), L([o()], H.prototype, "_editingCell", void 0), L([o()], H.prototype, "_sortCriteria", void 0), L([o()], H.prototype, "_openFilterKey", void 0), L([o()], H.prototype, "_rowSelectionVersion", void 0), H = L([i("flex-table")], H);
2738
+ //#endregion
2739
+ export { c as a, _ as i, D as n, C as r, H as t };