@gradio/dataframe 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/Dataframe.stories.svelte +283 -7
- package/Index.svelte +22 -3
- package/dist/Index.svelte +18 -4
- package/dist/Index.svelte.d.ts +16 -0
- package/dist/shared/EditableCell.svelte +49 -7
- package/dist/shared/EditableCell.svelte.d.ts +1 -1
- package/dist/shared/Table.svelte +692 -411
- package/dist/shared/Table.svelte.d.ts +4 -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 +30 -0
- package/dist/shared/selection_utils.js +139 -0
- package/dist/shared/types.d.ts +18 -0
- package/dist/shared/types.js +2 -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/EditableCell.svelte +55 -7
- package/shared/Table.svelte +762 -478
- 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 +230 -0
- package/shared/types.ts +29 -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 -6
- package/dist/shared/table_utils.js +0 -27
- package/shared/table_utils.ts +0 -38
package/shared/Table.svelte
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { afterUpdate, createEventDispatcher, tick, onMount } from "svelte";
|
|
3
|
-
import { dsvFormat } from "d3-dsv";
|
|
4
3
|
import { dequal } from "dequal/lite";
|
|
5
4
|
import { Upload } from "@gradio/upload";
|
|
6
5
|
|
|
@@ -17,7 +16,28 @@
|
|
|
17
16
|
} from "./utils";
|
|
18
17
|
import CellMenu from "./CellMenu.svelte";
|
|
19
18
|
import Toolbar from "./Toolbar.svelte";
|
|
20
|
-
import
|
|
19
|
+
import SortIcon from "./icons/SortIcon.svelte";
|
|
20
|
+
import type { CellCoordinate, EditingState } from "./types";
|
|
21
|
+
import {
|
|
22
|
+
is_cell_selected,
|
|
23
|
+
handle_selection,
|
|
24
|
+
handle_delete_key,
|
|
25
|
+
should_show_cell_menu,
|
|
26
|
+
get_next_cell_coordinates,
|
|
27
|
+
get_range_selection,
|
|
28
|
+
move_cursor,
|
|
29
|
+
get_current_indices,
|
|
30
|
+
handle_click_outside as handle_click_outside_util,
|
|
31
|
+
select_column,
|
|
32
|
+
select_row,
|
|
33
|
+
calculate_selection_positions
|
|
34
|
+
} from "./selection_utils";
|
|
35
|
+
import {
|
|
36
|
+
copy_table_data,
|
|
37
|
+
get_max,
|
|
38
|
+
handle_file_upload,
|
|
39
|
+
sort_table_data
|
|
40
|
+
} from "./utils/table_utils";
|
|
21
41
|
|
|
22
42
|
export let datatype: Datatype | Datatype[];
|
|
23
43
|
export let label: string | null = null;
|
|
@@ -46,52 +66,86 @@
|
|
|
46
66
|
export let show_fullscreen_button = false;
|
|
47
67
|
export let show_copy_button = false;
|
|
48
68
|
export let value_is_output = false;
|
|
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;
|
|
78
|
+
|
|
79
|
+
let selected_cells: CellCoordinate[] = [];
|
|
80
|
+
$: selected_cells = [...selected_cells];
|
|
81
|
+
let selected: CellCoordinate | false = false;
|
|
82
|
+
$: selected =
|
|
83
|
+
selected_cells.length > 0
|
|
84
|
+
? selected_cells[selected_cells.length - 1]
|
|
85
|
+
: false;
|
|
49
86
|
|
|
50
|
-
let selected: false | [number, number] = false;
|
|
51
|
-
let clicked_cell: { row: number; col: number } | undefined = undefined;
|
|
52
87
|
export let display_value: string[][] | null = null;
|
|
53
88
|
export let styling: string[][] | null = null;
|
|
54
89
|
let t_rect: DOMRectReadOnly;
|
|
90
|
+
let els: Record<
|
|
91
|
+
string,
|
|
92
|
+
{ cell: null | HTMLTableCellElement; input: null | HTMLInputElement }
|
|
93
|
+
> = {};
|
|
94
|
+
let data_binding: Record<string, (typeof data)[0][0]> = {};
|
|
55
95
|
|
|
56
96
|
const dispatch = createEventDispatcher<{
|
|
57
97
|
change: DataframeValue;
|
|
58
98
|
input: undefined;
|
|
59
99
|
select: SelectData;
|
|
100
|
+
search: string | null;
|
|
60
101
|
}>();
|
|
61
102
|
|
|
62
|
-
let editing:
|
|
103
|
+
let editing: EditingState = false;
|
|
104
|
+
let clear_on_focus = false;
|
|
105
|
+
let header_edit: number | false = false;
|
|
106
|
+
let selected_header: number | false = false;
|
|
107
|
+
let active_cell_menu: {
|
|
108
|
+
row: number;
|
|
109
|
+
col: number;
|
|
110
|
+
x: number;
|
|
111
|
+
y: number;
|
|
112
|
+
} | null = null;
|
|
113
|
+
let active_header_menu: {
|
|
114
|
+
col: number;
|
|
115
|
+
x: number;
|
|
116
|
+
y: number;
|
|
117
|
+
} | null = null;
|
|
118
|
+
let is_fullscreen = false;
|
|
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
|
+
});
|
|
63
133
|
|
|
64
134
|
const get_data_at = (row: number, col: number): string | number =>
|
|
65
135
|
data?.[row]?.[col]?.value;
|
|
66
136
|
|
|
67
|
-
let last_selected: [number, number] | null = null;
|
|
68
|
-
|
|
69
|
-
$: {
|
|
70
|
-
if (selected !== false && !dequal(selected, last_selected)) {
|
|
71
|
-
const [row, col] = selected;
|
|
72
|
-
if (!isNaN(row) && !isNaN(col) && data[row]) {
|
|
73
|
-
dispatch("select", {
|
|
74
|
-
index: [row, col],
|
|
75
|
-
value: get_data_at(row, col),
|
|
76
|
-
row_value: data[row].map((d) => d.value)
|
|
77
|
-
});
|
|
78
|
-
last_selected = selected;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
let els: Record<
|
|
84
|
-
string,
|
|
85
|
-
{ cell: null | HTMLTableCellElement; input: null | HTMLInputElement }
|
|
86
|
-
> = {};
|
|
87
|
-
|
|
88
|
-
let data_binding: Record<string, (typeof data)[0][0]> = {};
|
|
89
|
-
|
|
90
137
|
function make_id(): string {
|
|
91
138
|
return Math.random().toString(36).substring(2, 15);
|
|
92
139
|
}
|
|
93
140
|
|
|
94
|
-
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 {
|
|
95
149
|
let _h = _head || [];
|
|
96
150
|
if (col_count[1] === "fixed" && _h.length < col_count[0]) {
|
|
97
151
|
const fill = Array(col_count[0] - _h.length)
|
|
@@ -124,8 +178,8 @@
|
|
|
124
178
|
const data_row_length = _values.length;
|
|
125
179
|
return Array(row_count[1] === "fixed" ? row_count[0] : data_row_length)
|
|
126
180
|
.fill(0)
|
|
127
|
-
.map((_, i) =>
|
|
128
|
-
Array(
|
|
181
|
+
.map((_, i) => {
|
|
182
|
+
return Array(
|
|
129
183
|
col_count[1] === "fixed"
|
|
130
184
|
? col_count[0]
|
|
131
185
|
: data_row_length > 0
|
|
@@ -139,16 +193,16 @@
|
|
|
139
193
|
const obj = { value: _values?.[i]?.[j] ?? "", id };
|
|
140
194
|
data_binding[id] = obj;
|
|
141
195
|
return obj;
|
|
142
|
-
})
|
|
143
|
-
);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
144
198
|
}
|
|
145
199
|
|
|
146
|
-
let _headers = make_headers(headers);
|
|
200
|
+
let _headers = make_headers(headers, col_count, els);
|
|
147
201
|
let old_headers: string[] = headers;
|
|
148
202
|
|
|
149
203
|
$: {
|
|
150
204
|
if (!dequal(headers, old_headers)) {
|
|
151
|
-
_headers = make_headers(headers);
|
|
205
|
+
_headers = make_headers(headers, col_count, els);
|
|
152
206
|
old_headers = JSON.parse(JSON.stringify(headers));
|
|
153
207
|
}
|
|
154
208
|
}
|
|
@@ -165,6 +219,8 @@
|
|
|
165
219
|
let previous_data = data.map((row) => row.map((cell) => String(cell.value)));
|
|
166
220
|
|
|
167
221
|
async function trigger_change(): Promise<void> {
|
|
222
|
+
// shouldnt trigger if data changed due to search
|
|
223
|
+
if (current_search_query) return;
|
|
168
224
|
const current_headers = _headers.map((h) => h.value);
|
|
169
225
|
const current_data = data.map((row) =>
|
|
170
226
|
row.map((cell) => String(cell.value))
|
|
@@ -199,48 +255,9 @@
|
|
|
199
255
|
if (direction === "asc") return "ascending";
|
|
200
256
|
if (direction === "des") return "descending";
|
|
201
257
|
}
|
|
202
|
-
|
|
203
258
|
return "none";
|
|
204
259
|
}
|
|
205
260
|
|
|
206
|
-
function get_current_indices(id: string): [number, number] {
|
|
207
|
-
return data.reduce(
|
|
208
|
-
(acc, arr, i) => {
|
|
209
|
-
const j = arr.reduce(
|
|
210
|
-
(_acc, _data, k) => (id === _data.id ? k : _acc),
|
|
211
|
-
-1
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
return j === -1 ? acc : [i, j];
|
|
215
|
-
},
|
|
216
|
-
[-1, -1]
|
|
217
|
-
);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function move_cursor(
|
|
221
|
-
key: "ArrowRight" | "ArrowLeft" | "ArrowDown" | "ArrowUp",
|
|
222
|
-
current_coords: [number, number]
|
|
223
|
-
): void {
|
|
224
|
-
const dir = {
|
|
225
|
-
ArrowRight: [0, 1],
|
|
226
|
-
ArrowLeft: [0, -1],
|
|
227
|
-
ArrowDown: [1, 0],
|
|
228
|
-
ArrowUp: [-1, 0]
|
|
229
|
-
}[key];
|
|
230
|
-
|
|
231
|
-
const i = current_coords[0] + dir[0];
|
|
232
|
-
const j = current_coords[1] + dir[1];
|
|
233
|
-
|
|
234
|
-
if (i < 0 && j <= 0) {
|
|
235
|
-
selected_header = j;
|
|
236
|
-
selected = false;
|
|
237
|
-
} else {
|
|
238
|
-
const is_data = data[i]?.[j];
|
|
239
|
-
selected = is_data ? [i, j] : selected;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
let clear_on_focus = false;
|
|
244
261
|
// eslint-disable-next-line complexity
|
|
245
262
|
async function handle_keydown(event: KeyboardEvent): Promise<void> {
|
|
246
263
|
if (selected_header !== false && header_edit === false) {
|
|
@@ -268,6 +285,50 @@
|
|
|
268
285
|
break;
|
|
269
286
|
}
|
|
270
287
|
}
|
|
288
|
+
|
|
289
|
+
if (event.key === "Delete" || event.key === "Backspace") {
|
|
290
|
+
if (!editable) return;
|
|
291
|
+
|
|
292
|
+
if (editing) {
|
|
293
|
+
const [row, col] = editing;
|
|
294
|
+
const input_el = els[data[row][col].id].input;
|
|
295
|
+
if (input_el && input_el.selectionStart !== input_el.selectionEnd) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (
|
|
299
|
+
event.key === "Delete" &&
|
|
300
|
+
input_el?.selectionStart !== input_el?.value.length
|
|
301
|
+
) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if (event.key === "Backspace" && input_el?.selectionStart !== 0) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
event.preventDefault();
|
|
310
|
+
if (selected_cells.length > 0) {
|
|
311
|
+
data = handle_delete_key(data, selected_cells);
|
|
312
|
+
dispatch("change", {
|
|
313
|
+
data: data.map((row) => row.map((cell) => cell.value)),
|
|
314
|
+
headers: _headers.map((h) => h.value),
|
|
315
|
+
metadata: null
|
|
316
|
+
});
|
|
317
|
+
if (!value_is_output) {
|
|
318
|
+
dispatch("input");
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (event.key === "c" && (event.metaKey || event.ctrlKey)) {
|
|
325
|
+
event.preventDefault();
|
|
326
|
+
if (selected_cells.length > 0) {
|
|
327
|
+
await handle_copy();
|
|
328
|
+
}
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
271
332
|
if (!selected) {
|
|
272
333
|
return;
|
|
273
334
|
}
|
|
@@ -281,7 +342,31 @@
|
|
|
281
342
|
case "ArrowUp":
|
|
282
343
|
if (editing) break;
|
|
283
344
|
event.preventDefault();
|
|
284
|
-
move_cursor(event.key, [i, j]);
|
|
345
|
+
const next_coords = move_cursor(event.key, [i, j], data);
|
|
346
|
+
if (next_coords) {
|
|
347
|
+
if (event.shiftKey) {
|
|
348
|
+
selected_cells = get_range_selection(
|
|
349
|
+
selected_cells.length > 0 ? selected_cells[0] : [i, j],
|
|
350
|
+
next_coords
|
|
351
|
+
);
|
|
352
|
+
editing = false;
|
|
353
|
+
} else {
|
|
354
|
+
selected_cells = [next_coords];
|
|
355
|
+
if (editable) {
|
|
356
|
+
editing = next_coords;
|
|
357
|
+
clear_on_focus = false;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
selected = next_coords;
|
|
361
|
+
} else if (
|
|
362
|
+
next_coords === false &&
|
|
363
|
+
event.key === "ArrowUp" &&
|
|
364
|
+
i === 0
|
|
365
|
+
) {
|
|
366
|
+
selected_header = j;
|
|
367
|
+
selected = false;
|
|
368
|
+
editing = false;
|
|
369
|
+
}
|
|
285
370
|
break;
|
|
286
371
|
|
|
287
372
|
case "Escape":
|
|
@@ -290,59 +375,45 @@
|
|
|
290
375
|
editing = false;
|
|
291
376
|
break;
|
|
292
377
|
case "Enter":
|
|
293
|
-
if (!editable) break;
|
|
294
378
|
event.preventDefault();
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
await tick();
|
|
299
|
-
|
|
300
|
-
selected = [i + 1, j];
|
|
301
|
-
} else {
|
|
302
|
-
if (dequal(editing, [i, j])) {
|
|
303
|
-
const cell_id = data[i][j].id;
|
|
304
|
-
const input_el = els[cell_id].input;
|
|
305
|
-
if (input_el) {
|
|
306
|
-
data[i][j].value = input_el.value;
|
|
307
|
-
}
|
|
308
|
-
editing = false;
|
|
379
|
+
if (editable) {
|
|
380
|
+
if (event.shiftKey) {
|
|
381
|
+
add_row(i);
|
|
309
382
|
await tick();
|
|
310
|
-
selected = [i, j];
|
|
383
|
+
selected = [i + 1, j];
|
|
311
384
|
} else {
|
|
312
|
-
editing
|
|
385
|
+
if (dequal(editing, [i, j])) {
|
|
386
|
+
const cell_id = data[i][j].id;
|
|
387
|
+
const input_el = els[cell_id].input;
|
|
388
|
+
if (input_el) {
|
|
389
|
+
data[i][j].value = input_el.value;
|
|
390
|
+
}
|
|
391
|
+
editing = false;
|
|
392
|
+
await tick();
|
|
393
|
+
selected = [i, j];
|
|
394
|
+
} else {
|
|
395
|
+
editing = [i, j];
|
|
396
|
+
clear_on_focus = false;
|
|
397
|
+
}
|
|
313
398
|
}
|
|
314
399
|
}
|
|
315
|
-
|
|
316
|
-
break;
|
|
317
|
-
case "Backspace":
|
|
318
|
-
if (!editable) break;
|
|
319
|
-
if (!editing) {
|
|
320
|
-
event.preventDefault();
|
|
321
|
-
data[i][j].value = "";
|
|
322
|
-
}
|
|
323
|
-
break;
|
|
324
|
-
case "Delete":
|
|
325
|
-
if (!editable) break;
|
|
326
|
-
if (!editing) {
|
|
327
|
-
event.preventDefault();
|
|
328
|
-
data[i][j].value = "";
|
|
329
|
-
}
|
|
330
400
|
break;
|
|
331
401
|
case "Tab":
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
let is_data_x = data[i][j + direction];
|
|
335
|
-
let is_data_y =
|
|
336
|
-
data?.[i + direction]?.[direction > 0 ? 0 : _headers.length - 1];
|
|
337
|
-
|
|
338
|
-
if (is_data_x || is_data_y) {
|
|
339
|
-
event.preventDefault();
|
|
340
|
-
selected = is_data_x
|
|
341
|
-
? [i, j + direction]
|
|
342
|
-
: [i + direction, direction > 0 ? 0 : _headers.length - 1];
|
|
343
|
-
}
|
|
402
|
+
event.preventDefault();
|
|
344
403
|
editing = false;
|
|
345
|
-
|
|
404
|
+
const next_cell = get_next_cell_coordinates(
|
|
405
|
+
[i, j],
|
|
406
|
+
data,
|
|
407
|
+
event.shiftKey
|
|
408
|
+
);
|
|
409
|
+
if (next_cell) {
|
|
410
|
+
selected_cells = [next_cell];
|
|
411
|
+
selected = next_cell;
|
|
412
|
+
if (editable) {
|
|
413
|
+
editing = next_cell;
|
|
414
|
+
clear_on_focus = false;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
346
417
|
break;
|
|
347
418
|
default:
|
|
348
419
|
if (!editable) break;
|
|
@@ -360,29 +431,26 @@
|
|
|
360
431
|
let sort_direction: SortDirection | undefined;
|
|
361
432
|
let sort_by: number | undefined;
|
|
362
433
|
|
|
363
|
-
function handle_sort(col: number): void {
|
|
434
|
+
function handle_sort(col: number, direction: SortDirection): void {
|
|
364
435
|
if (typeof sort_by !== "number" || sort_by !== col) {
|
|
365
|
-
sort_direction =
|
|
436
|
+
sort_direction = direction;
|
|
366
437
|
sort_by = col;
|
|
367
|
-
} else {
|
|
368
|
-
if (sort_direction ===
|
|
369
|
-
sort_direction =
|
|
370
|
-
|
|
371
|
-
|
|
438
|
+
} else if (sort_by === col) {
|
|
439
|
+
if (sort_direction === direction) {
|
|
440
|
+
sort_direction = undefined;
|
|
441
|
+
sort_by = undefined;
|
|
442
|
+
} else {
|
|
443
|
+
sort_direction = direction;
|
|
372
444
|
}
|
|
373
445
|
}
|
|
374
446
|
}
|
|
375
447
|
|
|
376
|
-
let header_edit: number | false;
|
|
377
|
-
|
|
378
|
-
let select_on_focus = false;
|
|
379
|
-
let selected_header: number | false = false;
|
|
380
448
|
async function edit_header(i: number, _select = false): Promise<void> {
|
|
381
449
|
if (!editable || col_count[1] !== "dynamic" || header_edit === i) return;
|
|
382
450
|
selected = false;
|
|
451
|
+
selected_cells = [];
|
|
383
452
|
selected_header = i;
|
|
384
453
|
header_edit = i;
|
|
385
|
-
select_on_focus = _select;
|
|
386
454
|
}
|
|
387
455
|
|
|
388
456
|
function end_header_edit(event: CustomEvent<KeyboardEvent>): void {
|
|
@@ -457,107 +525,14 @@
|
|
|
457
525
|
}
|
|
458
526
|
|
|
459
527
|
function handle_click_outside(event: Event): void {
|
|
460
|
-
if (
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
) {
|
|
528
|
+
if (handle_click_outside_util(event, parent)) {
|
|
529
|
+
editing = false;
|
|
530
|
+
selected_cells = [];
|
|
531
|
+
header_edit = false;
|
|
532
|
+
selected_header = false;
|
|
466
533
|
active_cell_menu = null;
|
|
467
534
|
active_header_menu = null;
|
|
468
535
|
}
|
|
469
|
-
|
|
470
|
-
const [trigger] = event.composedPath() as HTMLElement[];
|
|
471
|
-
if (parent.contains(trigger)) {
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
clicked_cell = undefined;
|
|
476
|
-
editing = false;
|
|
477
|
-
selected = false;
|
|
478
|
-
header_edit = false;
|
|
479
|
-
selected_header = false;
|
|
480
|
-
active_cell_menu = null;
|
|
481
|
-
active_header_menu = null;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
function guess_delimitaor(
|
|
485
|
-
text: string,
|
|
486
|
-
possibleDelimiters: string[]
|
|
487
|
-
): string[] {
|
|
488
|
-
return possibleDelimiters.filter(weedOut);
|
|
489
|
-
|
|
490
|
-
function weedOut(delimiter: string): boolean {
|
|
491
|
-
var cache = -1;
|
|
492
|
-
return text.split("\n").every(checkLength);
|
|
493
|
-
|
|
494
|
-
function checkLength(line: string): boolean {
|
|
495
|
-
if (!line) {
|
|
496
|
-
return true;
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
var length = line.split(delimiter).length;
|
|
500
|
-
if (cache < 0) {
|
|
501
|
-
cache = length;
|
|
502
|
-
}
|
|
503
|
-
return cache === length && length > 1;
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
function data_uri_to_blob(data_uri: string): Blob {
|
|
509
|
-
const byte_str = atob(data_uri.split(",")[1]);
|
|
510
|
-
const mime_str = data_uri.split(",")[0].split(":")[1].split(";")[0];
|
|
511
|
-
|
|
512
|
-
const ab = new ArrayBuffer(byte_str.length);
|
|
513
|
-
const ia = new Uint8Array(ab);
|
|
514
|
-
|
|
515
|
-
for (let i = 0; i < byte_str.length; i++) {
|
|
516
|
-
ia[i] = byte_str.charCodeAt(i);
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
return new Blob([ab], { type: mime_str });
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
function blob_to_string(blob: Blob): void {
|
|
523
|
-
const reader = new FileReader();
|
|
524
|
-
|
|
525
|
-
function handle_read(e: ProgressEvent<FileReader>): void {
|
|
526
|
-
if (!e?.target?.result || typeof e.target.result !== "string") return;
|
|
527
|
-
|
|
528
|
-
const [delimiter] = guess_delimitaor(e.target.result, [",", "\t"]);
|
|
529
|
-
|
|
530
|
-
const [head, ...rest] = dsvFormat(delimiter).parseRows(e.target.result);
|
|
531
|
-
|
|
532
|
-
_headers = make_headers(
|
|
533
|
-
col_count[1] === "fixed" ? head.slice(0, col_count[0]) : head
|
|
534
|
-
);
|
|
535
|
-
|
|
536
|
-
values = rest;
|
|
537
|
-
reader.removeEventListener("loadend", handle_read);
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
reader.addEventListener("loadend", handle_read);
|
|
541
|
-
|
|
542
|
-
reader.readAsText(blob);
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
let dragging = false;
|
|
546
|
-
|
|
547
|
-
function get_max(
|
|
548
|
-
_d: { value: any; id: string }[][]
|
|
549
|
-
): { value: any; id: string }[] {
|
|
550
|
-
if (!_d || _d.length === 0 || !_d[0]) return [];
|
|
551
|
-
let max = _d[0].slice();
|
|
552
|
-
for (let i = 0; i < _d.length; i++) {
|
|
553
|
-
for (let j = 0; j < _d[i].length; j++) {
|
|
554
|
-
if (`${max[j].value}`.length < `${_d[i][j].value}`.length) {
|
|
555
|
-
max[j] = _d[i][j];
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
return max;
|
|
561
536
|
}
|
|
562
537
|
|
|
563
538
|
$: max = get_max(data);
|
|
@@ -568,16 +543,25 @@
|
|
|
568
543
|
let table: HTMLTableElement;
|
|
569
544
|
|
|
570
545
|
function set_cell_widths(): void {
|
|
571
|
-
const widths = cells.map((el
|
|
572
|
-
return el?.clientWidth || 0;
|
|
573
|
-
});
|
|
546
|
+
const widths = cells.map((el) => el?.clientWidth || 0);
|
|
574
547
|
if (widths.length === 0) return;
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
`${widths[i] - scrollbar_width / widths.length}px`
|
|
579
|
-
);
|
|
548
|
+
|
|
549
|
+
if (show_row_numbers) {
|
|
550
|
+
parent.style.setProperty(`--cell-width-row-number`, `${widths[0]}px`);
|
|
580
551
|
}
|
|
552
|
+
const data_cells = show_row_numbers ? widths.slice(1) : widths;
|
|
553
|
+
data_cells.forEach((width, i) => {
|
|
554
|
+
if (!column_widths[i]) {
|
|
555
|
+
parent.style.setProperty(
|
|
556
|
+
`--cell-width-${i}`,
|
|
557
|
+
`${width - scrollbar_width / data_cells.length}px`
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function get_cell_width(index: number): string {
|
|
564
|
+
return column_widths[index] || `var(--cell-width-${index})`;
|
|
581
565
|
}
|
|
582
566
|
|
|
583
567
|
let table_height: number =
|
|
@@ -592,43 +576,18 @@
|
|
|
592
576
|
dir?: SortDirection
|
|
593
577
|
): void {
|
|
594
578
|
let id = null;
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
id = data[selected[0]][selected[1]].id;
|
|
579
|
+
if (selected && selected[0] in _data && selected[1] in _data[selected[0]]) {
|
|
580
|
+
id = _data[selected[0]][selected[1]].id;
|
|
598
581
|
}
|
|
599
582
|
if (typeof col !== "number" || !dir) {
|
|
600
583
|
return;
|
|
601
584
|
}
|
|
602
|
-
const indices = [...Array(_data.length).keys()];
|
|
603
|
-
|
|
604
|
-
if (dir === "asc") {
|
|
605
|
-
indices.sort((i, j) =>
|
|
606
|
-
_data[i][col].value < _data[j][col].value ? -1 : 1
|
|
607
|
-
);
|
|
608
|
-
} else if (dir === "des") {
|
|
609
|
-
indices.sort((i, j) =>
|
|
610
|
-
_data[i][col].value > _data[j][col].value ? -1 : 1
|
|
611
|
-
);
|
|
612
|
-
} else {
|
|
613
|
-
return;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
// sort all the data and metadata based on the values in the data
|
|
617
|
-
const temp_data = [..._data];
|
|
618
|
-
const temp_display_value = _display_value ? [..._display_value] : null;
|
|
619
|
-
const temp_styling = _styling ? [..._styling] : null;
|
|
620
|
-
indices.forEach((originalIndex, sortedIndex) => {
|
|
621
|
-
_data[sortedIndex] = temp_data[originalIndex];
|
|
622
|
-
if (_display_value && temp_display_value)
|
|
623
|
-
_display_value[sortedIndex] = temp_display_value[originalIndex];
|
|
624
|
-
if (_styling && temp_styling)
|
|
625
|
-
_styling[sortedIndex] = temp_styling[originalIndex];
|
|
626
|
-
});
|
|
627
585
|
|
|
586
|
+
sort_table_data(_data, _display_value, _styling, col, dir);
|
|
628
587
|
data = data;
|
|
629
588
|
|
|
630
589
|
if (id) {
|
|
631
|
-
const [i, j] = get_current_indices(id);
|
|
590
|
+
const [i, j] = get_current_indices(id, data);
|
|
632
591
|
selected = [i, j];
|
|
633
592
|
}
|
|
634
593
|
}
|
|
@@ -640,19 +599,17 @@
|
|
|
640
599
|
let is_visible = false;
|
|
641
600
|
|
|
642
601
|
onMount(() => {
|
|
643
|
-
const observer = new IntersectionObserver((entries
|
|
602
|
+
const observer = new IntersectionObserver((entries) => {
|
|
644
603
|
entries.forEach((entry) => {
|
|
645
604
|
if (entry.isIntersecting && !is_visible) {
|
|
646
605
|
set_cell_widths();
|
|
647
606
|
data = data;
|
|
648
607
|
}
|
|
649
|
-
|
|
650
608
|
is_visible = entry.isIntersecting;
|
|
651
609
|
});
|
|
652
610
|
});
|
|
653
611
|
|
|
654
612
|
observer.observe(parent);
|
|
655
|
-
|
|
656
613
|
document.addEventListener("click", handle_click_outside);
|
|
657
614
|
window.addEventListener("resize", handle_resize);
|
|
658
615
|
document.addEventListener("fullscreenchange", handle_fullscreen_change);
|
|
@@ -668,14 +625,53 @@
|
|
|
668
625
|
};
|
|
669
626
|
});
|
|
670
627
|
|
|
671
|
-
|
|
628
|
+
function handle_cell_click(
|
|
629
|
+
event: MouseEvent,
|
|
630
|
+
row: number,
|
|
631
|
+
col: number
|
|
632
|
+
): void {
|
|
633
|
+
if (event.target instanceof HTMLAnchorElement) {
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
672
636
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
637
|
+
event.preventDefault();
|
|
638
|
+
event.stopPropagation();
|
|
639
|
+
|
|
640
|
+
if (show_row_numbers && col === -1) return;
|
|
641
|
+
|
|
642
|
+
clear_on_focus = false;
|
|
643
|
+
active_cell_menu = null;
|
|
644
|
+
active_header_menu = null;
|
|
645
|
+
selected_header = false;
|
|
646
|
+
header_edit = false;
|
|
647
|
+
|
|
648
|
+
selected_cells = handle_selection([row, col], selected_cells, event);
|
|
649
|
+
parent.focus();
|
|
650
|
+
|
|
651
|
+
if (editable) {
|
|
652
|
+
if (selected_cells.length === 1) {
|
|
653
|
+
editing = [row, col];
|
|
654
|
+
tick().then(() => {
|
|
655
|
+
const input_el = els[data[row][col].id].input;
|
|
656
|
+
if (input_el) {
|
|
657
|
+
input_el.focus();
|
|
658
|
+
input_el.selectionStart = input_el.selectionEnd =
|
|
659
|
+
input_el.value.length;
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
} else {
|
|
663
|
+
editing = false;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
toggle_cell_button(row, col);
|
|
668
|
+
|
|
669
|
+
dispatch("select", {
|
|
670
|
+
index: [row, col],
|
|
671
|
+
value: get_data_at(row, col),
|
|
672
|
+
row_value: data[row].map((d) => d.value)
|
|
673
|
+
});
|
|
674
|
+
}
|
|
679
675
|
|
|
680
676
|
function toggle_cell_menu(event: MouseEvent, row: number, col: number): void {
|
|
681
677
|
event.stopPropagation();
|
|
@@ -689,12 +685,7 @@
|
|
|
689
685
|
const cell = (event.target as HTMLElement).closest("td");
|
|
690
686
|
if (cell) {
|
|
691
687
|
const rect = cell.getBoundingClientRect();
|
|
692
|
-
active_cell_menu = {
|
|
693
|
-
row,
|
|
694
|
-
col,
|
|
695
|
-
x: rect.right,
|
|
696
|
-
y: rect.bottom
|
|
697
|
-
};
|
|
688
|
+
active_cell_menu = { row, col, x: rect.right, y: rect.bottom };
|
|
698
689
|
}
|
|
699
690
|
}
|
|
700
691
|
}
|
|
@@ -716,6 +707,9 @@
|
|
|
716
707
|
function handle_resize(): void {
|
|
717
708
|
active_cell_menu = null;
|
|
718
709
|
active_header_menu = null;
|
|
710
|
+
selected_cells = [];
|
|
711
|
+
selected = false;
|
|
712
|
+
editing = false;
|
|
719
713
|
set_cell_widths();
|
|
720
714
|
}
|
|
721
715
|
|
|
@@ -726,33 +720,21 @@
|
|
|
726
720
|
} | null = null;
|
|
727
721
|
|
|
728
722
|
function toggle_header_button(col: number): void {
|
|
729
|
-
|
|
730
|
-
active_button
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
}
|
|
723
|
+
active_button =
|
|
724
|
+
active_button?.type === "header" && active_button.col === col
|
|
725
|
+
? null
|
|
726
|
+
: { type: "header", col };
|
|
734
727
|
}
|
|
735
728
|
|
|
736
729
|
function toggle_cell_button(row: number, col: number): void {
|
|
737
|
-
|
|
730
|
+
active_button =
|
|
738
731
|
active_button?.type === "cell" &&
|
|
739
732
|
active_button.row === row &&
|
|
740
733
|
active_button.col === col
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
} else {
|
|
744
|
-
active_button = { type: "cell", row, col };
|
|
745
|
-
}
|
|
734
|
+
? null
|
|
735
|
+
: { type: "cell", row, col };
|
|
746
736
|
}
|
|
747
737
|
|
|
748
|
-
let active_header_menu: {
|
|
749
|
-
col: number;
|
|
750
|
-
x: number;
|
|
751
|
-
y: number;
|
|
752
|
-
} | null = null;
|
|
753
|
-
|
|
754
|
-
let is_fullscreen = false;
|
|
755
|
-
|
|
756
738
|
function toggle_fullscreen(): void {
|
|
757
739
|
if (!document.fullscreenElement) {
|
|
758
740
|
parent.requestFullscreen();
|
|
@@ -768,7 +750,11 @@
|
|
|
768
750
|
}
|
|
769
751
|
|
|
770
752
|
async function handle_copy(): Promise<void> {
|
|
771
|
-
await copy_table_data(data,
|
|
753
|
+
await copy_table_data(data, selected_cells);
|
|
754
|
+
copy_flash = true;
|
|
755
|
+
setTimeout(() => {
|
|
756
|
+
copy_flash = false;
|
|
757
|
+
}, 800);
|
|
772
758
|
}
|
|
773
759
|
|
|
774
760
|
function toggle_header_menu(event: MouseEvent, col: number): void {
|
|
@@ -779,11 +765,7 @@
|
|
|
779
765
|
const header = (event.target as HTMLElement).closest("th");
|
|
780
766
|
if (header) {
|
|
781
767
|
const rect = header.getBoundingClientRect();
|
|
782
|
-
active_header_menu = {
|
|
783
|
-
col,
|
|
784
|
-
x: rect.right,
|
|
785
|
-
y: rect.bottom
|
|
786
|
-
};
|
|
768
|
+
active_header_menu = { col, x: rect.right, y: rect.bottom };
|
|
787
769
|
}
|
|
788
770
|
}
|
|
789
771
|
}
|
|
@@ -827,6 +809,94 @@
|
|
|
827
809
|
active_cell_menu = null;
|
|
828
810
|
active_header_menu = null;
|
|
829
811
|
}
|
|
812
|
+
|
|
813
|
+
let row_order: number[] = [];
|
|
814
|
+
|
|
815
|
+
$: {
|
|
816
|
+
if (
|
|
817
|
+
typeof sort_by === "number" &&
|
|
818
|
+
sort_direction &&
|
|
819
|
+
sort_by >= 0 &&
|
|
820
|
+
sort_by < data[0].length
|
|
821
|
+
) {
|
|
822
|
+
const indices = [...Array(data.length)].map((_, i) => i);
|
|
823
|
+
const sort_index = sort_by as number;
|
|
824
|
+
indices.sort((a, b) => {
|
|
825
|
+
const row_a = data[a];
|
|
826
|
+
const row_b = data[b];
|
|
827
|
+
if (
|
|
828
|
+
!row_a ||
|
|
829
|
+
!row_b ||
|
|
830
|
+
sort_index >= row_a.length ||
|
|
831
|
+
sort_index >= row_b.length
|
|
832
|
+
)
|
|
833
|
+
return 0;
|
|
834
|
+
const val_a = row_a[sort_index].value;
|
|
835
|
+
const val_b = row_b[sort_index].value;
|
|
836
|
+
const comp = val_a < val_b ? -1 : val_a > val_b ? 1 : 0;
|
|
837
|
+
return sort_direction === "asc" ? comp : -comp;
|
|
838
|
+
});
|
|
839
|
+
row_order = indices;
|
|
840
|
+
} else {
|
|
841
|
+
row_order = [...Array(data.length)].map((_, i) => i);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
function handle_select_column(col: number): void {
|
|
846
|
+
selected_cells = select_column(data, col);
|
|
847
|
+
selected = selected_cells[0];
|
|
848
|
+
editing = false;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
function handle_select_row(row: number): void {
|
|
852
|
+
selected_cells = select_row(data, row);
|
|
853
|
+
selected = selected_cells[0];
|
|
854
|
+
editing = false;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
let coords: CellCoordinate;
|
|
858
|
+
$: if (selected !== false) coords = selected;
|
|
859
|
+
|
|
860
|
+
$: if (selected !== false) {
|
|
861
|
+
const positions = calculate_selection_positions(
|
|
862
|
+
selected,
|
|
863
|
+
data,
|
|
864
|
+
els,
|
|
865
|
+
parent,
|
|
866
|
+
table
|
|
867
|
+
);
|
|
868
|
+
document.documentElement.style.setProperty(
|
|
869
|
+
"--selected-col-pos",
|
|
870
|
+
positions.col_pos
|
|
871
|
+
);
|
|
872
|
+
if (positions.row_pos) {
|
|
873
|
+
document.documentElement.style.setProperty(
|
|
874
|
+
"--selected-row-pos",
|
|
875
|
+
positions.row_pos
|
|
876
|
+
);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
let current_search_query: string | null = null;
|
|
881
|
+
|
|
882
|
+
function handle_search(search_query: string | null): void {
|
|
883
|
+
current_search_query = search_query;
|
|
884
|
+
dispatch("search", search_query);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
function commit_filter(): void {
|
|
888
|
+
if (current_search_query && show_search === "filter") {
|
|
889
|
+
dispatch("change", {
|
|
890
|
+
data: data.map((row) => row.map((cell) => cell.value)),
|
|
891
|
+
headers: _headers.map((h) => h.value),
|
|
892
|
+
metadata: null
|
|
893
|
+
});
|
|
894
|
+
if (!value_is_output) {
|
|
895
|
+
dispatch("input");
|
|
896
|
+
}
|
|
897
|
+
current_search_query = null;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
830
900
|
</script>
|
|
831
901
|
|
|
832
902
|
<svelte:window on:resize={() => set_cell_widths()} />
|
|
@@ -844,6 +914,10 @@
|
|
|
844
914
|
on:click={toggle_fullscreen}
|
|
845
915
|
on_copy={handle_copy}
|
|
846
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}
|
|
847
921
|
/>
|
|
848
922
|
</div>
|
|
849
923
|
<div
|
|
@@ -851,11 +925,28 @@
|
|
|
851
925
|
class="table-wrap"
|
|
852
926
|
class:dragging
|
|
853
927
|
class:no-wrap={!wrap}
|
|
854
|
-
style="height:{table_height}px"
|
|
928
|
+
style="height:{table_height}px;"
|
|
929
|
+
class:menu-open={active_cell_menu || active_header_menu}
|
|
855
930
|
on:keydown={(e) => handle_keydown(e)}
|
|
856
931
|
role="grid"
|
|
857
932
|
tabindex="0"
|
|
858
933
|
>
|
|
934
|
+
{#if selected !== false && selected_cells.length === 1}
|
|
935
|
+
<button
|
|
936
|
+
class="selection-button selection-button-column"
|
|
937
|
+
on:click|stopPropagation={() => handle_select_column(coords[1])}
|
|
938
|
+
aria-label="Select column"
|
|
939
|
+
>
|
|
940
|
+
⋮
|
|
941
|
+
</button>
|
|
942
|
+
<button
|
|
943
|
+
class="selection-button selection-button-row"
|
|
944
|
+
on:click|stopPropagation={() => handle_select_row(coords[0])}
|
|
945
|
+
aria-label="Select row"
|
|
946
|
+
>
|
|
947
|
+
⋮
|
|
948
|
+
</button>
|
|
949
|
+
{/if}
|
|
859
950
|
<table
|
|
860
951
|
bind:contentRect={t_rect}
|
|
861
952
|
bind:this={table}
|
|
@@ -867,39 +958,59 @@
|
|
|
867
958
|
<thead>
|
|
868
959
|
<tr>
|
|
869
960
|
{#if show_row_numbers}
|
|
870
|
-
<th
|
|
961
|
+
<th
|
|
962
|
+
class="row-number-header frozen-column always-frozen"
|
|
963
|
+
style="left: 0;"
|
|
964
|
+
>
|
|
965
|
+
<div class="cell-wrap">
|
|
966
|
+
<div class="header-content">
|
|
967
|
+
<div class="header-text"></div>
|
|
968
|
+
</div>
|
|
969
|
+
</div>
|
|
970
|
+
</th>
|
|
871
971
|
{/if}
|
|
872
972
|
{#each _headers as { value, id }, i (id)}
|
|
873
973
|
<th
|
|
974
|
+
class:frozen-column={i < actual_pinned_columns}
|
|
975
|
+
class:last-frozen={show_row_numbers
|
|
976
|
+
? i === actual_pinned_columns - 1
|
|
977
|
+
: i === actual_pinned_columns - 1}
|
|
874
978
|
class:editing={header_edit === i}
|
|
875
979
|
aria-sort={get_sort_status(value, sort_by, sort_direction)}
|
|
876
|
-
style:
|
|
980
|
+
style="width: {column_widths.length
|
|
981
|
+
? column_widths[i]
|
|
982
|
+
: undefined}; left: {i < actual_pinned_columns
|
|
983
|
+
? i === 0
|
|
984
|
+
? show_row_numbers
|
|
985
|
+
? 'var(--cell-width-row-number)'
|
|
986
|
+
: '0'
|
|
987
|
+
: `calc(${show_row_numbers ? 'var(--cell-width-row-number) + ' : ''}${Array(
|
|
988
|
+
i
|
|
989
|
+
)
|
|
990
|
+
.fill(0)
|
|
991
|
+
.map((_, idx) => `var(--cell-width-${idx})`)
|
|
992
|
+
.join(' + ')})`
|
|
993
|
+
: 'auto'};"
|
|
877
994
|
>
|
|
878
995
|
<div class="cell-wrap">
|
|
879
|
-
<
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
class
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
viewBox="0 0 9 7"
|
|
898
|
-
fill="none"
|
|
899
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
900
|
-
>
|
|
901
|
-
<path d="M4.49999 0L8.3971 6.75H0.602875L4.49999 0Z" />
|
|
902
|
-
</svg>
|
|
996
|
+
<div class="header-content">
|
|
997
|
+
<EditableCell
|
|
998
|
+
{value}
|
|
999
|
+
{latex_delimiters}
|
|
1000
|
+
{line_breaks}
|
|
1001
|
+
header
|
|
1002
|
+
edit={false}
|
|
1003
|
+
el={null}
|
|
1004
|
+
{root}
|
|
1005
|
+
{editable}
|
|
1006
|
+
/>
|
|
1007
|
+
<div class="sort-buttons">
|
|
1008
|
+
<SortIcon
|
|
1009
|
+
direction={sort_by === i ? sort_direction : null}
|
|
1010
|
+
on:sort={({ detail }) => handle_sort(i, detail)}
|
|
1011
|
+
{i18n}
|
|
1012
|
+
/>
|
|
1013
|
+
</div>
|
|
903
1014
|
</div>
|
|
904
1015
|
</div>
|
|
905
1016
|
</th>
|
|
@@ -919,6 +1030,7 @@
|
|
|
919
1030
|
edit={false}
|
|
920
1031
|
el={null}
|
|
921
1032
|
{root}
|
|
1033
|
+
{editable}
|
|
922
1034
|
/>
|
|
923
1035
|
</div>
|
|
924
1036
|
</td>
|
|
@@ -934,8 +1046,23 @@
|
|
|
934
1046
|
boundedheight={false}
|
|
935
1047
|
disable_click={true}
|
|
936
1048
|
{root}
|
|
937
|
-
on:load={(
|
|
1049
|
+
on:load={({ detail }) =>
|
|
1050
|
+
handle_file_upload(
|
|
1051
|
+
detail.data,
|
|
1052
|
+
(head) => {
|
|
1053
|
+
_headers = make_headers(
|
|
1054
|
+
head.map((h) => h ?? ""),
|
|
1055
|
+
col_count,
|
|
1056
|
+
els
|
|
1057
|
+
);
|
|
1058
|
+
return _headers;
|
|
1059
|
+
},
|
|
1060
|
+
(vals) => {
|
|
1061
|
+
values = vals;
|
|
1062
|
+
}
|
|
1063
|
+
)}
|
|
938
1064
|
bind:dragging
|
|
1065
|
+
aria_label={i18n("dataframe.drop_to_upload")}
|
|
939
1066
|
>
|
|
940
1067
|
<VirtualTable
|
|
941
1068
|
bind:items={data}
|
|
@@ -943,19 +1070,44 @@
|
|
|
943
1070
|
bind:actual_height={table_height}
|
|
944
1071
|
bind:table_scrollbar_width={scrollbar_width}
|
|
945
1072
|
selected={selected_index}
|
|
1073
|
+
disable_scroll={active_cell_menu !== null ||
|
|
1074
|
+
active_header_menu !== null}
|
|
946
1075
|
>
|
|
947
1076
|
{#if label && label.length !== 0}
|
|
948
1077
|
<caption class="sr-only">{label}</caption>
|
|
949
1078
|
{/if}
|
|
950
1079
|
<tr slot="thead">
|
|
951
1080
|
{#if show_row_numbers}
|
|
952
|
-
<th
|
|
1081
|
+
<th
|
|
1082
|
+
class="row-number-header frozen-column always-frozen"
|
|
1083
|
+
style="left: 0;"
|
|
1084
|
+
>
|
|
1085
|
+
<div class="cell-wrap">
|
|
1086
|
+
<div class="header-content">
|
|
1087
|
+
<div class="header-text"></div>
|
|
1088
|
+
</div>
|
|
1089
|
+
</div>
|
|
1090
|
+
</th>
|
|
953
1091
|
{/if}
|
|
954
1092
|
{#each _headers as { value, id }, i (id)}
|
|
955
1093
|
<th
|
|
1094
|
+
class:frozen-column={i < actual_pinned_columns}
|
|
1095
|
+
class:last-frozen={i === actual_pinned_columns - 1}
|
|
956
1096
|
class:focus={header_edit === i || selected_header === i}
|
|
957
1097
|
aria-sort={get_sort_status(value, sort_by, sort_direction)}
|
|
958
|
-
style="width:
|
|
1098
|
+
style="width: {get_cell_width(i)}; left: {i <
|
|
1099
|
+
actual_pinned_columns
|
|
1100
|
+
? i === 0
|
|
1101
|
+
? show_row_numbers
|
|
1102
|
+
? 'var(--cell-width-row-number)'
|
|
1103
|
+
: '0'
|
|
1104
|
+
: `calc(${show_row_numbers ? 'var(--cell-width-row-number) + ' : ''}${Array(
|
|
1105
|
+
i
|
|
1106
|
+
)
|
|
1107
|
+
.fill(0)
|
|
1108
|
+
.map((_, idx) => `var(--cell-width-${idx})`)
|
|
1109
|
+
.join(' + ')})`
|
|
1110
|
+
: 'auto'};"
|
|
959
1111
|
on:click={() => {
|
|
960
1112
|
toggle_header_button(i);
|
|
961
1113
|
}}
|
|
@@ -963,6 +1115,7 @@
|
|
|
963
1115
|
<div class="cell-wrap">
|
|
964
1116
|
<div class="header-content">
|
|
965
1117
|
<EditableCell
|
|
1118
|
+
{max_chars}
|
|
966
1119
|
bind:value={_headers[i].value}
|
|
967
1120
|
bind:el={els[id].input}
|
|
968
1121
|
{latex_delimiters}
|
|
@@ -972,84 +1125,76 @@
|
|
|
972
1125
|
on:dblclick={() => edit_header(i)}
|
|
973
1126
|
header
|
|
974
1127
|
{root}
|
|
1128
|
+
{editable}
|
|
975
1129
|
/>
|
|
976
|
-
<
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
handle_sort(i);
|
|
984
|
-
}}
|
|
985
|
-
>
|
|
986
|
-
<svg
|
|
987
|
-
width="1em"
|
|
988
|
-
height="1em"
|
|
989
|
-
viewBox="0 0 9 7"
|
|
990
|
-
fill="none"
|
|
991
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
992
|
-
>
|
|
993
|
-
<path d="M4.49999 0L8.3971 6.75H0.602875L4.49999 0Z" />
|
|
994
|
-
</svg>
|
|
995
|
-
</button>
|
|
1130
|
+
<div class="sort-buttons">
|
|
1131
|
+
<SortIcon
|
|
1132
|
+
direction={sort_by === i ? sort_direction : null}
|
|
1133
|
+
on:sort={({ detail }) => handle_sort(i, detail)}
|
|
1134
|
+
{i18n}
|
|
1135
|
+
/>
|
|
1136
|
+
</div>
|
|
996
1137
|
</div>
|
|
997
|
-
|
|
998
1138
|
{#if editable}
|
|
999
1139
|
<button
|
|
1000
1140
|
class="cell-menu-button"
|
|
1001
1141
|
on:click={(event) => toggle_header_menu(event, i)}
|
|
1002
1142
|
>
|
|
1003
|
-
|
|
1143
|
+
⋮
|
|
1004
1144
|
</button>
|
|
1005
1145
|
{/if}
|
|
1006
1146
|
</div>
|
|
1007
1147
|
</th>
|
|
1008
1148
|
{/each}
|
|
1009
1149
|
</tr>
|
|
1010
|
-
|
|
1011
1150
|
<tr slot="tbody" let:item let:index class:row_odd={index % 2 === 0}>
|
|
1012
1151
|
{#if show_row_numbers}
|
|
1013
|
-
<td
|
|
1152
|
+
<td
|
|
1153
|
+
class="row-number frozen-column always-frozen"
|
|
1154
|
+
style="left: 0;"
|
|
1155
|
+
tabindex="-1"
|
|
1156
|
+
>
|
|
1157
|
+
{index + 1}
|
|
1158
|
+
</td>
|
|
1014
1159
|
{/if}
|
|
1015
1160
|
{#each item as { value, id }, j (id)}
|
|
1016
1161
|
<td
|
|
1017
|
-
|
|
1162
|
+
class:frozen-column={j < actual_pinned_columns}
|
|
1163
|
+
class:last-frozen={j === actual_pinned_columns - 1}
|
|
1164
|
+
tabindex={show_row_numbers && j === 0 ? -1 : 0}
|
|
1165
|
+
bind:this={els[id].cell}
|
|
1018
1166
|
on:touchstart={(event) => {
|
|
1019
|
-
event.
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
}
|
|
1029
|
-
toggle_cell_button(index, j);
|
|
1167
|
+
const touch = event.touches[0];
|
|
1168
|
+
const mouseEvent = new MouseEvent("click", {
|
|
1169
|
+
clientX: touch.clientX,
|
|
1170
|
+
clientY: touch.clientY,
|
|
1171
|
+
bubbles: true,
|
|
1172
|
+
cancelable: true,
|
|
1173
|
+
view: window
|
|
1174
|
+
});
|
|
1175
|
+
handle_cell_click(mouseEvent, index, j);
|
|
1030
1176
|
}}
|
|
1031
1177
|
on:mousedown={(event) => {
|
|
1032
1178
|
event.preventDefault();
|
|
1033
1179
|
event.stopPropagation();
|
|
1034
1180
|
}}
|
|
1035
|
-
on:click={(event) =>
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
class:focus={dequal(selected, [index, j])}
|
|
1181
|
+
on:click={(event) => handle_cell_click(event, index, j)}
|
|
1182
|
+
style="width: {get_cell_width(j)}; left: {j <
|
|
1183
|
+
actual_pinned_columns
|
|
1184
|
+
? j === 0
|
|
1185
|
+
? show_row_numbers
|
|
1186
|
+
? 'var(--cell-width-row-number)'
|
|
1187
|
+
: '0'
|
|
1188
|
+
: `calc(${show_row_numbers ? 'var(--cell-width-row-number) + ' : ''}${Array(
|
|
1189
|
+
j
|
|
1190
|
+
)
|
|
1191
|
+
.fill(0)
|
|
1192
|
+
.map((_, idx) => `var(--cell-width-${idx})`)
|
|
1193
|
+
.join(' + ')})`
|
|
1194
|
+
: 'auto'}; {styling?.[index]?.[j] || ''}"
|
|
1195
|
+
class:flash={copy_flash &&
|
|
1196
|
+
is_cell_selected([index, j], selected_cells)}
|
|
1197
|
+
class={is_cell_selected([index, j], selected_cells)}
|
|
1053
1198
|
class:menu-active={active_cell_menu &&
|
|
1054
1199
|
active_cell_menu.row === index &&
|
|
1055
1200
|
active_cell_menu.col === j}
|
|
@@ -1068,15 +1213,25 @@
|
|
|
1068
1213
|
clear_on_focus = false;
|
|
1069
1214
|
parent.focus();
|
|
1070
1215
|
}}
|
|
1216
|
+
on:focus={() => {
|
|
1217
|
+
const row = index;
|
|
1218
|
+
const col = j;
|
|
1219
|
+
if (
|
|
1220
|
+
!selected_cells.some(([r, c]) => r === row && c === col)
|
|
1221
|
+
) {
|
|
1222
|
+
selected_cells = [[row, col]];
|
|
1223
|
+
}
|
|
1224
|
+
}}
|
|
1071
1225
|
{clear_on_focus}
|
|
1072
1226
|
{root}
|
|
1227
|
+
{max_chars}
|
|
1073
1228
|
/>
|
|
1074
|
-
{#if editable}
|
|
1229
|
+
{#if editable && should_show_cell_menu([index, j], selected_cells, editable)}
|
|
1075
1230
|
<button
|
|
1076
1231
|
class="cell-menu-button"
|
|
1077
1232
|
on:click={(event) => toggle_cell_menu(event, index, j)}
|
|
1078
1233
|
>
|
|
1079
|
-
|
|
1234
|
+
⋮
|
|
1080
1235
|
</button>
|
|
1081
1236
|
{/if}
|
|
1082
1237
|
</div>
|
|
@@ -1128,15 +1283,6 @@
|
|
|
1128
1283
|
{/if}
|
|
1129
1284
|
|
|
1130
1285
|
<style>
|
|
1131
|
-
.button-wrap:hover svg {
|
|
1132
|
-
color: var(--color-accent);
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
.button-wrap svg {
|
|
1136
|
-
margin-right: var(--size-1);
|
|
1137
|
-
margin-left: -5px;
|
|
1138
|
-
}
|
|
1139
|
-
|
|
1140
1286
|
.label p {
|
|
1141
1287
|
position: relative;
|
|
1142
1288
|
z-index: var(--layer-4);
|
|
@@ -1145,17 +1291,25 @@
|
|
|
1145
1291
|
font-size: var(--block-label-text-size);
|
|
1146
1292
|
}
|
|
1147
1293
|
|
|
1294
|
+
.table-container {
|
|
1295
|
+
display: flex;
|
|
1296
|
+
flex-direction: column;
|
|
1297
|
+
gap: var(--size-2);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1148
1300
|
.table-wrap {
|
|
1149
1301
|
position: relative;
|
|
1150
1302
|
transition: 150ms;
|
|
1151
1303
|
border: 1px solid var(--border-color-primary);
|
|
1152
1304
|
border-radius: var(--table-radius);
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
.table-wrap.menu-open {
|
|
1153
1308
|
overflow: hidden;
|
|
1154
1309
|
}
|
|
1155
1310
|
|
|
1156
1311
|
.table-wrap:focus-within {
|
|
1157
1312
|
outline: none;
|
|
1158
|
-
background-color: none;
|
|
1159
1313
|
}
|
|
1160
1314
|
|
|
1161
1315
|
.dragging {
|
|
@@ -1177,6 +1331,7 @@
|
|
|
1177
1331
|
line-height: var(--line-md);
|
|
1178
1332
|
font-family: var(--font-mono);
|
|
1179
1333
|
border-spacing: 0;
|
|
1334
|
+
border-collapse: separate;
|
|
1180
1335
|
}
|
|
1181
1336
|
|
|
1182
1337
|
div:not(.no-wrap) td {
|
|
@@ -1194,8 +1349,7 @@
|
|
|
1194
1349
|
thead {
|
|
1195
1350
|
position: sticky;
|
|
1196
1351
|
top: 0;
|
|
1197
|
-
|
|
1198
|
-
z-index: var(--layer-1);
|
|
1352
|
+
z-index: var(--layer-2);
|
|
1199
1353
|
box-shadow: var(--shadow-drop);
|
|
1200
1354
|
}
|
|
1201
1355
|
|
|
@@ -1231,6 +1385,12 @@
|
|
|
1231
1385
|
th.focus,
|
|
1232
1386
|
td.focus {
|
|
1233
1387
|
--ring-color: var(--color-accent);
|
|
1388
|
+
box-shadow: inset 0 0 0 2px var(--ring-color);
|
|
1389
|
+
z-index: var(--layer-1);
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
th.focus {
|
|
1393
|
+
z-index: var(--layer-2);
|
|
1234
1394
|
}
|
|
1235
1395
|
|
|
1236
1396
|
tr:last-child td:first-child {
|
|
@@ -1245,33 +1405,10 @@
|
|
|
1245
1405
|
background: var(--table-even-background-fill);
|
|
1246
1406
|
}
|
|
1247
1407
|
|
|
1248
|
-
|
|
1249
|
-
fill: currentColor;
|
|
1250
|
-
font-size: 10px;
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
.sort-button {
|
|
1408
|
+
.sort-buttons {
|
|
1254
1409
|
display: flex;
|
|
1255
|
-
flex: none;
|
|
1256
|
-
justify-content: center;
|
|
1257
1410
|
align-items: center;
|
|
1258
|
-
|
|
1259
|
-
cursor: pointer;
|
|
1260
|
-
padding: var(--size-2);
|
|
1261
|
-
color: var(--body-text-color-subdued);
|
|
1262
|
-
line-height: var(--text-sm);
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
.sort-button:hover {
|
|
1266
|
-
color: var(--body-text-color);
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
|
-
.des {
|
|
1270
|
-
transform: scaleY(-1);
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
.sort-button.sorted {
|
|
1274
|
-
color: var(--color-accent);
|
|
1411
|
+
flex-shrink: 0;
|
|
1275
1412
|
}
|
|
1276
1413
|
|
|
1277
1414
|
.editing {
|
|
@@ -1280,25 +1417,26 @@
|
|
|
1280
1417
|
|
|
1281
1418
|
.cell-wrap {
|
|
1282
1419
|
display: flex;
|
|
1283
|
-
align-items:
|
|
1420
|
+
align-items: flex-start;
|
|
1284
1421
|
outline: none;
|
|
1285
|
-
height: var(--size-full);
|
|
1286
1422
|
min-height: var(--size-9);
|
|
1287
|
-
|
|
1423
|
+
position: relative;
|
|
1424
|
+
height: auto;
|
|
1288
1425
|
}
|
|
1289
1426
|
|
|
1290
1427
|
.header-content {
|
|
1291
1428
|
display: flex;
|
|
1292
1429
|
align-items: center;
|
|
1430
|
+
justify-content: space-between;
|
|
1293
1431
|
overflow: hidden;
|
|
1294
1432
|
flex-grow: 1;
|
|
1295
1433
|
min-width: 0;
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1434
|
+
white-space: normal;
|
|
1435
|
+
overflow-wrap: break-word;
|
|
1436
|
+
word-break: normal;
|
|
1437
|
+
height: 100%;
|
|
1438
|
+
padding: var(--size-1);
|
|
1439
|
+
gap: var(--size-1);
|
|
1302
1440
|
}
|
|
1303
1441
|
|
|
1304
1442
|
.row_odd {
|
|
@@ -1309,10 +1447,6 @@
|
|
|
1309
1447
|
background: var(--background-fill-primary);
|
|
1310
1448
|
}
|
|
1311
1449
|
|
|
1312
|
-
table {
|
|
1313
|
-
border-collapse: separate;
|
|
1314
|
-
}
|
|
1315
|
-
|
|
1316
1450
|
.cell-menu-button {
|
|
1317
1451
|
flex-shrink: 0;
|
|
1318
1452
|
display: none;
|
|
@@ -1325,77 +1459,227 @@
|
|
|
1325
1459
|
padding: 0;
|
|
1326
1460
|
margin-right: var(--spacing-sm);
|
|
1327
1461
|
z-index: var(--layer-1);
|
|
1462
|
+
position: absolute;
|
|
1463
|
+
right: var(--size-1);
|
|
1464
|
+
top: 50%;
|
|
1465
|
+
transform: translateY(-50%);
|
|
1328
1466
|
}
|
|
1329
1467
|
|
|
1330
|
-
.cell-menu-button
|
|
1331
|
-
|
|
1468
|
+
.cell-selected .cell-menu-button {
|
|
1469
|
+
display: flex;
|
|
1470
|
+
align-items: center;
|
|
1471
|
+
justify-content: center;
|
|
1332
1472
|
}
|
|
1333
1473
|
|
|
1334
|
-
|
|
1474
|
+
.header-row {
|
|
1335
1475
|
display: flex;
|
|
1476
|
+
justify-content: flex-end;
|
|
1336
1477
|
align-items: center;
|
|
1337
|
-
|
|
1478
|
+
gap: var(--size-2);
|
|
1479
|
+
min-height: var(--size-6);
|
|
1480
|
+
flex-wrap: nowrap;
|
|
1481
|
+
width: 100%;
|
|
1338
1482
|
}
|
|
1339
1483
|
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
word-break: break-word;
|
|
1484
|
+
.label {
|
|
1485
|
+
flex: 1 1 auto;
|
|
1486
|
+
margin-right: auto;
|
|
1344
1487
|
}
|
|
1345
1488
|
|
|
1346
|
-
.
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1489
|
+
.label p {
|
|
1490
|
+
margin: 0;
|
|
1491
|
+
color: var(--block-label-text-color);
|
|
1492
|
+
font-size: var(--block-label-text-size);
|
|
1493
|
+
line-height: var(--line-sm);
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
.toolbar {
|
|
1497
|
+
flex: 0 0 auto;
|
|
1350
1498
|
}
|
|
1351
1499
|
|
|
1352
1500
|
.row-number,
|
|
1353
1501
|
.row-number-header {
|
|
1354
|
-
width: var(--size-7);
|
|
1355
|
-
min-width: var(--size-7);
|
|
1356
1502
|
text-align: center;
|
|
1357
1503
|
background: var(--table-even-background-fill);
|
|
1358
|
-
position: sticky;
|
|
1359
|
-
left: 0;
|
|
1360
1504
|
font-size: var(--input-text-size);
|
|
1361
1505
|
color: var(--body-text-color);
|
|
1362
|
-
padding: var(--size-1)
|
|
1506
|
+
padding: var(--size-1);
|
|
1507
|
+
min-width: var(--size-12);
|
|
1508
|
+
width: var(--size-12);
|
|
1363
1509
|
overflow: hidden;
|
|
1364
1510
|
text-overflow: ellipsis;
|
|
1365
1511
|
white-space: nowrap;
|
|
1366
1512
|
font-weight: var(--weight-semibold);
|
|
1367
1513
|
}
|
|
1368
1514
|
|
|
1369
|
-
.row-number-header {
|
|
1370
|
-
|
|
1515
|
+
.row-number-header .header-content {
|
|
1516
|
+
justify-content: space-between;
|
|
1517
|
+
padding: var(--size-1);
|
|
1518
|
+
height: var(--size-9);
|
|
1519
|
+
display: flex;
|
|
1520
|
+
align-items: center;
|
|
1371
1521
|
}
|
|
1372
1522
|
|
|
1373
|
-
.row-number {
|
|
1374
|
-
|
|
1523
|
+
.row-number-header :global(.sort-icons) {
|
|
1524
|
+
margin-right: 0;
|
|
1375
1525
|
}
|
|
1376
1526
|
|
|
1377
1527
|
:global(tbody > tr:nth-child(odd)) .row-number {
|
|
1378
1528
|
background: var(--table-odd-background-fill);
|
|
1379
1529
|
}
|
|
1380
1530
|
|
|
1381
|
-
.
|
|
1531
|
+
.cell-selected {
|
|
1532
|
+
--ring-color: var(--color-accent);
|
|
1533
|
+
box-shadow: inset 0 0 0 2px var(--ring-color);
|
|
1534
|
+
z-index: var(--layer-1);
|
|
1535
|
+
position: relative;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
.cell-selected.no-top {
|
|
1539
|
+
box-shadow:
|
|
1540
|
+
inset 2px 0 0 var(--ring-color),
|
|
1541
|
+
inset -2px 0 0 var(--ring-color),
|
|
1542
|
+
inset 0 -2px 0 var(--ring-color);
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
.cell-selected.no-bottom {
|
|
1546
|
+
box-shadow:
|
|
1547
|
+
inset 2px 0 0 var(--ring-color),
|
|
1548
|
+
inset -2px 0 0 var(--ring-color),
|
|
1549
|
+
inset 0 2px 0 var(--ring-color);
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
.cell-selected.no-left {
|
|
1553
|
+
box-shadow:
|
|
1554
|
+
inset 0 2px 0 var(--ring-color),
|
|
1555
|
+
inset -2px 0 0 var(--ring-color),
|
|
1556
|
+
inset 0 -2px 0 var(--ring-color);
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
.cell-selected.no-right {
|
|
1560
|
+
box-shadow:
|
|
1561
|
+
inset 0 2px 0 var(--ring-color),
|
|
1562
|
+
inset 2px 0 0 var(--ring-color),
|
|
1563
|
+
inset 0 -2px 0 var(--ring-color);
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
.cell-selected.no-top.no-left {
|
|
1567
|
+
box-shadow:
|
|
1568
|
+
inset -2px 0 0 var(--ring-color),
|
|
1569
|
+
inset 0 -2px 0 var(--ring-color);
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
.cell-selected.no-top.no-right {
|
|
1573
|
+
box-shadow:
|
|
1574
|
+
inset 2px 0 0 var(--ring-color),
|
|
1575
|
+
inset 0 -2px 0 var(--ring-color);
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
.cell-selected.no-bottom.no-left {
|
|
1579
|
+
box-shadow:
|
|
1580
|
+
inset -2px 0 0 var(--ring-color),
|
|
1581
|
+
inset 0 2px 0 var(--ring-color);
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
.cell-selected.no-bottom.no-right {
|
|
1585
|
+
box-shadow:
|
|
1586
|
+
inset 2px 0 0 var(--ring-color),
|
|
1587
|
+
inset 0 2px 0 var(--ring-color);
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
.cell-selected.no-top.no-bottom {
|
|
1591
|
+
box-shadow:
|
|
1592
|
+
inset 2px 0 0 var(--ring-color),
|
|
1593
|
+
inset -2px 0 0 var(--ring-color);
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
.cell-selected.no-left.no-right {
|
|
1597
|
+
box-shadow:
|
|
1598
|
+
inset 0 2px 0 var(--ring-color),
|
|
1599
|
+
inset 0 -2px 0 var(--ring-color);
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
.cell-selected.no-top.no-left.no-right {
|
|
1603
|
+
box-shadow: inset 0 -2px 0 var(--ring-color);
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
.cell-selected.no-bottom.no-left.no-right {
|
|
1607
|
+
box-shadow: inset 0 2px 0 var(--ring-color);
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
.cell-selected.no-left.no-top.no-bottom {
|
|
1611
|
+
box-shadow: inset -2px 0 0 var(--ring-color);
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
.cell-selected.no-right.no-top.no-bottom {
|
|
1615
|
+
box-shadow: inset 2px 0 0 var(--ring-color);
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
.cell-selected.no-top.no-bottom.no-left.no-right {
|
|
1619
|
+
box-shadow: none;
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
.selection-button {
|
|
1623
|
+
position: absolute;
|
|
1382
1624
|
display: flex;
|
|
1383
|
-
justify-content: space-between;
|
|
1384
1625
|
align-items: center;
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1626
|
+
justify-content: center;
|
|
1627
|
+
background: var(--color-accent);
|
|
1628
|
+
color: white;
|
|
1629
|
+
border-radius: var(--radius-sm);
|
|
1630
|
+
z-index: var(--layer-4);
|
|
1388
1631
|
}
|
|
1389
1632
|
|
|
1390
|
-
.
|
|
1391
|
-
|
|
1633
|
+
.selection-button-column {
|
|
1634
|
+
width: var(--size-3);
|
|
1635
|
+
height: var(--size-5);
|
|
1636
|
+
top: -10px;
|
|
1637
|
+
left: var(--selected-col-pos);
|
|
1638
|
+
transform: rotate(90deg);
|
|
1392
1639
|
}
|
|
1393
1640
|
|
|
1394
|
-
.
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1641
|
+
.selection-button-row {
|
|
1642
|
+
width: var(--size-3);
|
|
1643
|
+
height: var(--size-5);
|
|
1644
|
+
left: -7px;
|
|
1645
|
+
top: calc(var(--selected-row-pos) - var(--size-5) / 2);
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
.table-wrap:not(:focus-within) .selection-button {
|
|
1649
|
+
opacity: 0;
|
|
1650
|
+
pointer-events: none;
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
.flash.cell-selected {
|
|
1654
|
+
animation: flash-color 700ms ease-out;
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
@keyframes flash-color {
|
|
1658
|
+
0%,
|
|
1659
|
+
30% {
|
|
1660
|
+
background: var(--color-accent-copied);
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
100% {
|
|
1664
|
+
background: transparent;
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
.frozen-column {
|
|
1669
|
+
position: sticky;
|
|
1670
|
+
z-index: var(--layer-2);
|
|
1671
|
+
border-right: 1px solid var(--border-color-primary);
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
tr:nth-child(odd) .frozen-column {
|
|
1675
|
+
background: var(--table-odd-background-fill);
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
tr:nth-child(even) .frozen-column {
|
|
1679
|
+
background: var(--table-even-background-fill);
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
.always-frozen {
|
|
1683
|
+
z-index: var(--layer-3);
|
|
1400
1684
|
}
|
|
1401
1685
|
</style>
|