@gradio/dataframe 0.13.1 → 0.15.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 +28 -0
- package/Dataframe.stories.svelte +148 -2
- package/Index.svelte +4 -0
- package/dist/Index.svelte +4 -0
- package/dist/Index.svelte.d.ts +8 -0
- package/dist/shared/CellMenu.svelte +21 -9
- package/dist/shared/CellMenu.svelte.d.ts +4 -0
- package/dist/shared/CellMenuIcons.svelte +112 -0
- package/dist/shared/CellMenuIcons.svelte.d.ts +16 -0
- package/dist/shared/EditableCell.svelte +52 -7
- package/dist/shared/EditableCell.svelte.d.ts +1 -1
- package/dist/shared/Table.svelte +356 -270
- package/dist/shared/Table.svelte.d.ts +2 -0
- package/dist/shared/Toolbar.svelte +46 -6
- package/dist/shared/Toolbar.svelte.d.ts +2 -0
- package/dist/shared/selection_utils.d.ts +20 -0
- package/dist/shared/selection_utils.js +111 -0
- package/dist/shared/table_utils.d.ts +12 -0
- package/dist/shared/table_utils.js +113 -0
- package/dist/shared/types.d.ts +2 -0
- package/dist/shared/types.js +1 -0
- package/package.json +6 -6
- package/shared/CellMenu.svelte +21 -9
- package/shared/CellMenuIcons.svelte +113 -0
- package/shared/EditableCell.svelte +58 -7
- package/shared/Table.svelte +400 -341
- package/shared/Toolbar.svelte +48 -6
- package/shared/selection_utils.ts +188 -0
- package/shared/table_utils.ts +148 -0
- package/shared/types.ts +2 -0
- package/dist/shared/Arrow.svelte +0 -9
- package/dist/shared/Arrow.svelte.d.ts +0 -16
- package/shared/Arrow.svelte +0 -10
package/dist/shared/Table.svelte
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script>import { afterUpdate, createEventDispatcher, tick, onMount } from "svelte";
|
|
2
|
-
import { dsvFormat } from "d3-dsv";
|
|
3
2
|
import { dequal } from "dequal/lite";
|
|
4
3
|
import { Upload } from "@gradio/upload";
|
|
5
4
|
import EditableCell from "./EditableCell.svelte";
|
|
@@ -7,6 +6,18 @@ import {} from "@gradio/client";
|
|
|
7
6
|
import VirtualTable from "./VirtualTable.svelte";
|
|
8
7
|
import CellMenu from "./CellMenu.svelte";
|
|
9
8
|
import Toolbar from "./Toolbar.svelte";
|
|
9
|
+
import {
|
|
10
|
+
is_cell_selected,
|
|
11
|
+
handle_selection,
|
|
12
|
+
handle_delete_key,
|
|
13
|
+
should_show_cell_menu,
|
|
14
|
+
get_next_cell_coordinates,
|
|
15
|
+
get_range_selection,
|
|
16
|
+
move_cursor,
|
|
17
|
+
get_current_indices,
|
|
18
|
+
handle_click_outside as handle_click_outside_util
|
|
19
|
+
} from "./selection_utils";
|
|
20
|
+
import { copy_table_data, get_max, handle_file_upload } from "./table_utils";
|
|
10
21
|
export let datatype;
|
|
11
22
|
export let label = null;
|
|
12
23
|
export let show_label = true;
|
|
@@ -26,31 +37,30 @@ export let show_row_numbers = false;
|
|
|
26
37
|
export let upload;
|
|
27
38
|
export let stream_handler;
|
|
28
39
|
export let show_fullscreen_button = false;
|
|
40
|
+
export let show_copy_button = false;
|
|
29
41
|
export let value_is_output = false;
|
|
42
|
+
export let max_chars = void 0;
|
|
43
|
+
let selected_cells = [];
|
|
44
|
+
$:
|
|
45
|
+
selected_cells = [...selected_cells];
|
|
30
46
|
let selected = false;
|
|
31
|
-
|
|
47
|
+
$:
|
|
48
|
+
selected = selected_cells.length > 0 ? selected_cells[selected_cells.length - 1] : false;
|
|
32
49
|
export let display_value = null;
|
|
33
50
|
export let styling = null;
|
|
34
51
|
let t_rect;
|
|
52
|
+
let els = {};
|
|
53
|
+
let data_binding = {};
|
|
35
54
|
const dispatch = createEventDispatcher();
|
|
36
55
|
let editing = false;
|
|
56
|
+
let clear_on_focus = false;
|
|
57
|
+
let header_edit = false;
|
|
58
|
+
let selected_header = false;
|
|
59
|
+
let active_cell_menu = null;
|
|
60
|
+
let active_header_menu = null;
|
|
61
|
+
let is_fullscreen = false;
|
|
62
|
+
let dragging = false;
|
|
37
63
|
const get_data_at = (row, col) => data?.[row]?.[col]?.value;
|
|
38
|
-
let last_selected = null;
|
|
39
|
-
$: {
|
|
40
|
-
if (selected !== false && !dequal(selected, last_selected)) {
|
|
41
|
-
const [row, col] = selected;
|
|
42
|
-
if (!isNaN(row) && !isNaN(col) && data[row]) {
|
|
43
|
-
dispatch("select", {
|
|
44
|
-
index: [row, col],
|
|
45
|
-
value: get_data_at(row, col),
|
|
46
|
-
row_value: data[row].map((d) => d.value)
|
|
47
|
-
});
|
|
48
|
-
last_selected = selected;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
let els = {};
|
|
53
|
-
let data_binding = {};
|
|
54
64
|
function make_id() {
|
|
55
65
|
return Math.random().toString(36).substring(2, 15);
|
|
56
66
|
}
|
|
@@ -75,9 +85,7 @@ function make_headers(_head) {
|
|
|
75
85
|
}
|
|
76
86
|
function process_data(_values) {
|
|
77
87
|
const data_row_length = _values.length;
|
|
78
|
-
return Array(
|
|
79
|
-
row_count[1] === "fixed" ? row_count[0] : data_row_length < row_count[0] ? row_count[0] : data_row_length
|
|
80
|
-
).fill(0).map(
|
|
88
|
+
return Array(row_count[1] === "fixed" ? row_count[0] : data_row_length).fill(0).map(
|
|
81
89
|
(_, i) => Array(
|
|
82
90
|
col_count[1] === "fixed" ? col_count[0] : data_row_length > 0 ? _values[0].length : headers.length
|
|
83
91
|
).fill(0).map((_2, j) => {
|
|
@@ -135,36 +143,6 @@ function get_sort_status(name, _sort, direction) {
|
|
|
135
143
|
}
|
|
136
144
|
return "none";
|
|
137
145
|
}
|
|
138
|
-
function get_current_indices(id) {
|
|
139
|
-
return data.reduce(
|
|
140
|
-
(acc, arr, i) => {
|
|
141
|
-
const j = arr.reduce(
|
|
142
|
-
(_acc, _data, k) => id === _data.id ? k : _acc,
|
|
143
|
-
-1
|
|
144
|
-
);
|
|
145
|
-
return j === -1 ? acc : [i, j];
|
|
146
|
-
},
|
|
147
|
-
[-1, -1]
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
function move_cursor(key, current_coords) {
|
|
151
|
-
const dir = {
|
|
152
|
-
ArrowRight: [0, 1],
|
|
153
|
-
ArrowLeft: [0, -1],
|
|
154
|
-
ArrowDown: [1, 0],
|
|
155
|
-
ArrowUp: [-1, 0]
|
|
156
|
-
}[key];
|
|
157
|
-
const i = current_coords[0] + dir[0];
|
|
158
|
-
const j = current_coords[1] + dir[1];
|
|
159
|
-
if (i < 0 && j <= 0) {
|
|
160
|
-
selected_header = j;
|
|
161
|
-
selected = false;
|
|
162
|
-
} else {
|
|
163
|
-
const is_data = data[i]?.[j];
|
|
164
|
-
selected = is_data ? [i, j] : selected;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
let clear_on_focus = false;
|
|
168
146
|
async function handle_keydown(event) {
|
|
169
147
|
if (selected_header !== false && header_edit === false) {
|
|
170
148
|
switch (event.key) {
|
|
@@ -187,6 +165,43 @@ async function handle_keydown(event) {
|
|
|
187
165
|
break;
|
|
188
166
|
}
|
|
189
167
|
}
|
|
168
|
+
if (event.key === "Delete" || event.key === "Backspace") {
|
|
169
|
+
if (!editable)
|
|
170
|
+
return;
|
|
171
|
+
if (editing) {
|
|
172
|
+
const [row, col] = editing;
|
|
173
|
+
const input_el = els[data[row][col].id].input;
|
|
174
|
+
if (input_el && input_el.selectionStart !== input_el.selectionEnd) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (event.key === "Delete" && input_el?.selectionStart !== input_el?.value.length) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (event.key === "Backspace" && input_el?.selectionStart !== 0) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
event.preventDefault();
|
|
185
|
+
if (selected_cells.length > 0) {
|
|
186
|
+
data = handle_delete_key(data, selected_cells);
|
|
187
|
+
dispatch("change", {
|
|
188
|
+
data: data.map((row) => row.map((cell) => cell.value)),
|
|
189
|
+
headers: _headers.map((h) => h.value),
|
|
190
|
+
metadata: null
|
|
191
|
+
});
|
|
192
|
+
if (!value_is_output) {
|
|
193
|
+
dispatch("input");
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (event.key === "c" && (event.metaKey || event.ctrlKey)) {
|
|
199
|
+
event.preventDefault();
|
|
200
|
+
if (selected_cells.length > 0) {
|
|
201
|
+
await handle_copy();
|
|
202
|
+
}
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
190
205
|
if (!selected) {
|
|
191
206
|
return;
|
|
192
207
|
}
|
|
@@ -199,7 +214,25 @@ async function handle_keydown(event) {
|
|
|
199
214
|
if (editing)
|
|
200
215
|
break;
|
|
201
216
|
event.preventDefault();
|
|
202
|
-
move_cursor(event.key, [i, j]);
|
|
217
|
+
const next_coords = move_cursor(event.key, [i, j], data);
|
|
218
|
+
if (next_coords) {
|
|
219
|
+
if (event.shiftKey) {
|
|
220
|
+
selected_cells = get_range_selection(
|
|
221
|
+
selected_cells.length > 0 ? selected_cells[0] : [i, j],
|
|
222
|
+
next_coords
|
|
223
|
+
);
|
|
224
|
+
editing = false;
|
|
225
|
+
} else {
|
|
226
|
+
selected_cells = [next_coords];
|
|
227
|
+
editing = next_coords;
|
|
228
|
+
clear_on_focus = false;
|
|
229
|
+
}
|
|
230
|
+
selected = next_coords;
|
|
231
|
+
} else if (next_coords === false && event.key === "ArrowUp" && i === 0) {
|
|
232
|
+
selected_header = j;
|
|
233
|
+
selected = false;
|
|
234
|
+
editing = false;
|
|
235
|
+
}
|
|
203
236
|
break;
|
|
204
237
|
case "Escape":
|
|
205
238
|
if (!editable)
|
|
@@ -227,34 +260,26 @@ async function handle_keydown(event) {
|
|
|
227
260
|
selected = [i, j];
|
|
228
261
|
} else {
|
|
229
262
|
editing = [i, j];
|
|
263
|
+
clear_on_focus = false;
|
|
230
264
|
}
|
|
231
265
|
}
|
|
232
266
|
break;
|
|
233
|
-
case "Backspace":
|
|
234
|
-
if (!editable)
|
|
235
|
-
break;
|
|
236
|
-
if (!editing) {
|
|
237
|
-
event.preventDefault();
|
|
238
|
-
data[i][j].value = "";
|
|
239
|
-
}
|
|
240
|
-
break;
|
|
241
|
-
case "Delete":
|
|
242
|
-
if (!editable)
|
|
243
|
-
break;
|
|
244
|
-
if (!editing) {
|
|
245
|
-
event.preventDefault();
|
|
246
|
-
data[i][j].value = "";
|
|
247
|
-
}
|
|
248
|
-
break;
|
|
249
267
|
case "Tab":
|
|
250
|
-
|
|
251
|
-
let is_data_x = data[i][j + direction];
|
|
252
|
-
let is_data_y = data?.[i + direction]?.[direction > 0 ? 0 : _headers.length - 1];
|
|
253
|
-
if (is_data_x || is_data_y) {
|
|
254
|
-
event.preventDefault();
|
|
255
|
-
selected = is_data_x ? [i, j + direction] : [i + direction, direction > 0 ? 0 : _headers.length - 1];
|
|
256
|
-
}
|
|
268
|
+
event.preventDefault();
|
|
257
269
|
editing = false;
|
|
270
|
+
const next_cell = get_next_cell_coordinates(
|
|
271
|
+
[i, j],
|
|
272
|
+
data,
|
|
273
|
+
event.shiftKey
|
|
274
|
+
);
|
|
275
|
+
if (next_cell) {
|
|
276
|
+
selected_cells = [next_cell];
|
|
277
|
+
selected = next_cell;
|
|
278
|
+
if (editable) {
|
|
279
|
+
editing = next_cell;
|
|
280
|
+
clear_on_focus = false;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
258
283
|
break;
|
|
259
284
|
default:
|
|
260
285
|
if (!editable)
|
|
@@ -279,16 +304,13 @@ function handle_sort(col) {
|
|
|
279
304
|
}
|
|
280
305
|
}
|
|
281
306
|
}
|
|
282
|
-
let header_edit;
|
|
283
|
-
let select_on_focus = false;
|
|
284
|
-
let selected_header = false;
|
|
285
307
|
async function edit_header(i, _select = false) {
|
|
286
308
|
if (!editable || col_count[1] !== "dynamic" || header_edit === i)
|
|
287
309
|
return;
|
|
288
310
|
selected = false;
|
|
311
|
+
selected_cells = [];
|
|
289
312
|
selected_header = i;
|
|
290
313
|
header_edit = i;
|
|
291
|
-
select_on_focus = _select;
|
|
292
314
|
}
|
|
293
315
|
function end_header_edit(event) {
|
|
294
316
|
if (!editable)
|
|
@@ -349,78 +371,14 @@ async function add_col(index) {
|
|
|
349
371
|
});
|
|
350
372
|
}
|
|
351
373
|
function handle_click_outside(event) {
|
|
352
|
-
if (
|
|
374
|
+
if (handle_click_outside_util(event, parent)) {
|
|
375
|
+
editing = false;
|
|
376
|
+
selected_cells = [];
|
|
377
|
+
header_edit = false;
|
|
378
|
+
selected_header = false;
|
|
353
379
|
active_cell_menu = null;
|
|
354
380
|
active_header_menu = null;
|
|
355
381
|
}
|
|
356
|
-
const [trigger] = event.composedPath();
|
|
357
|
-
if (parent.contains(trigger)) {
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
clicked_cell = void 0;
|
|
361
|
-
editing = false;
|
|
362
|
-
selected = false;
|
|
363
|
-
header_edit = false;
|
|
364
|
-
selected_header = false;
|
|
365
|
-
active_cell_menu = null;
|
|
366
|
-
active_header_menu = null;
|
|
367
|
-
}
|
|
368
|
-
function guess_delimitaor(text, possibleDelimiters) {
|
|
369
|
-
return possibleDelimiters.filter(weedOut);
|
|
370
|
-
function weedOut(delimiter) {
|
|
371
|
-
var cache = -1;
|
|
372
|
-
return text.split("\n").every(checkLength);
|
|
373
|
-
function checkLength(line) {
|
|
374
|
-
if (!line) {
|
|
375
|
-
return true;
|
|
376
|
-
}
|
|
377
|
-
var length = line.split(delimiter).length;
|
|
378
|
-
if (cache < 0) {
|
|
379
|
-
cache = length;
|
|
380
|
-
}
|
|
381
|
-
return cache === length && length > 1;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
function data_uri_to_blob(data_uri) {
|
|
386
|
-
const byte_str = atob(data_uri.split(",")[1]);
|
|
387
|
-
const mime_str = data_uri.split(",")[0].split(":")[1].split(";")[0];
|
|
388
|
-
const ab = new ArrayBuffer(byte_str.length);
|
|
389
|
-
const ia = new Uint8Array(ab);
|
|
390
|
-
for (let i = 0; i < byte_str.length; i++) {
|
|
391
|
-
ia[i] = byte_str.charCodeAt(i);
|
|
392
|
-
}
|
|
393
|
-
return new Blob([ab], { type: mime_str });
|
|
394
|
-
}
|
|
395
|
-
function blob_to_string(blob) {
|
|
396
|
-
const reader = new FileReader();
|
|
397
|
-
function handle_read(e) {
|
|
398
|
-
if (!e?.target?.result || typeof e.target.result !== "string")
|
|
399
|
-
return;
|
|
400
|
-
const [delimiter] = guess_delimitaor(e.target.result, [",", " "]);
|
|
401
|
-
const [head, ...rest] = dsvFormat(delimiter).parseRows(e.target.result);
|
|
402
|
-
_headers = make_headers(
|
|
403
|
-
col_count[1] === "fixed" ? head.slice(0, col_count[0]) : head
|
|
404
|
-
);
|
|
405
|
-
values = rest;
|
|
406
|
-
reader.removeEventListener("loadend", handle_read);
|
|
407
|
-
}
|
|
408
|
-
reader.addEventListener("loadend", handle_read);
|
|
409
|
-
reader.readAsText(blob);
|
|
410
|
-
}
|
|
411
|
-
let dragging = false;
|
|
412
|
-
function get_max(_d) {
|
|
413
|
-
if (!_d || _d.length === 0 || !_d[0])
|
|
414
|
-
return [];
|
|
415
|
-
let max2 = _d[0].slice();
|
|
416
|
-
for (let i = 0; i < _d.length; i++) {
|
|
417
|
-
for (let j = 0; j < _d[i].length; j++) {
|
|
418
|
-
if (`${max2[j].value}`.length < `${_d[i][j].value}`.length) {
|
|
419
|
-
max2[j] = _d[i][j];
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
return max2;
|
|
424
382
|
}
|
|
425
383
|
$:
|
|
426
384
|
max = get_max(data);
|
|
@@ -476,7 +434,7 @@ function sort_data(_data, _display_value, _styling, col, dir) {
|
|
|
476
434
|
});
|
|
477
435
|
data = data;
|
|
478
436
|
if (id) {
|
|
479
|
-
const [i, j] = get_current_indices(id);
|
|
437
|
+
const [i, j] = get_current_indices(id, data);
|
|
480
438
|
selected = [i, j];
|
|
481
439
|
}
|
|
482
440
|
}
|
|
@@ -486,7 +444,7 @@ $:
|
|
|
486
444
|
selected_index = !!selected && selected[0];
|
|
487
445
|
let is_visible = false;
|
|
488
446
|
onMount(() => {
|
|
489
|
-
const observer = new IntersectionObserver((entries
|
|
447
|
+
const observer = new IntersectionObserver((entries) => {
|
|
490
448
|
entries.forEach((entry) => {
|
|
491
449
|
if (entry.isIntersecting && !is_visible) {
|
|
492
450
|
set_cell_widths();
|
|
@@ -509,8 +467,34 @@ onMount(() => {
|
|
|
509
467
|
);
|
|
510
468
|
};
|
|
511
469
|
});
|
|
512
|
-
|
|
513
|
-
|
|
470
|
+
function handle_cell_click(event, row, col) {
|
|
471
|
+
event.preventDefault();
|
|
472
|
+
event.stopPropagation();
|
|
473
|
+
clear_on_focus = false;
|
|
474
|
+
active_cell_menu = null;
|
|
475
|
+
active_header_menu = null;
|
|
476
|
+
selected_header = false;
|
|
477
|
+
header_edit = false;
|
|
478
|
+
selected_cells = handle_selection([row, col], selected_cells, event);
|
|
479
|
+
if (selected_cells.length === 1 && editable) {
|
|
480
|
+
editing = [row, col];
|
|
481
|
+
tick().then(() => {
|
|
482
|
+
const input_el = els[data[row][col].id].input;
|
|
483
|
+
if (input_el) {
|
|
484
|
+
input_el.focus();
|
|
485
|
+
input_el.selectionStart = input_el.selectionEnd = input_el.value.length;
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
} else {
|
|
489
|
+
editing = false;
|
|
490
|
+
}
|
|
491
|
+
toggle_cell_button(row, col);
|
|
492
|
+
dispatch("select", {
|
|
493
|
+
index: [row, col],
|
|
494
|
+
value: get_data_at(row, col),
|
|
495
|
+
row_value: data[row].map((d) => d.value)
|
|
496
|
+
});
|
|
497
|
+
}
|
|
514
498
|
function toggle_cell_menu(event, row, col) {
|
|
515
499
|
event.stopPropagation();
|
|
516
500
|
if (active_cell_menu && active_cell_menu.row === row && active_cell_menu.col === col) {
|
|
@@ -519,12 +503,7 @@ function toggle_cell_menu(event, row, col) {
|
|
|
519
503
|
const cell = event.target.closest("td");
|
|
520
504
|
if (cell) {
|
|
521
505
|
const rect = cell.getBoundingClientRect();
|
|
522
|
-
active_cell_menu = {
|
|
523
|
-
row,
|
|
524
|
-
col,
|
|
525
|
-
x: rect.right,
|
|
526
|
-
y: rect.bottom
|
|
527
|
-
};
|
|
506
|
+
active_cell_menu = { row, col, x: rect.right, y: rect.bottom };
|
|
528
507
|
}
|
|
529
508
|
}
|
|
530
509
|
}
|
|
@@ -547,21 +526,11 @@ function handle_resize() {
|
|
|
547
526
|
}
|
|
548
527
|
let active_button = null;
|
|
549
528
|
function toggle_header_button(col) {
|
|
550
|
-
|
|
551
|
-
active_button = null;
|
|
552
|
-
} else {
|
|
553
|
-
active_button = { type: "header", col };
|
|
554
|
-
}
|
|
529
|
+
active_button = active_button?.type === "header" && active_button.col === col ? null : { type: "header", col };
|
|
555
530
|
}
|
|
556
531
|
function toggle_cell_button(row, col) {
|
|
557
|
-
|
|
558
|
-
active_button = null;
|
|
559
|
-
} else {
|
|
560
|
-
active_button = { type: "cell", row, col };
|
|
561
|
-
}
|
|
532
|
+
active_button = active_button?.type === "cell" && active_button.row === row && active_button.col === col ? null : { type: "cell", row, col };
|
|
562
533
|
}
|
|
563
|
-
let active_header_menu = null;
|
|
564
|
-
let is_fullscreen = false;
|
|
565
534
|
function toggle_fullscreen() {
|
|
566
535
|
if (!document.fullscreenElement) {
|
|
567
536
|
parent.requestFullscreen();
|
|
@@ -574,6 +543,9 @@ function toggle_fullscreen() {
|
|
|
574
543
|
function handle_fullscreen_change() {
|
|
575
544
|
is_fullscreen = !!document.fullscreenElement;
|
|
576
545
|
}
|
|
546
|
+
async function handle_copy() {
|
|
547
|
+
await copy_table_data(data, _headers, selected_cells);
|
|
548
|
+
}
|
|
577
549
|
function toggle_header_menu(event, col) {
|
|
578
550
|
event.stopPropagation();
|
|
579
551
|
if (active_header_menu && active_header_menu.col === col) {
|
|
@@ -582,17 +554,47 @@ function toggle_header_menu(event, col) {
|
|
|
582
554
|
const header = event.target.closest("th");
|
|
583
555
|
if (header) {
|
|
584
556
|
const rect = header.getBoundingClientRect();
|
|
585
|
-
active_header_menu = {
|
|
586
|
-
col,
|
|
587
|
-
x: rect.right,
|
|
588
|
-
y: rect.bottom
|
|
589
|
-
};
|
|
557
|
+
active_header_menu = { col, x: rect.right, y: rect.bottom };
|
|
590
558
|
}
|
|
591
559
|
}
|
|
592
560
|
}
|
|
593
561
|
afterUpdate(() => {
|
|
594
562
|
value_is_output = false;
|
|
595
563
|
});
|
|
564
|
+
async function delete_row(index) {
|
|
565
|
+
parent.focus();
|
|
566
|
+
if (row_count[1] !== "dynamic")
|
|
567
|
+
return;
|
|
568
|
+
if (data.length <= 1)
|
|
569
|
+
return;
|
|
570
|
+
data.splice(index, 1);
|
|
571
|
+
data = data;
|
|
572
|
+
selected = false;
|
|
573
|
+
}
|
|
574
|
+
async function delete_col(index) {
|
|
575
|
+
parent.focus();
|
|
576
|
+
if (col_count[1] !== "dynamic")
|
|
577
|
+
return;
|
|
578
|
+
if (data[0].length <= 1)
|
|
579
|
+
return;
|
|
580
|
+
_headers.splice(index, 1);
|
|
581
|
+
_headers = _headers;
|
|
582
|
+
data.forEach((row) => {
|
|
583
|
+
row.splice(index, 1);
|
|
584
|
+
});
|
|
585
|
+
data = data;
|
|
586
|
+
selected = false;
|
|
587
|
+
}
|
|
588
|
+
function delete_row_at(index) {
|
|
589
|
+
delete_row(index);
|
|
590
|
+
active_cell_menu = null;
|
|
591
|
+
active_header_menu = null;
|
|
592
|
+
}
|
|
593
|
+
function delete_col_at(index) {
|
|
594
|
+
delete_col(index);
|
|
595
|
+
active_cell_menu = null;
|
|
596
|
+
active_header_menu = null;
|
|
597
|
+
}
|
|
596
598
|
</script>
|
|
597
599
|
|
|
598
600
|
<svelte:window on:resize={() => set_cell_widths()} />
|
|
@@ -608,6 +610,8 @@ afterUpdate(() => {
|
|
|
608
610
|
{show_fullscreen_button}
|
|
609
611
|
{is_fullscreen}
|
|
610
612
|
on:click={toggle_fullscreen}
|
|
613
|
+
on_copy={handle_copy}
|
|
614
|
+
{show_copy_button}
|
|
611
615
|
/>
|
|
612
616
|
</div>
|
|
613
617
|
<div
|
|
@@ -648,6 +652,7 @@ afterUpdate(() => {
|
|
|
648
652
|
edit={false}
|
|
649
653
|
el={null}
|
|
650
654
|
{root}
|
|
655
|
+
{editable}
|
|
651
656
|
/>
|
|
652
657
|
|
|
653
658
|
<div
|
|
@@ -683,6 +688,7 @@ afterUpdate(() => {
|
|
|
683
688
|
edit={false}
|
|
684
689
|
el={null}
|
|
685
690
|
{root}
|
|
691
|
+
{editable}
|
|
686
692
|
/>
|
|
687
693
|
</div>
|
|
688
694
|
</td>
|
|
@@ -698,8 +704,20 @@ afterUpdate(() => {
|
|
|
698
704
|
boundedheight={false}
|
|
699
705
|
disable_click={true}
|
|
700
706
|
{root}
|
|
701
|
-
on:load={(
|
|
707
|
+
on:load={({ detail }) =>
|
|
708
|
+
handle_file_upload(
|
|
709
|
+
detail.data,
|
|
710
|
+
col_count,
|
|
711
|
+
(head) => {
|
|
712
|
+
_headers = make_headers(head);
|
|
713
|
+
return _headers;
|
|
714
|
+
},
|
|
715
|
+
(vals) => {
|
|
716
|
+
values = vals;
|
|
717
|
+
}
|
|
718
|
+
)}
|
|
702
719
|
bind:dragging
|
|
720
|
+
aria_label={i18n("dataframe.drop_to_upload")}
|
|
703
721
|
>
|
|
704
722
|
<VirtualTable
|
|
705
723
|
bind:items={data}
|
|
@@ -727,6 +745,7 @@ afterUpdate(() => {
|
|
|
727
745
|
<div class="cell-wrap">
|
|
728
746
|
<div class="header-content">
|
|
729
747
|
<EditableCell
|
|
748
|
+
{max_chars}
|
|
730
749
|
bind:value={_headers[i].value}
|
|
731
750
|
bind:el={els[id].input}
|
|
732
751
|
{latex_delimiters}
|
|
@@ -736,6 +755,7 @@ afterUpdate(() => {
|
|
|
736
755
|
on:dblclick={() => edit_header(i)}
|
|
737
756
|
header
|
|
738
757
|
{root}
|
|
758
|
+
{editable}
|
|
739
759
|
/>
|
|
740
760
|
<button
|
|
741
761
|
class:sorted={sort_by === i}
|
|
@@ -764,7 +784,7 @@ afterUpdate(() => {
|
|
|
764
784
|
class="cell-menu-button"
|
|
765
785
|
on:click={(event) => toggle_header_menu(event, i)}
|
|
766
786
|
>
|
|
767
|
-
|
|
787
|
+
⋮
|
|
768
788
|
</button>
|
|
769
789
|
{/if}
|
|
770
790
|
</div>
|
|
@@ -780,40 +800,24 @@ afterUpdate(() => {
|
|
|
780
800
|
<td
|
|
781
801
|
tabindex="0"
|
|
782
802
|
on:touchstart={(event) => {
|
|
783
|
-
event.
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
}
|
|
793
|
-
toggle_cell_button(index, j);
|
|
803
|
+
const touch = event.touches[0];
|
|
804
|
+
const mouseEvent = new MouseEvent("click", {
|
|
805
|
+
clientX: touch.clientX,
|
|
806
|
+
clientY: touch.clientY,
|
|
807
|
+
bubbles: true,
|
|
808
|
+
cancelable: true,
|
|
809
|
+
view: window
|
|
810
|
+
});
|
|
811
|
+
handle_cell_click(mouseEvent, index, j);
|
|
794
812
|
}}
|
|
795
813
|
on:mousedown={(event) => {
|
|
796
814
|
event.preventDefault();
|
|
797
815
|
event.stopPropagation();
|
|
798
816
|
}}
|
|
799
|
-
on:click={(event) =>
|
|
800
|
-
event.preventDefault();
|
|
801
|
-
event.stopPropagation();
|
|
802
|
-
clear_on_focus = false;
|
|
803
|
-
active_cell_menu = null;
|
|
804
|
-
active_header_menu = null;
|
|
805
|
-
clicked_cell = { row: index, col: j };
|
|
806
|
-
selected = [index, j];
|
|
807
|
-
selected_header = false;
|
|
808
|
-
header_edit = false;
|
|
809
|
-
if (editable) {
|
|
810
|
-
editing = [index, j];
|
|
811
|
-
}
|
|
812
|
-
toggle_cell_button(index, j);
|
|
813
|
-
}}
|
|
817
|
+
on:click={(event) => handle_cell_click(event, index, j)}
|
|
814
818
|
style:width="var(--cell-width-{j})"
|
|
815
819
|
style={styling?.[index]?.[j] || ""}
|
|
816
|
-
class
|
|
820
|
+
class={is_cell_selected([index, j], selected_cells)}
|
|
817
821
|
class:menu-active={active_cell_menu &&
|
|
818
822
|
active_cell_menu.row === index &&
|
|
819
823
|
active_cell_menu.col === j}
|
|
@@ -832,15 +836,25 @@ afterUpdate(() => {
|
|
|
832
836
|
clear_on_focus = false;
|
|
833
837
|
parent.focus();
|
|
834
838
|
}}
|
|
839
|
+
on:focus={() => {
|
|
840
|
+
const row = index;
|
|
841
|
+
const col = j;
|
|
842
|
+
if (
|
|
843
|
+
!selected_cells.some(([r, c]) => r === row && c === col)
|
|
844
|
+
) {
|
|
845
|
+
selected_cells = [[row, col]];
|
|
846
|
+
}
|
|
847
|
+
}}
|
|
835
848
|
{clear_on_focus}
|
|
836
849
|
{root}
|
|
850
|
+
{max_chars}
|
|
837
851
|
/>
|
|
838
|
-
{#if editable}
|
|
852
|
+
{#if editable && should_show_cell_menu([index, j], selected_cells, editable)}
|
|
839
853
|
<button
|
|
840
854
|
class="cell-menu-button"
|
|
841
855
|
on:click={(event) => toggle_cell_menu(event, index, j)}
|
|
842
856
|
>
|
|
843
|
-
|
|
857
|
+
⋮
|
|
844
858
|
</button>
|
|
845
859
|
{/if}
|
|
846
860
|
</div>
|
|
@@ -852,18 +866,22 @@ afterUpdate(() => {
|
|
|
852
866
|
</div>
|
|
853
867
|
</div>
|
|
854
868
|
|
|
855
|
-
{#if active_cell_menu
|
|
869
|
+
{#if active_cell_menu}
|
|
856
870
|
<CellMenu
|
|
857
|
-
{i18n}
|
|
858
871
|
x={active_cell_menu.x}
|
|
859
872
|
y={active_cell_menu.y}
|
|
860
|
-
row={active_cell_menu
|
|
873
|
+
row={active_cell_menu.row}
|
|
861
874
|
{col_count}
|
|
862
875
|
{row_count}
|
|
863
|
-
on_add_row_above={() => add_row_at(active_cell_menu?.row
|
|
864
|
-
on_add_row_below={() => add_row_at(active_cell_menu?.row
|
|
865
|
-
on_add_column_left={() => add_col_at(active_cell_menu?.col
|
|
866
|
-
on_add_column_right={() => add_col_at(active_cell_menu?.col
|
|
876
|
+
on_add_row_above={() => add_row_at(active_cell_menu?.row || 0, "above")}
|
|
877
|
+
on_add_row_below={() => add_row_at(active_cell_menu?.row || 0, "below")}
|
|
878
|
+
on_add_column_left={() => add_col_at(active_cell_menu?.col || 0, "left")}
|
|
879
|
+
on_add_column_right={() => add_col_at(active_cell_menu?.col || 0, "right")}
|
|
880
|
+
on_delete_row={() => delete_row_at(active_cell_menu?.row || 0)}
|
|
881
|
+
on_delete_col={() => delete_col_at(active_cell_menu?.col || 0)}
|
|
882
|
+
can_delete_rows={data.length > 1}
|
|
883
|
+
can_delete_cols={data[0].length > 1}
|
|
884
|
+
{i18n}
|
|
867
885
|
/>
|
|
868
886
|
{/if}
|
|
869
887
|
|
|
@@ -880,25 +898,18 @@ afterUpdate(() => {
|
|
|
880
898
|
on_add_column_left={() => add_col_at(active_header_menu?.col ?? -1, "left")}
|
|
881
899
|
on_add_column_right={() =>
|
|
882
900
|
add_col_at(active_header_menu?.col ?? -1, "right")}
|
|
901
|
+
on_delete_row={() => delete_row_at(active_cell_menu?.row ?? -1)}
|
|
902
|
+
on_delete_col={() => delete_col_at(active_header_menu?.col ?? -1)}
|
|
903
|
+
can_delete_rows={false}
|
|
904
|
+
can_delete_cols={data[0].length > 1}
|
|
883
905
|
/>
|
|
884
906
|
{/if}
|
|
885
907
|
|
|
886
908
|
<style>
|
|
887
|
-
.
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
.button-wrap svg {
|
|
892
|
-
margin-right: var(--size-1);
|
|
893
|
-
margin-left: -5px;
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
.label p {
|
|
897
|
-
position: relative;
|
|
898
|
-
z-index: var(--layer-4);
|
|
899
|
-
margin-bottom: var(--size-2);
|
|
900
|
-
color: var(--block-label-text-color);
|
|
901
|
-
font-size: var(--block-label-text-size);
|
|
909
|
+
.table-container {
|
|
910
|
+
display: flex;
|
|
911
|
+
flex-direction: column;
|
|
912
|
+
gap: var(--size-2);
|
|
902
913
|
}
|
|
903
914
|
|
|
904
915
|
.table-wrap {
|
|
@@ -911,7 +922,6 @@ afterUpdate(() => {
|
|
|
911
922
|
|
|
912
923
|
.table-wrap:focus-within {
|
|
913
924
|
outline: none;
|
|
914
|
-
background-color: none;
|
|
915
925
|
}
|
|
916
926
|
|
|
917
927
|
.dragging {
|
|
@@ -933,6 +943,7 @@ afterUpdate(() => {
|
|
|
933
943
|
line-height: var(--line-md);
|
|
934
944
|
font-family: var(--font-mono);
|
|
935
945
|
border-spacing: 0;
|
|
946
|
+
border-collapse: separate;
|
|
936
947
|
}
|
|
937
948
|
|
|
938
949
|
div:not(.no-wrap) td {
|
|
@@ -987,6 +998,12 @@ afterUpdate(() => {
|
|
|
987
998
|
th.focus,
|
|
988
999
|
td.focus {
|
|
989
1000
|
--ring-color: var(--color-accent);
|
|
1001
|
+
box-shadow: inset 0 0 0 2px var(--ring-color);
|
|
1002
|
+
z-index: var(--layer-1);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
th.focus {
|
|
1006
|
+
z-index: var(--layer-2);
|
|
990
1007
|
}
|
|
991
1008
|
|
|
992
1009
|
tr:last-child td:first-child {
|
|
@@ -1015,7 +1032,6 @@ afterUpdate(() => {
|
|
|
1015
1032
|
cursor: pointer;
|
|
1016
1033
|
padding: var(--size-2);
|
|
1017
1034
|
color: var(--body-text-color-subdued);
|
|
1018
|
-
line-height: var(--text-sm);
|
|
1019
1035
|
}
|
|
1020
1036
|
|
|
1021
1037
|
.sort-button:hover {
|
|
@@ -1036,11 +1052,11 @@ afterUpdate(() => {
|
|
|
1036
1052
|
|
|
1037
1053
|
.cell-wrap {
|
|
1038
1054
|
display: flex;
|
|
1039
|
-
align-items:
|
|
1055
|
+
align-items: flex-start;
|
|
1040
1056
|
outline: none;
|
|
1041
|
-
height: var(--size-full);
|
|
1042
1057
|
min-height: var(--size-9);
|
|
1043
|
-
|
|
1058
|
+
position: relative;
|
|
1059
|
+
height: auto;
|
|
1044
1060
|
}
|
|
1045
1061
|
|
|
1046
1062
|
.header-content {
|
|
@@ -1049,12 +1065,9 @@ afterUpdate(() => {
|
|
|
1049
1065
|
overflow: hidden;
|
|
1050
1066
|
flex-grow: 1;
|
|
1051
1067
|
min-width: 0;
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
display: flex;
|
|
1056
|
-
justify-content: flex-end;
|
|
1057
|
-
padding-top: var(--size-2);
|
|
1068
|
+
white-space: normal;
|
|
1069
|
+
overflow-wrap: break-word;
|
|
1070
|
+
word-break: break-word;
|
|
1058
1071
|
}
|
|
1059
1072
|
|
|
1060
1073
|
.row_odd {
|
|
@@ -1065,10 +1078,6 @@ afterUpdate(() => {
|
|
|
1065
1078
|
background: var(--background-fill-primary);
|
|
1066
1079
|
}
|
|
1067
1080
|
|
|
1068
|
-
table {
|
|
1069
|
-
border-collapse: separate;
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
1081
|
.cell-menu-button {
|
|
1073
1082
|
flex-shrink: 0;
|
|
1074
1083
|
display: none;
|
|
@@ -1081,28 +1090,35 @@ afterUpdate(() => {
|
|
|
1081
1090
|
padding: 0;
|
|
1082
1091
|
margin-right: var(--spacing-sm);
|
|
1083
1092
|
z-index: var(--layer-1);
|
|
1093
|
+
position: absolute;
|
|
1094
|
+
right: var(--size-1);
|
|
1095
|
+
top: 50%;
|
|
1096
|
+
transform: translateY(-50%);
|
|
1084
1097
|
}
|
|
1085
1098
|
|
|
1086
|
-
.cell-menu-button
|
|
1087
|
-
|
|
1099
|
+
.cell-selected .cell-menu-button {
|
|
1100
|
+
display: flex;
|
|
1101
|
+
align-items: center;
|
|
1102
|
+
justify-content: center;
|
|
1088
1103
|
}
|
|
1089
1104
|
|
|
1090
|
-
|
|
1105
|
+
.header-row {
|
|
1091
1106
|
display: flex;
|
|
1107
|
+
justify-content: space-between;
|
|
1092
1108
|
align-items: center;
|
|
1093
|
-
|
|
1109
|
+
gap: var(--size-2);
|
|
1110
|
+
height: var(--size-6);
|
|
1111
|
+
min-height: var(--size-6);
|
|
1094
1112
|
}
|
|
1095
1113
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
overflow-wrap: break-word;
|
|
1099
|
-
word-break: break-word;
|
|
1114
|
+
.label {
|
|
1115
|
+
flex: 1;
|
|
1100
1116
|
}
|
|
1101
1117
|
|
|
1102
|
-
.
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1118
|
+
.label p {
|
|
1119
|
+
margin: 0;
|
|
1120
|
+
color: var(--block-label-text-color);
|
|
1121
|
+
font-size: var(--block-label-text-size);
|
|
1106
1122
|
}
|
|
1107
1123
|
|
|
1108
1124
|
.row-number,
|
|
@@ -1134,24 +1150,94 @@ afterUpdate(() => {
|
|
|
1134
1150
|
background: var(--table-odd-background-fill);
|
|
1135
1151
|
}
|
|
1136
1152
|
|
|
1137
|
-
.
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
height: var(--size-6);
|
|
1143
|
-
min-height: var(--size-6);
|
|
1153
|
+
.cell-selected {
|
|
1154
|
+
--ring-color: var(--color-accent);
|
|
1155
|
+
box-shadow: inset 0 0 0 2px var(--ring-color);
|
|
1156
|
+
z-index: var(--layer-1);
|
|
1157
|
+
position: relative;
|
|
1144
1158
|
}
|
|
1145
1159
|
|
|
1146
|
-
.
|
|
1147
|
-
|
|
1160
|
+
.cell-selected.no-top {
|
|
1161
|
+
box-shadow:
|
|
1162
|
+
inset 2px 0 0 var(--ring-color),
|
|
1163
|
+
inset -2px 0 0 var(--ring-color),
|
|
1164
|
+
inset 0 -2px 0 var(--ring-color);
|
|
1148
1165
|
}
|
|
1149
1166
|
|
|
1150
|
-
.
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1167
|
+
.cell-selected.no-bottom {
|
|
1168
|
+
box-shadow:
|
|
1169
|
+
inset 2px 0 0 var(--ring-color),
|
|
1170
|
+
inset -2px 0 0 var(--ring-color),
|
|
1171
|
+
inset 0 2px 0 var(--ring-color);
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
.cell-selected.no-left {
|
|
1175
|
+
box-shadow:
|
|
1176
|
+
inset 0 2px 0 var(--ring-color),
|
|
1177
|
+
inset -2px 0 0 var(--ring-color),
|
|
1178
|
+
inset 0 -2px 0 var(--ring-color);
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
.cell-selected.no-right {
|
|
1182
|
+
box-shadow:
|
|
1183
|
+
inset 0 2px 0 var(--ring-color),
|
|
1184
|
+
inset 2px 0 0 var(--ring-color),
|
|
1185
|
+
inset 0 -2px 0 var(--ring-color);
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
.cell-selected.no-top.no-left {
|
|
1189
|
+
box-shadow:
|
|
1190
|
+
inset -2px 0 0 var(--ring-color),
|
|
1191
|
+
inset 0 -2px 0 var(--ring-color);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
.cell-selected.no-top.no-right {
|
|
1195
|
+
box-shadow:
|
|
1196
|
+
inset 2px 0 0 var(--ring-color),
|
|
1197
|
+
inset 0 -2px 0 var(--ring-color);
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
.cell-selected.no-bottom.no-left {
|
|
1201
|
+
box-shadow:
|
|
1202
|
+
inset -2px 0 0 var(--ring-color),
|
|
1203
|
+
inset 0 2px 0 var(--ring-color);
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
.cell-selected.no-bottom.no-right {
|
|
1207
|
+
box-shadow:
|
|
1208
|
+
inset 2px 0 0 var(--ring-color),
|
|
1209
|
+
inset 0 2px 0 var(--ring-color);
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
.cell-selected.no-top.no-bottom {
|
|
1213
|
+
box-shadow:
|
|
1214
|
+
inset 2px 0 0 var(--ring-color),
|
|
1215
|
+
inset -2px 0 0 var(--ring-color);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
.cell-selected.no-left.no-right {
|
|
1219
|
+
box-shadow:
|
|
1220
|
+
inset 0 2px 0 var(--ring-color),
|
|
1221
|
+
inset 0 -2px 0 var(--ring-color);
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
.cell-selected.no-top.no-left.no-right {
|
|
1225
|
+
box-shadow: inset 0 -2px 0 var(--ring-color);
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
.cell-selected.no-bottom.no-left.no-right {
|
|
1229
|
+
box-shadow: inset 0 2px 0 var(--ring-color);
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
.cell-selected.no-left.no-top.no-bottom {
|
|
1233
|
+
box-shadow: inset -2px 0 0 var(--ring-color);
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
.cell-selected.no-right.no-top.no-bottom {
|
|
1237
|
+
box-shadow: inset 2px 0 0 var(--ring-color);
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
.cell-selected.no-top.no-bottom.no-left.no-right {
|
|
1241
|
+
box-shadow: none;
|
|
1156
1242
|
}
|
|
1157
1243
|
</style>
|