@gradio/dataframe 0.15.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/Dataframe.stories.svelte +183 -2
- package/Example.svelte +7 -0
- package/Index.svelte +20 -3
- package/dist/Example.svelte +7 -0
- package/dist/Index.svelte +16 -4
- package/dist/Index.svelte.d.ts +12 -0
- package/dist/shared/CellMenu.svelte +1 -1
- package/dist/shared/EditableCell.svelte +1 -6
- package/dist/shared/Table.svelte +620 -319
- package/dist/shared/Table.svelte.d.ts +3 -0
- package/dist/shared/Toolbar.svelte +122 -30
- package/dist/shared/Toolbar.svelte.d.ts +4 -0
- package/dist/shared/VirtualTable.svelte +70 -26
- package/dist/shared/VirtualTable.svelte.d.ts +1 -0
- package/dist/shared/icons/FilterIcon.svelte +11 -0
- package/dist/shared/icons/FilterIcon.svelte.d.ts +16 -0
- package/dist/shared/icons/SortIcon.svelte +90 -0
- package/dist/shared/icons/SortIcon.svelte.d.ts +20 -0
- package/dist/shared/selection_utils.d.ts +12 -2
- package/dist/shared/selection_utils.js +33 -5
- package/dist/shared/types.d.ts +16 -0
- package/dist/shared/types.js +1 -0
- package/dist/shared/utils/menu_utils.d.ts +42 -0
- package/dist/shared/utils/menu_utils.js +58 -0
- package/dist/shared/utils/sort_utils.d.ts +7 -0
- package/dist/shared/utils/sort_utils.js +39 -0
- package/dist/shared/utils/table_utils.d.ts +12 -0
- package/dist/shared/utils/table_utils.js +148 -0
- package/package.json +8 -8
- package/shared/CellMenu.svelte +1 -1
- package/shared/EditableCell.svelte +1 -6
- package/shared/Table.svelte +649 -322
- package/shared/Toolbar.svelte +125 -30
- package/shared/VirtualTable.svelte +73 -26
- package/shared/icons/FilterIcon.svelte +12 -0
- package/shared/icons/SortIcon.svelte +95 -0
- package/shared/selection_utils.ts +51 -9
- package/shared/types.ts +27 -0
- package/shared/utils/menu_utils.ts +115 -0
- package/shared/utils/sort_utils.test.ts +71 -0
- package/shared/utils/sort_utils.ts +55 -0
- package/shared/utils/table_utils.test.ts +114 -0
- package/shared/utils/table_utils.ts +206 -0
- package/dist/shared/table_utils.d.ts +0 -12
- package/dist/shared/table_utils.js +0 -113
- package/shared/table_utils.ts +0 -148
package/shared/Table.svelte
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
} from "./utils";
|
|
17
17
|
import CellMenu from "./CellMenu.svelte";
|
|
18
18
|
import Toolbar from "./Toolbar.svelte";
|
|
19
|
+
import SortIcon from "./icons/SortIcon.svelte";
|
|
19
20
|
import type { CellCoordinate, EditingState } from "./types";
|
|
20
21
|
import {
|
|
21
22
|
is_cell_selected,
|
|
@@ -26,9 +27,17 @@
|
|
|
26
27
|
get_range_selection,
|
|
27
28
|
move_cursor,
|
|
28
29
|
get_current_indices,
|
|
29
|
-
handle_click_outside as handle_click_outside_util
|
|
30
|
+
handle_click_outside as handle_click_outside_util,
|
|
31
|
+
select_column,
|
|
32
|
+
select_row,
|
|
33
|
+
calculate_selection_positions
|
|
30
34
|
} from "./selection_utils";
|
|
31
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
copy_table_data,
|
|
37
|
+
get_max,
|
|
38
|
+
handle_file_upload,
|
|
39
|
+
sort_table_data
|
|
40
|
+
} from "./utils/table_utils";
|
|
32
41
|
|
|
33
42
|
export let datatype: Datatype | Datatype[];
|
|
34
43
|
export let label: string | null = null;
|
|
@@ -58,6 +67,14 @@
|
|
|
58
67
|
export let show_copy_button = false;
|
|
59
68
|
export let value_is_output = false;
|
|
60
69
|
export let max_chars: number | undefined = undefined;
|
|
70
|
+
export let show_search: "none" | "search" | "filter" = "none";
|
|
71
|
+
export let pinned_columns = 0;
|
|
72
|
+
|
|
73
|
+
let actual_pinned_columns = 0;
|
|
74
|
+
$: actual_pinned_columns =
|
|
75
|
+
pinned_columns && data?.[0]?.length
|
|
76
|
+
? Math.min(pinned_columns, data[0].length)
|
|
77
|
+
: 0;
|
|
61
78
|
|
|
62
79
|
let selected_cells: CellCoordinate[] = [];
|
|
63
80
|
$: selected_cells = [...selected_cells];
|
|
@@ -80,6 +97,7 @@
|
|
|
80
97
|
change: DataframeValue;
|
|
81
98
|
input: undefined;
|
|
82
99
|
select: SelectData;
|
|
100
|
+
search: string | null;
|
|
83
101
|
}>();
|
|
84
102
|
|
|
85
103
|
let editing: EditingState = false;
|
|
@@ -99,6 +117,19 @@
|
|
|
99
117
|
} | null = null;
|
|
100
118
|
let is_fullscreen = false;
|
|
101
119
|
let dragging = false;
|
|
120
|
+
let copy_flash = false;
|
|
121
|
+
|
|
122
|
+
let color_accent_copied: string;
|
|
123
|
+
onMount(() => {
|
|
124
|
+
const color = getComputedStyle(document.documentElement)
|
|
125
|
+
.getPropertyValue("--color-accent")
|
|
126
|
+
.trim();
|
|
127
|
+
color_accent_copied = color + "40"; // 80 is 50% opacity in hex
|
|
128
|
+
document.documentElement.style.setProperty(
|
|
129
|
+
"--color-accent-copied",
|
|
130
|
+
color_accent_copied
|
|
131
|
+
);
|
|
132
|
+
});
|
|
102
133
|
|
|
103
134
|
const get_data_at = (row: number, col: number): string | number =>
|
|
104
135
|
data?.[row]?.[col]?.value;
|
|
@@ -107,7 +138,14 @@
|
|
|
107
138
|
return Math.random().toString(36).substring(2, 15);
|
|
108
139
|
}
|
|
109
140
|
|
|
110
|
-
function make_headers(
|
|
141
|
+
function make_headers(
|
|
142
|
+
_head: Headers,
|
|
143
|
+
col_count: [number, "fixed" | "dynamic"],
|
|
144
|
+
els: Record<
|
|
145
|
+
string,
|
|
146
|
+
{ cell: null | HTMLTableCellElement; input: null | HTMLInputElement }
|
|
147
|
+
>
|
|
148
|
+
): HeadersWithIDs {
|
|
111
149
|
let _h = _head || [];
|
|
112
150
|
if (col_count[1] === "fixed" && _h.length < col_count[0]) {
|
|
113
151
|
const fill = Array(col_count[0] - _h.length)
|
|
@@ -138,15 +176,14 @@
|
|
|
138
176
|
id: string;
|
|
139
177
|
}[][] {
|
|
140
178
|
const data_row_length = _values.length;
|
|
179
|
+
if (data_row_length === 0) return [];
|
|
141
180
|
return Array(row_count[1] === "fixed" ? row_count[0] : data_row_length)
|
|
142
181
|
.fill(0)
|
|
143
|
-
.map((_, i) =>
|
|
144
|
-
Array(
|
|
182
|
+
.map((_, i) => {
|
|
183
|
+
return Array(
|
|
145
184
|
col_count[1] === "fixed"
|
|
146
185
|
? col_count[0]
|
|
147
|
-
:
|
|
148
|
-
? _values[0].length
|
|
149
|
-
: headers.length
|
|
186
|
+
: _values[0].length || headers.length
|
|
150
187
|
)
|
|
151
188
|
.fill(0)
|
|
152
189
|
.map((_, j) => {
|
|
@@ -155,16 +192,16 @@
|
|
|
155
192
|
const obj = { value: _values?.[i]?.[j] ?? "", id };
|
|
156
193
|
data_binding[id] = obj;
|
|
157
194
|
return obj;
|
|
158
|
-
})
|
|
159
|
-
);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
160
197
|
}
|
|
161
198
|
|
|
162
|
-
let _headers = make_headers(headers);
|
|
199
|
+
let _headers = make_headers(headers, col_count, els);
|
|
163
200
|
let old_headers: string[] = headers;
|
|
164
201
|
|
|
165
202
|
$: {
|
|
166
203
|
if (!dequal(headers, old_headers)) {
|
|
167
|
-
_headers = make_headers(headers);
|
|
204
|
+
_headers = make_headers(headers, col_count, els);
|
|
168
205
|
old_headers = JSON.parse(JSON.stringify(headers));
|
|
169
206
|
}
|
|
170
207
|
}
|
|
@@ -181,6 +218,8 @@
|
|
|
181
218
|
let previous_data = data.map((row) => row.map((cell) => String(cell.value)));
|
|
182
219
|
|
|
183
220
|
async function trigger_change(): Promise<void> {
|
|
221
|
+
// shouldnt trigger if data changed due to search
|
|
222
|
+
if (current_search_query) return;
|
|
184
223
|
const current_headers = _headers.map((h) => h.value);
|
|
185
224
|
const current_data = data.map((row) =>
|
|
186
225
|
row.map((cell) => String(cell.value))
|
|
@@ -312,8 +351,10 @@
|
|
|
312
351
|
editing = false;
|
|
313
352
|
} else {
|
|
314
353
|
selected_cells = [next_coords];
|
|
315
|
-
|
|
316
|
-
|
|
354
|
+
if (editable) {
|
|
355
|
+
editing = next_coords;
|
|
356
|
+
clear_on_focus = false;
|
|
357
|
+
}
|
|
317
358
|
}
|
|
318
359
|
selected = next_coords;
|
|
319
360
|
} else if (
|
|
@@ -333,27 +374,26 @@
|
|
|
333
374
|
editing = false;
|
|
334
375
|
break;
|
|
335
376
|
case "Enter":
|
|
336
|
-
if (!editable) break;
|
|
337
377
|
event.preventDefault();
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
await tick();
|
|
342
|
-
|
|
343
|
-
selected = [i + 1, j];
|
|
344
|
-
} else {
|
|
345
|
-
if (dequal(editing, [i, j])) {
|
|
346
|
-
const cell_id = data[i][j].id;
|
|
347
|
-
const input_el = els[cell_id].input;
|
|
348
|
-
if (input_el) {
|
|
349
|
-
data[i][j].value = input_el.value;
|
|
350
|
-
}
|
|
351
|
-
editing = false;
|
|
378
|
+
if (editable) {
|
|
379
|
+
if (event.shiftKey) {
|
|
380
|
+
add_row(i);
|
|
352
381
|
await tick();
|
|
353
|
-
selected = [i, j];
|
|
382
|
+
selected = [i + 1, j];
|
|
354
383
|
} else {
|
|
355
|
-
editing
|
|
356
|
-
|
|
384
|
+
if (dequal(editing, [i, j])) {
|
|
385
|
+
const cell_id = data[i][j].id;
|
|
386
|
+
const input_el = els[cell_id].input;
|
|
387
|
+
if (input_el) {
|
|
388
|
+
data[i][j].value = input_el.value;
|
|
389
|
+
}
|
|
390
|
+
editing = false;
|
|
391
|
+
await tick();
|
|
392
|
+
selected = [i, j];
|
|
393
|
+
} else {
|
|
394
|
+
editing = [i, j];
|
|
395
|
+
clear_on_focus = false;
|
|
396
|
+
}
|
|
357
397
|
}
|
|
358
398
|
}
|
|
359
399
|
break;
|
|
@@ -390,15 +430,16 @@
|
|
|
390
430
|
let sort_direction: SortDirection | undefined;
|
|
391
431
|
let sort_by: number | undefined;
|
|
392
432
|
|
|
393
|
-
function handle_sort(col: number): void {
|
|
433
|
+
function handle_sort(col: number, direction: SortDirection): void {
|
|
394
434
|
if (typeof sort_by !== "number" || sort_by !== col) {
|
|
395
|
-
sort_direction =
|
|
435
|
+
sort_direction = direction;
|
|
396
436
|
sort_by = col;
|
|
397
|
-
} else {
|
|
398
|
-
if (sort_direction ===
|
|
399
|
-
sort_direction =
|
|
400
|
-
|
|
401
|
-
|
|
437
|
+
} else if (sort_by === col) {
|
|
438
|
+
if (sort_direction === direction) {
|
|
439
|
+
sort_direction = undefined;
|
|
440
|
+
sort_by = undefined;
|
|
441
|
+
} else {
|
|
442
|
+
sort_direction = direction;
|
|
402
443
|
}
|
|
403
444
|
}
|
|
404
445
|
}
|
|
@@ -431,12 +472,8 @@
|
|
|
431
472
|
parent.focus();
|
|
432
473
|
|
|
433
474
|
if (row_count[1] !== "dynamic") return;
|
|
434
|
-
if (data.length === 0) {
|
|
435
|
-
values = [Array(headers.length).fill("")];
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
438
475
|
|
|
439
|
-
const new_row = Array(data[0].length)
|
|
476
|
+
const new_row = Array(data[0]?.length || headers.length)
|
|
440
477
|
.fill(0)
|
|
441
478
|
.map((_, i) => {
|
|
442
479
|
const _id = make_id();
|
|
@@ -444,7 +481,9 @@
|
|
|
444
481
|
return { id: _id, value: "" };
|
|
445
482
|
});
|
|
446
483
|
|
|
447
|
-
if (
|
|
484
|
+
if (data.length === 0) {
|
|
485
|
+
data = [new_row];
|
|
486
|
+
} else if (index !== undefined && index >= 0 && index <= data.length) {
|
|
448
487
|
data.splice(index, 0, new_row);
|
|
449
488
|
} else {
|
|
450
489
|
data.push(new_row);
|
|
@@ -501,16 +540,25 @@
|
|
|
501
540
|
let table: HTMLTableElement;
|
|
502
541
|
|
|
503
542
|
function set_cell_widths(): void {
|
|
504
|
-
const widths = cells.map((el
|
|
505
|
-
return el?.clientWidth || 0;
|
|
506
|
-
});
|
|
543
|
+
const widths = cells.map((el) => el?.clientWidth || 0);
|
|
507
544
|
if (widths.length === 0) return;
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
`${widths[i] - scrollbar_width / widths.length}px`
|
|
512
|
-
);
|
|
545
|
+
|
|
546
|
+
if (show_row_numbers) {
|
|
547
|
+
parent.style.setProperty(`--cell-width-row-number`, `${widths[0]}px`);
|
|
513
548
|
}
|
|
549
|
+
const data_cells = show_row_numbers ? widths.slice(1) : widths;
|
|
550
|
+
data_cells.forEach((width, i) => {
|
|
551
|
+
if (!column_widths[i]) {
|
|
552
|
+
parent.style.setProperty(
|
|
553
|
+
`--cell-width-${i}`,
|
|
554
|
+
`${width - scrollbar_width / data_cells.length}px`
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function get_cell_width(index: number): string {
|
|
561
|
+
return column_widths[index] || `var(--cell-width-${index})`;
|
|
514
562
|
}
|
|
515
563
|
|
|
516
564
|
let table_height: number =
|
|
@@ -525,39 +573,14 @@
|
|
|
525
573
|
dir?: SortDirection
|
|
526
574
|
): void {
|
|
527
575
|
let id = null;
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
id = data[selected[0]][selected[1]].id;
|
|
576
|
+
if (selected && selected[0] in _data && selected[1] in _data[selected[0]]) {
|
|
577
|
+
id = _data[selected[0]][selected[1]].id;
|
|
531
578
|
}
|
|
532
579
|
if (typeof col !== "number" || !dir) {
|
|
533
580
|
return;
|
|
534
581
|
}
|
|
535
|
-
const indices = [...Array(_data.length).keys()];
|
|
536
|
-
|
|
537
|
-
if (dir === "asc") {
|
|
538
|
-
indices.sort((i, j) =>
|
|
539
|
-
_data[i][col].value < _data[j][col].value ? -1 : 1
|
|
540
|
-
);
|
|
541
|
-
} else if (dir === "des") {
|
|
542
|
-
indices.sort((i, j) =>
|
|
543
|
-
_data[i][col].value > _data[j][col].value ? -1 : 1
|
|
544
|
-
);
|
|
545
|
-
} else {
|
|
546
|
-
return;
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
// sort all the data and metadata based on the values in the data
|
|
550
|
-
const temp_data = [..._data];
|
|
551
|
-
const temp_display_value = _display_value ? [..._display_value] : null;
|
|
552
|
-
const temp_styling = _styling ? [..._styling] : null;
|
|
553
|
-
indices.forEach((originalIndex, sortedIndex) => {
|
|
554
|
-
_data[sortedIndex] = temp_data[originalIndex];
|
|
555
|
-
if (_display_value && temp_display_value)
|
|
556
|
-
_display_value[sortedIndex] = temp_display_value[originalIndex];
|
|
557
|
-
if (_styling && temp_styling)
|
|
558
|
-
_styling[sortedIndex] = temp_styling[originalIndex];
|
|
559
|
-
});
|
|
560
582
|
|
|
583
|
+
sort_table_data(_data, _display_value, _styling, col, dir);
|
|
561
584
|
data = data;
|
|
562
585
|
|
|
563
586
|
if (id) {
|
|
@@ -604,8 +627,15 @@
|
|
|
604
627
|
row: number,
|
|
605
628
|
col: number
|
|
606
629
|
): void {
|
|
630
|
+
if (event.target instanceof HTMLAnchorElement) {
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
|
|
607
634
|
event.preventDefault();
|
|
608
635
|
event.stopPropagation();
|
|
636
|
+
|
|
637
|
+
if (show_row_numbers && col === -1) return;
|
|
638
|
+
|
|
609
639
|
clear_on_focus = false;
|
|
610
640
|
active_cell_menu = null;
|
|
611
641
|
active_header_menu = null;
|
|
@@ -613,19 +643,22 @@
|
|
|
613
643
|
header_edit = false;
|
|
614
644
|
|
|
615
645
|
selected_cells = handle_selection([row, col], selected_cells, event);
|
|
646
|
+
parent.focus();
|
|
616
647
|
|
|
617
|
-
if (
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
input_el
|
|
623
|
-
|
|
624
|
-
input_el.
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
648
|
+
if (editable) {
|
|
649
|
+
if (selected_cells.length === 1) {
|
|
650
|
+
editing = [row, col];
|
|
651
|
+
tick().then(() => {
|
|
652
|
+
const input_el = els[data[row][col].id].input;
|
|
653
|
+
if (input_el) {
|
|
654
|
+
input_el.focus();
|
|
655
|
+
input_el.selectionStart = input_el.selectionEnd =
|
|
656
|
+
input_el.value.length;
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
} else {
|
|
660
|
+
editing = false;
|
|
661
|
+
}
|
|
629
662
|
}
|
|
630
663
|
|
|
631
664
|
toggle_cell_button(row, col);
|
|
@@ -671,6 +704,9 @@
|
|
|
671
704
|
function handle_resize(): void {
|
|
672
705
|
active_cell_menu = null;
|
|
673
706
|
active_header_menu = null;
|
|
707
|
+
selected_cells = [];
|
|
708
|
+
selected = false;
|
|
709
|
+
editing = false;
|
|
674
710
|
set_cell_widths();
|
|
675
711
|
}
|
|
676
712
|
|
|
@@ -711,7 +747,11 @@
|
|
|
711
747
|
}
|
|
712
748
|
|
|
713
749
|
async function handle_copy(): Promise<void> {
|
|
714
|
-
await copy_table_data(data,
|
|
750
|
+
await copy_table_data(data, selected_cells);
|
|
751
|
+
copy_flash = true;
|
|
752
|
+
setTimeout(() => {
|
|
753
|
+
copy_flash = false;
|
|
754
|
+
}, 800);
|
|
715
755
|
}
|
|
716
756
|
|
|
717
757
|
function toggle_header_menu(event: MouseEvent, col: number): void {
|
|
@@ -743,15 +783,17 @@
|
|
|
743
783
|
async function delete_col(index: number): Promise<void> {
|
|
744
784
|
parent.focus();
|
|
745
785
|
if (col_count[1] !== "dynamic") return;
|
|
746
|
-
if (
|
|
786
|
+
if (_headers.length <= 1) return;
|
|
747
787
|
|
|
748
788
|
_headers.splice(index, 1);
|
|
749
789
|
_headers = _headers;
|
|
750
790
|
|
|
751
|
-
data.
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
791
|
+
if (data.length > 0) {
|
|
792
|
+
data.forEach((row) => {
|
|
793
|
+
row.splice(index, 1);
|
|
794
|
+
});
|
|
795
|
+
data = data;
|
|
796
|
+
}
|
|
755
797
|
selected = false;
|
|
756
798
|
}
|
|
757
799
|
|
|
@@ -766,35 +808,146 @@
|
|
|
766
808
|
active_cell_menu = null;
|
|
767
809
|
active_header_menu = null;
|
|
768
810
|
}
|
|
811
|
+
|
|
812
|
+
let row_order: number[] = [];
|
|
813
|
+
|
|
814
|
+
$: {
|
|
815
|
+
if (
|
|
816
|
+
typeof sort_by === "number" &&
|
|
817
|
+
sort_direction &&
|
|
818
|
+
sort_by >= 0 &&
|
|
819
|
+
sort_by < data[0].length
|
|
820
|
+
) {
|
|
821
|
+
const indices = [...Array(data.length)].map((_, i) => i);
|
|
822
|
+
const sort_index = sort_by as number;
|
|
823
|
+
indices.sort((a, b) => {
|
|
824
|
+
const row_a = data[a];
|
|
825
|
+
const row_b = data[b];
|
|
826
|
+
if (
|
|
827
|
+
!row_a ||
|
|
828
|
+
!row_b ||
|
|
829
|
+
sort_index >= row_a.length ||
|
|
830
|
+
sort_index >= row_b.length
|
|
831
|
+
)
|
|
832
|
+
return 0;
|
|
833
|
+
const val_a = row_a[sort_index].value;
|
|
834
|
+
const val_b = row_b[sort_index].value;
|
|
835
|
+
const comp = val_a < val_b ? -1 : val_a > val_b ? 1 : 0;
|
|
836
|
+
return sort_direction === "asc" ? comp : -comp;
|
|
837
|
+
});
|
|
838
|
+
row_order = indices;
|
|
839
|
+
} else {
|
|
840
|
+
row_order = [...Array(data.length)].map((_, i) => i);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
function handle_select_column(col: number): void {
|
|
845
|
+
selected_cells = select_column(data, col);
|
|
846
|
+
selected = selected_cells[0];
|
|
847
|
+
editing = false;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
function handle_select_row(row: number): void {
|
|
851
|
+
selected_cells = select_row(data, row);
|
|
852
|
+
selected = selected_cells[0];
|
|
853
|
+
editing = false;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
let coords: CellCoordinate;
|
|
857
|
+
$: if (selected !== false) coords = selected;
|
|
858
|
+
|
|
859
|
+
$: if (selected !== false) {
|
|
860
|
+
const positions = calculate_selection_positions(
|
|
861
|
+
selected,
|
|
862
|
+
data,
|
|
863
|
+
els,
|
|
864
|
+
parent,
|
|
865
|
+
table
|
|
866
|
+
);
|
|
867
|
+
document.documentElement.style.setProperty(
|
|
868
|
+
"--selected-col-pos",
|
|
869
|
+
positions.col_pos
|
|
870
|
+
);
|
|
871
|
+
if (positions.row_pos) {
|
|
872
|
+
document.documentElement.style.setProperty(
|
|
873
|
+
"--selected-row-pos",
|
|
874
|
+
positions.row_pos
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
let current_search_query: string | null = null;
|
|
880
|
+
|
|
881
|
+
function handle_search(search_query: string | null): void {
|
|
882
|
+
current_search_query = search_query;
|
|
883
|
+
dispatch("search", search_query);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
function commit_filter(): void {
|
|
887
|
+
if (current_search_query && show_search === "filter") {
|
|
888
|
+
dispatch("change", {
|
|
889
|
+
data: data.map((row) => row.map((cell) => cell.value)),
|
|
890
|
+
headers: _headers.map((h) => h.value),
|
|
891
|
+
metadata: null
|
|
892
|
+
});
|
|
893
|
+
if (!value_is_output) {
|
|
894
|
+
dispatch("input");
|
|
895
|
+
}
|
|
896
|
+
current_search_query = null;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
769
899
|
</script>
|
|
770
900
|
|
|
771
901
|
<svelte:window on:resize={() => set_cell_widths()} />
|
|
772
902
|
|
|
773
903
|
<div class="table-container">
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
<
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
904
|
+
{#if (label && label.length !== 0 && show_label) || show_fullscreen_button || show_copy_button || show_search !== "none"}
|
|
905
|
+
<div class="header-row">
|
|
906
|
+
{#if label && label.length !== 0 && show_label}
|
|
907
|
+
<div class="label">
|
|
908
|
+
<p>{label}</p>
|
|
909
|
+
</div>
|
|
910
|
+
{/if}
|
|
911
|
+
<Toolbar
|
|
912
|
+
{show_fullscreen_button}
|
|
913
|
+
{is_fullscreen}
|
|
914
|
+
on:click={toggle_fullscreen}
|
|
915
|
+
on_copy={handle_copy}
|
|
916
|
+
{show_copy_button}
|
|
917
|
+
{show_search}
|
|
918
|
+
on:search={(e) => handle_search(e.detail)}
|
|
919
|
+
on_commit_filter={commit_filter}
|
|
920
|
+
{current_search_query}
|
|
921
|
+
/>
|
|
922
|
+
</div>
|
|
923
|
+
{/if}
|
|
788
924
|
<div
|
|
789
925
|
bind:this={parent}
|
|
790
926
|
class="table-wrap"
|
|
791
927
|
class:dragging
|
|
792
928
|
class:no-wrap={!wrap}
|
|
793
|
-
style="height:{table_height}px"
|
|
929
|
+
style="height:{table_height}px;"
|
|
930
|
+
class:menu-open={active_cell_menu || active_header_menu}
|
|
794
931
|
on:keydown={(e) => handle_keydown(e)}
|
|
795
932
|
role="grid"
|
|
796
933
|
tabindex="0"
|
|
797
934
|
>
|
|
935
|
+
{#if selected !== false && selected_cells.length === 1}
|
|
936
|
+
<button
|
|
937
|
+
class="selection-button selection-button-column"
|
|
938
|
+
on:click|stopPropagation={() => handle_select_column(coords[1])}
|
|
939
|
+
aria-label="Select column"
|
|
940
|
+
>
|
|
941
|
+
⋮
|
|
942
|
+
</button>
|
|
943
|
+
<button
|
|
944
|
+
class="selection-button selection-button-row"
|
|
945
|
+
on:click|stopPropagation={() => handle_select_row(coords[0])}
|
|
946
|
+
aria-label="Select row"
|
|
947
|
+
>
|
|
948
|
+
⋮
|
|
949
|
+
</button>
|
|
950
|
+
{/if}
|
|
798
951
|
<table
|
|
799
952
|
bind:contentRect={t_rect}
|
|
800
953
|
bind:this={table}
|
|
@@ -806,40 +959,59 @@
|
|
|
806
959
|
<thead>
|
|
807
960
|
<tr>
|
|
808
961
|
{#if show_row_numbers}
|
|
809
|
-
<th
|
|
962
|
+
<th
|
|
963
|
+
class="row-number-header frozen-column always-frozen"
|
|
964
|
+
style="left: 0;"
|
|
965
|
+
>
|
|
966
|
+
<div class="cell-wrap">
|
|
967
|
+
<div class="header-content">
|
|
968
|
+
<div class="header-text"></div>
|
|
969
|
+
</div>
|
|
970
|
+
</div>
|
|
971
|
+
</th>
|
|
810
972
|
{/if}
|
|
811
973
|
{#each _headers as { value, id }, i (id)}
|
|
812
974
|
<th
|
|
975
|
+
class:frozen-column={i < actual_pinned_columns}
|
|
976
|
+
class:last-frozen={show_row_numbers
|
|
977
|
+
? i === actual_pinned_columns - 1
|
|
978
|
+
: i === actual_pinned_columns - 1}
|
|
813
979
|
class:editing={header_edit === i}
|
|
814
980
|
aria-sort={get_sort_status(value, sort_by, sort_direction)}
|
|
815
|
-
style:
|
|
981
|
+
style="width: {column_widths.length
|
|
982
|
+
? column_widths[i]
|
|
983
|
+
: undefined}; left: {i < actual_pinned_columns
|
|
984
|
+
? i === 0
|
|
985
|
+
? show_row_numbers
|
|
986
|
+
? 'var(--cell-width-row-number)'
|
|
987
|
+
: '0'
|
|
988
|
+
: `calc(${show_row_numbers ? 'var(--cell-width-row-number) + ' : ''}${Array(
|
|
989
|
+
i
|
|
990
|
+
)
|
|
991
|
+
.fill(0)
|
|
992
|
+
.map((_, idx) => `var(--cell-width-${idx})`)
|
|
993
|
+
.join(' + ')})`
|
|
994
|
+
: 'auto'};"
|
|
816
995
|
>
|
|
817
996
|
<div class="cell-wrap">
|
|
818
|
-
<
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
height="1em"
|
|
837
|
-
viewBox="0 0 9 7"
|
|
838
|
-
fill="none"
|
|
839
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
840
|
-
>
|
|
841
|
-
<path d="M4.49999 0L8.3971 6.75H0.602875L4.49999 0Z" />
|
|
842
|
-
</svg>
|
|
997
|
+
<div class="header-content">
|
|
998
|
+
<EditableCell
|
|
999
|
+
{value}
|
|
1000
|
+
{latex_delimiters}
|
|
1001
|
+
{line_breaks}
|
|
1002
|
+
header
|
|
1003
|
+
edit={false}
|
|
1004
|
+
el={null}
|
|
1005
|
+
{root}
|
|
1006
|
+
{editable}
|
|
1007
|
+
/>
|
|
1008
|
+
<div class="sort-buttons">
|
|
1009
|
+
<SortIcon
|
|
1010
|
+
direction={sort_by === i ? sort_direction : null}
|
|
1011
|
+
on:sort={({ detail }) => handle_sort(i, detail)}
|
|
1012
|
+
{i18n}
|
|
1013
|
+
/>
|
|
1014
|
+
</div>
|
|
843
1015
|
</div>
|
|
844
1016
|
</div>
|
|
845
1017
|
</th>
|
|
@@ -878,9 +1050,12 @@
|
|
|
878
1050
|
on:load={({ detail }) =>
|
|
879
1051
|
handle_file_upload(
|
|
880
1052
|
detail.data,
|
|
881
|
-
col_count,
|
|
882
1053
|
(head) => {
|
|
883
|
-
_headers = make_headers(
|
|
1054
|
+
_headers = make_headers(
|
|
1055
|
+
head.map((h) => h ?? ""),
|
|
1056
|
+
col_count,
|
|
1057
|
+
els
|
|
1058
|
+
);
|
|
884
1059
|
return _headers;
|
|
885
1060
|
},
|
|
886
1061
|
(vals) => {
|
|
@@ -890,152 +1065,205 @@
|
|
|
890
1065
|
bind:dragging
|
|
891
1066
|
aria_label={i18n("dataframe.drop_to_upload")}
|
|
892
1067
|
>
|
|
893
|
-
<
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
<th class="row-number-header"></th>
|
|
1068
|
+
<div class="table-wrap">
|
|
1069
|
+
<VirtualTable
|
|
1070
|
+
bind:items={data}
|
|
1071
|
+
{max_height}
|
|
1072
|
+
bind:actual_height={table_height}
|
|
1073
|
+
bind:table_scrollbar_width={scrollbar_width}
|
|
1074
|
+
selected={selected_index}
|
|
1075
|
+
disable_scroll={active_cell_menu !== null ||
|
|
1076
|
+
active_header_menu !== null}
|
|
1077
|
+
>
|
|
1078
|
+
{#if label && label.length !== 0}
|
|
1079
|
+
<caption class="sr-only">{label}</caption>
|
|
906
1080
|
{/if}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1081
|
+
<tr slot="thead">
|
|
1082
|
+
{#if show_row_numbers}
|
|
1083
|
+
<th
|
|
1084
|
+
class="row-number-header frozen-column always-frozen"
|
|
1085
|
+
style="left: 0;"
|
|
1086
|
+
>
|
|
1087
|
+
<div class="cell-wrap">
|
|
1088
|
+
<div class="header-content">
|
|
1089
|
+
<div class="header-text"></div>
|
|
1090
|
+
</div>
|
|
1091
|
+
</div>
|
|
1092
|
+
</th>
|
|
1093
|
+
{/if}
|
|
1094
|
+
{#each _headers as { value, id }, i (id)}
|
|
1095
|
+
<th
|
|
1096
|
+
class:frozen-column={i < actual_pinned_columns}
|
|
1097
|
+
class:last-frozen={i === actual_pinned_columns - 1}
|
|
1098
|
+
class:focus={header_edit === i || selected_header === i}
|
|
1099
|
+
aria-sort={get_sort_status(value, sort_by, sort_direction)}
|
|
1100
|
+
style="width: {get_cell_width(i)}; left: {i <
|
|
1101
|
+
actual_pinned_columns
|
|
1102
|
+
? i === 0
|
|
1103
|
+
? show_row_numbers
|
|
1104
|
+
? 'var(--cell-width-row-number)'
|
|
1105
|
+
: '0'
|
|
1106
|
+
: `calc(${show_row_numbers ? 'var(--cell-width-row-number) + ' : ''}${Array(
|
|
1107
|
+
i
|
|
1108
|
+
)
|
|
1109
|
+
.fill(0)
|
|
1110
|
+
.map((_, idx) => `var(--cell-width-${idx})`)
|
|
1111
|
+
.join(' + ')})`
|
|
1112
|
+
: 'auto'};"
|
|
1113
|
+
on:click={() => {
|
|
1114
|
+
toggle_header_button(i);
|
|
1115
|
+
}}
|
|
1116
|
+
>
|
|
1117
|
+
<div class="cell-wrap">
|
|
1118
|
+
<div class="header-content">
|
|
1119
|
+
<EditableCell
|
|
1120
|
+
{max_chars}
|
|
1121
|
+
bind:value={_headers[i].value}
|
|
1122
|
+
bind:el={els[id].input}
|
|
1123
|
+
{latex_delimiters}
|
|
1124
|
+
{line_breaks}
|
|
1125
|
+
edit={header_edit === i}
|
|
1126
|
+
on:keydown={end_header_edit}
|
|
1127
|
+
on:dblclick={() => edit_header(i)}
|
|
1128
|
+
header
|
|
1129
|
+
{root}
|
|
1130
|
+
{editable}
|
|
1131
|
+
/>
|
|
1132
|
+
<div class="sort-buttons">
|
|
1133
|
+
<SortIcon
|
|
1134
|
+
direction={sort_by === i ? sort_direction : null}
|
|
1135
|
+
on:sort={({ detail }) => handle_sort(i, detail)}
|
|
1136
|
+
{i18n}
|
|
1137
|
+
/>
|
|
1138
|
+
</div>
|
|
1139
|
+
</div>
|
|
1140
|
+
{#if editable}
|
|
1141
|
+
<button
|
|
1142
|
+
class="cell-menu-button"
|
|
1143
|
+
on:click={(event) => toggle_header_menu(event, i)}
|
|
1144
|
+
on:touchstart={(event) => {
|
|
1145
|
+
event.preventDefault();
|
|
1146
|
+
const touch = event.touches[0];
|
|
1147
|
+
const mouseEvent = new MouseEvent("click", {
|
|
1148
|
+
clientX: touch.clientX,
|
|
1149
|
+
clientY: touch.clientY,
|
|
1150
|
+
bubbles: true,
|
|
1151
|
+
cancelable: true,
|
|
1152
|
+
view: window
|
|
1153
|
+
});
|
|
1154
|
+
toggle_header_menu(mouseEvent, i);
|
|
1155
|
+
}}
|
|
1156
|
+
>
|
|
1157
|
+
⋮
|
|
1158
|
+
</button>
|
|
1159
|
+
{/if}
|
|
1160
|
+
</div>
|
|
1161
|
+
</th>
|
|
1162
|
+
{/each}
|
|
1163
|
+
</tr>
|
|
1164
|
+
<tr slot="tbody" let:item let:index class:row_odd={index % 2 === 0}>
|
|
1165
|
+
{#if show_row_numbers}
|
|
1166
|
+
<td
|
|
1167
|
+
class="row-number frozen-column always-frozen"
|
|
1168
|
+
style="left: 0;"
|
|
1169
|
+
tabindex="-1"
|
|
1170
|
+
>
|
|
1171
|
+
{index + 1}
|
|
1172
|
+
</td>
|
|
1173
|
+
{/if}
|
|
1174
|
+
{#each item as { value, id }, j (id)}
|
|
1175
|
+
<td
|
|
1176
|
+
class:frozen-column={j < actual_pinned_columns}
|
|
1177
|
+
class:last-frozen={j === actual_pinned_columns - 1}
|
|
1178
|
+
tabindex={show_row_numbers && j === 0 ? -1 : 0}
|
|
1179
|
+
bind:this={els[id].cell}
|
|
1180
|
+
on:touchstart={(event) => {
|
|
1181
|
+
const touch = event.touches[0];
|
|
1182
|
+
const mouseEvent = new MouseEvent("click", {
|
|
1183
|
+
clientX: touch.clientX,
|
|
1184
|
+
clientY: touch.clientY,
|
|
1185
|
+
bubbles: true,
|
|
1186
|
+
cancelable: true,
|
|
1187
|
+
view: window
|
|
1188
|
+
});
|
|
1189
|
+
handle_cell_click(mouseEvent, index, j);
|
|
1190
|
+
}}
|
|
1191
|
+
on:mousedown={(event) => {
|
|
1192
|
+
event.preventDefault();
|
|
1193
|
+
event.stopPropagation();
|
|
1194
|
+
}}
|
|
1195
|
+
on:click={(event) => handle_cell_click(event, index, j)}
|
|
1196
|
+
style="width: {get_cell_width(j)}; left: {j <
|
|
1197
|
+
actual_pinned_columns
|
|
1198
|
+
? j === 0
|
|
1199
|
+
? show_row_numbers
|
|
1200
|
+
? 'var(--cell-width-row-number)'
|
|
1201
|
+
: '0'
|
|
1202
|
+
: `calc(${show_row_numbers ? 'var(--cell-width-row-number) + ' : ''}${Array(
|
|
1203
|
+
j
|
|
1204
|
+
)
|
|
1205
|
+
.fill(0)
|
|
1206
|
+
.map((_, idx) => `var(--cell-width-${idx})`)
|
|
1207
|
+
.join(' + ')})`
|
|
1208
|
+
: 'auto'}; {styling?.[index]?.[j] || ''}"
|
|
1209
|
+
class:flash={copy_flash &&
|
|
1210
|
+
is_cell_selected([index, j], selected_cells)}
|
|
1211
|
+
class={is_cell_selected([index, j], selected_cells)}
|
|
1212
|
+
class:menu-active={active_cell_menu &&
|
|
1213
|
+
active_cell_menu.row === index &&
|
|
1214
|
+
active_cell_menu.col === j}
|
|
1215
|
+
>
|
|
1216
|
+
<div class="cell-wrap">
|
|
918
1217
|
<EditableCell
|
|
919
|
-
{
|
|
920
|
-
bind:value={_headers[i].value}
|
|
1218
|
+
bind:value={data[index][j].value}
|
|
921
1219
|
bind:el={els[id].input}
|
|
1220
|
+
display_value={display_value?.[index]?.[j]}
|
|
922
1221
|
{latex_delimiters}
|
|
923
1222
|
{line_breaks}
|
|
924
|
-
edit={header_edit === i}
|
|
925
|
-
on:keydown={end_header_edit}
|
|
926
|
-
on:dblclick={() => edit_header(i)}
|
|
927
|
-
header
|
|
928
|
-
{root}
|
|
929
1223
|
{editable}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
on:
|
|
937
|
-
|
|
938
|
-
|
|
1224
|
+
edit={dequal(editing, [index, j])}
|
|
1225
|
+
datatype={Array.isArray(datatype) ? datatype[j] : datatype}
|
|
1226
|
+
on:blur={() => {
|
|
1227
|
+
clear_on_focus = false;
|
|
1228
|
+
parent.focus();
|
|
1229
|
+
}}
|
|
1230
|
+
on:focus={() => {
|
|
1231
|
+
const row = index;
|
|
1232
|
+
const col = j;
|
|
1233
|
+
if (
|
|
1234
|
+
!selected_cells.some(([r, c]) => r === row && c === col)
|
|
1235
|
+
) {
|
|
1236
|
+
selected_cells = [[row, col]];
|
|
1237
|
+
}
|
|
939
1238
|
}}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1239
|
+
{clear_on_focus}
|
|
1240
|
+
{root}
|
|
1241
|
+
{max_chars}
|
|
1242
|
+
/>
|
|
1243
|
+
{#if editable && should_show_cell_menu([index, j], selected_cells, editable)}
|
|
1244
|
+
<button
|
|
1245
|
+
class="cell-menu-button"
|
|
1246
|
+
on:click={(event) => toggle_cell_menu(event, index, j)}
|
|
947
1247
|
>
|
|
948
|
-
|
|
949
|
-
</
|
|
950
|
-
|
|
1248
|
+
⋮
|
|
1249
|
+
</button>
|
|
1250
|
+
{/if}
|
|
951
1251
|
</div>
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
>
|
|
958
|
-
⋮
|
|
959
|
-
</button>
|
|
960
|
-
{/if}
|
|
961
|
-
</div>
|
|
962
|
-
</th>
|
|
963
|
-
{/each}
|
|
964
|
-
</tr>
|
|
965
|
-
|
|
966
|
-
<tr slot="tbody" let:item let:index class:row_odd={index % 2 === 0}>
|
|
967
|
-
{#if show_row_numbers}
|
|
968
|
-
<td class="row-number" title={`Row ${index + 1}`}>{index + 1}</td>
|
|
969
|
-
{/if}
|
|
970
|
-
{#each item as { value, id }, j (id)}
|
|
971
|
-
<td
|
|
972
|
-
tabindex="0"
|
|
973
|
-
on:touchstart={(event) => {
|
|
974
|
-
const touch = event.touches[0];
|
|
975
|
-
const mouseEvent = new MouseEvent("click", {
|
|
976
|
-
clientX: touch.clientX,
|
|
977
|
-
clientY: touch.clientY,
|
|
978
|
-
bubbles: true,
|
|
979
|
-
cancelable: true,
|
|
980
|
-
view: window
|
|
981
|
-
});
|
|
982
|
-
handle_cell_click(mouseEvent, index, j);
|
|
983
|
-
}}
|
|
984
|
-
on:mousedown={(event) => {
|
|
985
|
-
event.preventDefault();
|
|
986
|
-
event.stopPropagation();
|
|
987
|
-
}}
|
|
988
|
-
on:click={(event) => handle_cell_click(event, index, j)}
|
|
989
|
-
style:width="var(--cell-width-{j})"
|
|
990
|
-
style={styling?.[index]?.[j] || ""}
|
|
991
|
-
class={is_cell_selected([index, j], selected_cells)}
|
|
992
|
-
class:menu-active={active_cell_menu &&
|
|
993
|
-
active_cell_menu.row === index &&
|
|
994
|
-
active_cell_menu.col === j}
|
|
995
|
-
>
|
|
996
|
-
<div class="cell-wrap">
|
|
997
|
-
<EditableCell
|
|
998
|
-
bind:value={data[index][j].value}
|
|
999
|
-
bind:el={els[id].input}
|
|
1000
|
-
display_value={display_value?.[index]?.[j]}
|
|
1001
|
-
{latex_delimiters}
|
|
1002
|
-
{line_breaks}
|
|
1003
|
-
{editable}
|
|
1004
|
-
edit={dequal(editing, [index, j])}
|
|
1005
|
-
datatype={Array.isArray(datatype) ? datatype[j] : datatype}
|
|
1006
|
-
on:blur={() => {
|
|
1007
|
-
clear_on_focus = false;
|
|
1008
|
-
parent.focus();
|
|
1009
|
-
}}
|
|
1010
|
-
on:focus={() => {
|
|
1011
|
-
const row = index;
|
|
1012
|
-
const col = j;
|
|
1013
|
-
if (
|
|
1014
|
-
!selected_cells.some(([r, c]) => r === row && c === col)
|
|
1015
|
-
) {
|
|
1016
|
-
selected_cells = [[row, col]];
|
|
1017
|
-
}
|
|
1018
|
-
}}
|
|
1019
|
-
{clear_on_focus}
|
|
1020
|
-
{root}
|
|
1021
|
-
{max_chars}
|
|
1022
|
-
/>
|
|
1023
|
-
{#if editable && should_show_cell_menu([index, j], selected_cells, editable)}
|
|
1024
|
-
<button
|
|
1025
|
-
class="cell-menu-button"
|
|
1026
|
-
on:click={(event) => toggle_cell_menu(event, index, j)}
|
|
1027
|
-
>
|
|
1028
|
-
⋮
|
|
1029
|
-
</button>
|
|
1030
|
-
{/if}
|
|
1031
|
-
</div>
|
|
1032
|
-
</td>
|
|
1033
|
-
{/each}
|
|
1034
|
-
</tr>
|
|
1035
|
-
</VirtualTable>
|
|
1252
|
+
</td>
|
|
1253
|
+
{/each}
|
|
1254
|
+
</tr>
|
|
1255
|
+
</VirtualTable>
|
|
1256
|
+
</div>
|
|
1036
1257
|
</Upload>
|
|
1037
1258
|
</div>
|
|
1038
1259
|
</div>
|
|
1260
|
+
{#if data.length === 0 && editable && row_count[1] === "dynamic"}
|
|
1261
|
+
<div class="add-row-container">
|
|
1262
|
+
<button class="add-row-button" on:click={() => add_row()}>
|
|
1263
|
+
<span>+</span>
|
|
1264
|
+
</button>
|
|
1265
|
+
</div>
|
|
1266
|
+
{/if}
|
|
1039
1267
|
|
|
1040
1268
|
{#if active_cell_menu}
|
|
1041
1269
|
<CellMenu
|
|
@@ -1072,11 +1300,19 @@
|
|
|
1072
1300
|
on_delete_row={() => delete_row_at(active_cell_menu?.row ?? -1)}
|
|
1073
1301
|
on_delete_col={() => delete_col_at(active_header_menu?.col ?? -1)}
|
|
1074
1302
|
can_delete_rows={false}
|
|
1075
|
-
can_delete_cols={
|
|
1303
|
+
can_delete_cols={_headers.length > 1}
|
|
1076
1304
|
/>
|
|
1077
1305
|
{/if}
|
|
1078
1306
|
|
|
1079
1307
|
<style>
|
|
1308
|
+
.label p {
|
|
1309
|
+
position: relative;
|
|
1310
|
+
z-index: var(--layer-4);
|
|
1311
|
+
margin-bottom: var(--size-2);
|
|
1312
|
+
color: var(--block-label-text-color);
|
|
1313
|
+
font-size: var(--block-label-text-size);
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1080
1316
|
.table-container {
|
|
1081
1317
|
display: flex;
|
|
1082
1318
|
flex-direction: column;
|
|
@@ -1086,8 +1322,9 @@
|
|
|
1086
1322
|
.table-wrap {
|
|
1087
1323
|
position: relative;
|
|
1088
1324
|
transition: 150ms;
|
|
1089
|
-
|
|
1090
|
-
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
.table-wrap.menu-open {
|
|
1091
1328
|
overflow: hidden;
|
|
1092
1329
|
}
|
|
1093
1330
|
|
|
@@ -1117,6 +1354,12 @@
|
|
|
1117
1354
|
border-collapse: separate;
|
|
1118
1355
|
}
|
|
1119
1356
|
|
|
1357
|
+
.table-wrap > :global(button) {
|
|
1358
|
+
border: 1px solid var(--border-color-primary);
|
|
1359
|
+
border-radius: var(--table-radius);
|
|
1360
|
+
overflow: hidden;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1120
1363
|
div:not(.no-wrap) td {
|
|
1121
1364
|
overflow-wrap: anywhere;
|
|
1122
1365
|
}
|
|
@@ -1132,8 +1375,7 @@
|
|
|
1132
1375
|
thead {
|
|
1133
1376
|
position: sticky;
|
|
1134
1377
|
top: 0;
|
|
1135
|
-
|
|
1136
|
-
z-index: var(--layer-1);
|
|
1378
|
+
z-index: var(--layer-2);
|
|
1137
1379
|
box-shadow: var(--shadow-drop);
|
|
1138
1380
|
}
|
|
1139
1381
|
|
|
@@ -1160,10 +1402,12 @@
|
|
|
1160
1402
|
|
|
1161
1403
|
th:first-child {
|
|
1162
1404
|
border-top-left-radius: var(--table-radius);
|
|
1405
|
+
border-bottom-left-radius: var(--table-radius);
|
|
1163
1406
|
}
|
|
1164
1407
|
|
|
1165
1408
|
th:last-child {
|
|
1166
1409
|
border-top-right-radius: var(--table-radius);
|
|
1410
|
+
border-bottom-right-radius: var(--table-radius);
|
|
1167
1411
|
}
|
|
1168
1412
|
|
|
1169
1413
|
th.focus,
|
|
@@ -1189,32 +1433,11 @@
|
|
|
1189
1433
|
background: var(--table-even-background-fill);
|
|
1190
1434
|
}
|
|
1191
1435
|
|
|
1192
|
-
|
|
1193
|
-
fill: currentColor;
|
|
1194
|
-
font-size: 10px;
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
.sort-button {
|
|
1436
|
+
.sort-buttons {
|
|
1198
1437
|
display: flex;
|
|
1199
|
-
flex: none;
|
|
1200
|
-
justify-content: center;
|
|
1201
1438
|
align-items: center;
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
padding: var(--size-2);
|
|
1205
|
-
color: var(--body-text-color-subdued);
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
.sort-button:hover {
|
|
1209
|
-
color: var(--body-text-color);
|
|
1210
|
-
}
|
|
1211
|
-
|
|
1212
|
-
.des {
|
|
1213
|
-
transform: scaleY(-1);
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
.sort-button.sorted {
|
|
1217
|
-
color: var(--color-accent);
|
|
1439
|
+
flex-shrink: 0;
|
|
1440
|
+
order: -1;
|
|
1218
1441
|
}
|
|
1219
1442
|
|
|
1220
1443
|
.editing {
|
|
@@ -1223,11 +1446,19 @@
|
|
|
1223
1446
|
|
|
1224
1447
|
.cell-wrap {
|
|
1225
1448
|
display: flex;
|
|
1226
|
-
align-items:
|
|
1449
|
+
align-items: center;
|
|
1450
|
+
justify-content: flex-start;
|
|
1227
1451
|
outline: none;
|
|
1228
1452
|
min-height: var(--size-9);
|
|
1229
1453
|
position: relative;
|
|
1230
|
-
height:
|
|
1454
|
+
height: 100%;
|
|
1455
|
+
padding: var(--size-2);
|
|
1456
|
+
box-sizing: border-box;
|
|
1457
|
+
margin: 0;
|
|
1458
|
+
gap: var(--size-1);
|
|
1459
|
+
overflow: visible;
|
|
1460
|
+
min-width: 0;
|
|
1461
|
+
border-radius: var(--table-radius);
|
|
1231
1462
|
}
|
|
1232
1463
|
|
|
1233
1464
|
.header-content {
|
|
@@ -1238,7 +1469,9 @@
|
|
|
1238
1469
|
min-width: 0;
|
|
1239
1470
|
white-space: normal;
|
|
1240
1471
|
overflow-wrap: break-word;
|
|
1241
|
-
word-break:
|
|
1472
|
+
word-break: normal;
|
|
1473
|
+
height: 100%;
|
|
1474
|
+
gap: var(--size-1);
|
|
1242
1475
|
}
|
|
1243
1476
|
|
|
1244
1477
|
.row_odd {
|
|
@@ -1267,7 +1500,8 @@
|
|
|
1267
1500
|
transform: translateY(-50%);
|
|
1268
1501
|
}
|
|
1269
1502
|
|
|
1270
|
-
.cell-selected .cell-menu-button
|
|
1503
|
+
.cell-selected .cell-menu-button,
|
|
1504
|
+
th:hover .cell-menu-button {
|
|
1271
1505
|
display: flex;
|
|
1272
1506
|
align-items: center;
|
|
1273
1507
|
justify-content: center;
|
|
@@ -1275,46 +1509,55 @@
|
|
|
1275
1509
|
|
|
1276
1510
|
.header-row {
|
|
1277
1511
|
display: flex;
|
|
1278
|
-
justify-content:
|
|
1512
|
+
justify-content: flex-end;
|
|
1279
1513
|
align-items: center;
|
|
1280
1514
|
gap: var(--size-2);
|
|
1281
|
-
height: var(--size-6);
|
|
1282
1515
|
min-height: var(--size-6);
|
|
1516
|
+
flex-wrap: nowrap;
|
|
1517
|
+
width: 100%;
|
|
1283
1518
|
}
|
|
1284
1519
|
|
|
1285
1520
|
.label {
|
|
1286
|
-
flex: 1;
|
|
1521
|
+
flex: 1 1 auto;
|
|
1522
|
+
margin-right: auto;
|
|
1287
1523
|
}
|
|
1288
1524
|
|
|
1289
1525
|
.label p {
|
|
1290
1526
|
margin: 0;
|
|
1291
1527
|
color: var(--block-label-text-color);
|
|
1292
1528
|
font-size: var(--block-label-text-size);
|
|
1529
|
+
line-height: var(--line-sm);
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
.toolbar {
|
|
1533
|
+
flex: 0 0 auto;
|
|
1293
1534
|
}
|
|
1294
1535
|
|
|
1295
1536
|
.row-number,
|
|
1296
1537
|
.row-number-header {
|
|
1297
|
-
width: var(--size-7);
|
|
1298
|
-
min-width: var(--size-7);
|
|
1299
1538
|
text-align: center;
|
|
1300
1539
|
background: var(--table-even-background-fill);
|
|
1301
|
-
position: sticky;
|
|
1302
|
-
left: 0;
|
|
1303
1540
|
font-size: var(--input-text-size);
|
|
1304
1541
|
color: var(--body-text-color);
|
|
1305
|
-
padding: var(--size-1)
|
|
1542
|
+
padding: var(--size-1);
|
|
1543
|
+
min-width: var(--size-12);
|
|
1544
|
+
width: var(--size-12);
|
|
1306
1545
|
overflow: hidden;
|
|
1307
1546
|
text-overflow: ellipsis;
|
|
1308
1547
|
white-space: nowrap;
|
|
1309
1548
|
font-weight: var(--weight-semibold);
|
|
1310
1549
|
}
|
|
1311
1550
|
|
|
1312
|
-
.row-number-header {
|
|
1313
|
-
|
|
1551
|
+
.row-number-header .header-content {
|
|
1552
|
+
justify-content: space-between;
|
|
1553
|
+
padding: var(--size-1);
|
|
1554
|
+
height: var(--size-9);
|
|
1555
|
+
display: flex;
|
|
1556
|
+
align-items: center;
|
|
1314
1557
|
}
|
|
1315
1558
|
|
|
1316
|
-
.row-number {
|
|
1317
|
-
|
|
1559
|
+
.row-number-header :global(.sort-icons) {
|
|
1560
|
+
margin-right: 0;
|
|
1318
1561
|
}
|
|
1319
1562
|
|
|
1320
1563
|
:global(tbody > tr:nth-child(odd)) .row-number {
|
|
@@ -1411,4 +1654,88 @@
|
|
|
1411
1654
|
.cell-selected.no-top.no-bottom.no-left.no-right {
|
|
1412
1655
|
box-shadow: none;
|
|
1413
1656
|
}
|
|
1657
|
+
|
|
1658
|
+
.selection-button {
|
|
1659
|
+
position: absolute;
|
|
1660
|
+
display: flex;
|
|
1661
|
+
align-items: center;
|
|
1662
|
+
justify-content: center;
|
|
1663
|
+
background: var(--color-accent);
|
|
1664
|
+
color: white;
|
|
1665
|
+
border-radius: var(--radius-sm);
|
|
1666
|
+
z-index: var(--layer-4);
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
.selection-button-column {
|
|
1670
|
+
width: var(--size-3);
|
|
1671
|
+
height: var(--size-5);
|
|
1672
|
+
top: -10px;
|
|
1673
|
+
left: var(--selected-col-pos);
|
|
1674
|
+
transform: rotate(90deg);
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
.selection-button-row {
|
|
1678
|
+
width: var(--size-3);
|
|
1679
|
+
height: var(--size-5);
|
|
1680
|
+
left: -7px;
|
|
1681
|
+
top: calc(var(--selected-row-pos) - var(--size-5) / 2);
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
.table-wrap:not(:focus-within) .selection-button {
|
|
1685
|
+
opacity: 0;
|
|
1686
|
+
pointer-events: none;
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
.flash.cell-selected {
|
|
1690
|
+
animation: flash-color 700ms ease-out;
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
@keyframes flash-color {
|
|
1694
|
+
0%,
|
|
1695
|
+
30% {
|
|
1696
|
+
background: var(--color-accent-copied);
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
100% {
|
|
1700
|
+
background: transparent;
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
.frozen-column {
|
|
1705
|
+
position: sticky;
|
|
1706
|
+
z-index: var(--layer-2);
|
|
1707
|
+
border-right: 1px solid var(--border-color-primary);
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
tr:nth-child(odd) .frozen-column {
|
|
1711
|
+
background: var(--table-odd-background-fill);
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
tr:nth-child(even) .frozen-column {
|
|
1715
|
+
background: var(--table-even-background-fill);
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
.always-frozen {
|
|
1719
|
+
z-index: var(--layer-3);
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
.add-row-container {
|
|
1723
|
+
margin-top: var(--size-2);
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
.add-row-button {
|
|
1727
|
+
width: 100%;
|
|
1728
|
+
padding: var(--size-1);
|
|
1729
|
+
background: transparent;
|
|
1730
|
+
border: 1px dashed var(--border-color-primary);
|
|
1731
|
+
border-radius: var(--radius-sm);
|
|
1732
|
+
color: var(--body-text-color);
|
|
1733
|
+
cursor: pointer;
|
|
1734
|
+
transition: all 150ms;
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
.add-row-button:hover {
|
|
1738
|
+
background: var(--background-fill-secondary);
|
|
1739
|
+
border-style: solid;
|
|
1740
|
+
}
|
|
1414
1741
|
</style>
|