@gradio/dataframe 0.17.0 → 0.17.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 +6 -0
- package/Dataframe.stories.svelte +5 -5
- package/dist/shared/CellMenu.svelte +39 -10
- package/dist/shared/CellMenu.svelte.d.ts +1 -0
- package/dist/shared/CellMenuButton.svelte +1 -0
- package/dist/shared/Table.svelte +28 -18
- package/dist/shared/TableHeader.svelte +1 -1
- package/dist/shared/utils/sort_utils.d.ts +13 -0
- package/dist/shared/utils/sort_utils.js +14 -0
- package/package.json +4 -4
- package/shared/CellMenu.svelte +39 -10
- package/shared/CellMenuButton.svelte +1 -0
- package/shared/Table.svelte +43 -19
- package/shared/TableHeader.svelte +1 -1
- package/shared/utils/sort_utils.ts +28 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @gradio/dataframe
|
|
2
2
|
|
|
3
|
+
## 0.17.1
|
|
4
|
+
|
|
5
|
+
### Fixes
|
|
6
|
+
|
|
7
|
+
- [#10819](https://github.com/gradio-app/gradio/pull/10819) [`ac075ad`](https://github.com/gradio-app/gradio/commit/ac075ad6aaea855bfd4839cef7140719a584498e) - Fix cell menu not showing in non-editable dataframes. Thanks @hannahblair!
|
|
8
|
+
|
|
3
9
|
## 0.17.0
|
|
4
10
|
|
|
5
11
|
### Features
|
package/Dataframe.stories.svelte
CHANGED
|
@@ -675,7 +675,7 @@
|
|
|
675
675
|
/>
|
|
676
676
|
|
|
677
677
|
<Story
|
|
678
|
-
name="
|
|
678
|
+
name="Non-interactive dataframe with sorting by multiple columns"
|
|
679
679
|
args={{
|
|
680
680
|
values: [
|
|
681
681
|
[1, 2, 3],
|
|
@@ -685,7 +685,7 @@
|
|
|
685
685
|
headers: ["A", "B", "C"],
|
|
686
686
|
col_count: [3, "dynamic"],
|
|
687
687
|
row_count: [3, "dynamic"],
|
|
688
|
-
editable:
|
|
688
|
+
editable: false,
|
|
689
689
|
sort_columns: [
|
|
690
690
|
{ col: 0, direction: "asc" },
|
|
691
691
|
{ col: 1, direction: "desc" }
|
|
@@ -708,7 +708,7 @@
|
|
|
708
708
|
const cell_menu_button = canvas.getAllByLabelText("Open cell menu")[0];
|
|
709
709
|
await userEvent.click(cell_menu_button);
|
|
710
710
|
|
|
711
|
-
const sort_ascending_button = canvas.getByRole("
|
|
711
|
+
const sort_ascending_button = canvas.getByRole("menuitem", {
|
|
712
712
|
name: "Sort ascending"
|
|
713
713
|
});
|
|
714
714
|
await userEvent.click(sort_ascending_button);
|
|
@@ -719,7 +719,7 @@
|
|
|
719
719
|
const cell_menu_button_2 = canvas.getAllByLabelText("Open cell menu")[1];
|
|
720
720
|
await userEvent.click(cell_menu_button_2);
|
|
721
721
|
|
|
722
|
-
const sort_descending_button = canvas.getByRole("
|
|
722
|
+
const sort_descending_button = canvas.getByRole("menuitem", {
|
|
723
723
|
name: "Sort descending"
|
|
724
724
|
});
|
|
725
725
|
await userEvent.click(sort_descending_button);
|
|
@@ -730,7 +730,7 @@
|
|
|
730
730
|
const cell_menu_button_3 = canvas.getAllByLabelText("Open cell menu")[2];
|
|
731
731
|
await userEvent.click(cell_menu_button_3);
|
|
732
732
|
|
|
733
|
-
const sort_ascending_button_3 = canvas.getByRole("
|
|
733
|
+
const sort_ascending_button_3 = canvas.getByRole("menuitem", {
|
|
734
734
|
name: "Sort ascending"
|
|
735
735
|
});
|
|
736
736
|
await userEvent.click(sort_ascending_button_3);
|
|
@@ -19,14 +19,15 @@ export let on_clear_sort = () => {
|
|
|
19
19
|
};
|
|
20
20
|
export let sort_direction = null;
|
|
21
21
|
export let sort_priority = null;
|
|
22
|
+
export let editable = true;
|
|
22
23
|
export let i18n;
|
|
23
24
|
let menu_element;
|
|
24
25
|
$:
|
|
25
26
|
is_header = row === -1;
|
|
26
27
|
$:
|
|
27
|
-
can_add_rows = row_count[1] === "dynamic";
|
|
28
|
+
can_add_rows = editable && row_count[1] === "dynamic";
|
|
28
29
|
$:
|
|
29
|
-
can_add_columns = col_count[1] === "dynamic";
|
|
30
|
+
can_add_columns = editable && col_count[1] === "dynamic";
|
|
30
31
|
onMount(() => {
|
|
31
32
|
position_menu();
|
|
32
33
|
});
|
|
@@ -49,9 +50,10 @@ function position_menu() {
|
|
|
49
50
|
}
|
|
50
51
|
</script>
|
|
51
52
|
|
|
52
|
-
<div bind:this={menu_element} class="cell-menu">
|
|
53
|
+
<div bind:this={menu_element} class="cell-menu" role="menu">
|
|
53
54
|
{#if is_header}
|
|
54
55
|
<button
|
|
56
|
+
role="menuitem"
|
|
55
57
|
on:click={() => on_sort("asc")}
|
|
56
58
|
class:active={sort_direction === "asc"}
|
|
57
59
|
>
|
|
@@ -62,6 +64,7 @@ function position_menu() {
|
|
|
62
64
|
{/if}
|
|
63
65
|
</button>
|
|
64
66
|
<button
|
|
67
|
+
role="menuitem"
|
|
65
68
|
on:click={() => on_sort("desc")}
|
|
66
69
|
class:active={sort_direction === "desc"}
|
|
67
70
|
>
|
|
@@ -71,39 +74,65 @@ function position_menu() {
|
|
|
71
74
|
<span class="priority">{sort_priority}</span>
|
|
72
75
|
{/if}
|
|
73
76
|
</button>
|
|
74
|
-
<button on:click={on_clear_sort}>
|
|
77
|
+
<button role="menuitem" on:click={on_clear_sort}>
|
|
75
78
|
<CellMenuIcons icon="clear-sort" />
|
|
76
79
|
{i18n("dataframe.clear_sort")}
|
|
77
80
|
</button>
|
|
78
81
|
{/if}
|
|
79
82
|
|
|
80
83
|
{#if !is_header && can_add_rows}
|
|
81
|
-
<button
|
|
84
|
+
<button
|
|
85
|
+
role="menuitem"
|
|
86
|
+
on:click={() => on_add_row_above()}
|
|
87
|
+
aria-label="Add row above"
|
|
88
|
+
>
|
|
82
89
|
<CellMenuIcons icon="add-row-above" />
|
|
83
90
|
{i18n("dataframe.add_row_above")}
|
|
84
91
|
</button>
|
|
85
|
-
<button
|
|
92
|
+
<button
|
|
93
|
+
role="menuitem"
|
|
94
|
+
on:click={() => on_add_row_below()}
|
|
95
|
+
aria-label="Add row below"
|
|
96
|
+
>
|
|
86
97
|
<CellMenuIcons icon="add-row-below" />
|
|
87
98
|
{i18n("dataframe.add_row_below")}
|
|
88
99
|
</button>
|
|
89
100
|
{#if can_delete_rows}
|
|
90
|
-
<button
|
|
101
|
+
<button
|
|
102
|
+
role="menuitem"
|
|
103
|
+
on:click={on_delete_row}
|
|
104
|
+
class="delete"
|
|
105
|
+
aria-label="Delete row"
|
|
106
|
+
>
|
|
91
107
|
<CellMenuIcons icon="delete-row" />
|
|
92
108
|
{i18n("dataframe.delete_row")}
|
|
93
109
|
</button>
|
|
94
110
|
{/if}
|
|
95
111
|
{/if}
|
|
96
112
|
{#if can_add_columns}
|
|
97
|
-
<button
|
|
113
|
+
<button
|
|
114
|
+
role="menuitem"
|
|
115
|
+
on:click={() => on_add_column_left()}
|
|
116
|
+
aria-label="Add column to the left"
|
|
117
|
+
>
|
|
98
118
|
<CellMenuIcons icon="add-column-left" />
|
|
99
119
|
{i18n("dataframe.add_column_left")}
|
|
100
120
|
</button>
|
|
101
|
-
<button
|
|
121
|
+
<button
|
|
122
|
+
role="menuitem"
|
|
123
|
+
on:click={() => on_add_column_right()}
|
|
124
|
+
aria-label="Add column to the right"
|
|
125
|
+
>
|
|
102
126
|
<CellMenuIcons icon="add-column-right" />
|
|
103
127
|
{i18n("dataframe.add_column_right")}
|
|
104
128
|
</button>
|
|
105
129
|
{#if can_delete_cols}
|
|
106
|
-
<button
|
|
130
|
+
<button
|
|
131
|
+
role="menuitem"
|
|
132
|
+
on:click={on_delete_col}
|
|
133
|
+
class="delete"
|
|
134
|
+
aria-label="Delete column"
|
|
135
|
+
>
|
|
107
136
|
<CellMenuIcons icon="delete-column" />
|
|
108
137
|
{i18n("dataframe.delete_column")}
|
|
109
138
|
</button>
|
package/dist/shared/Table.svelte
CHANGED
|
@@ -30,14 +30,14 @@ import {
|
|
|
30
30
|
import {
|
|
31
31
|
copy_table_data,
|
|
32
32
|
get_max,
|
|
33
|
-
handle_file_upload
|
|
34
|
-
sort_table_data
|
|
33
|
+
handle_file_upload
|
|
35
34
|
} from "./utils/table_utils";
|
|
36
35
|
import { make_headers, process_data } from "./utils/data_processing";
|
|
37
36
|
import { handle_keydown } from "./utils/keyboard_utils";
|
|
38
37
|
import {
|
|
39
38
|
create_drag_handlers
|
|
40
39
|
} from "./utils/drag_utils";
|
|
40
|
+
import { sort_data_and_preserve_selection } from "./utils/sort_utils";
|
|
41
41
|
export let datatype;
|
|
42
42
|
export let label = null;
|
|
43
43
|
export let show_label = true;
|
|
@@ -137,8 +137,14 @@ let search_results = [[]];
|
|
|
137
137
|
$:
|
|
138
138
|
if (!dequal(values, old_val)) {
|
|
139
139
|
if (parent) {
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
const is_reset2 = values.length === 0 || values.length === 1 && values[0].length === 0;
|
|
141
|
+
const is_different_structure2 = old_val !== void 0 && (values.length !== old_val.length || values[0] && old_val[0] && values[0].length !== old_val[0].length);
|
|
142
|
+
if (is_reset2 || is_different_structure2) {
|
|
143
|
+
for (let i = 0; i < 50; i++) {
|
|
144
|
+
parent.style.removeProperty(`--cell-width-${i}`);
|
|
145
|
+
}
|
|
146
|
+
last_width_data_length = 0;
|
|
147
|
+
last_width_column_count = 0;
|
|
142
148
|
}
|
|
143
149
|
}
|
|
144
150
|
const is_reset = values.length === 0 || values.length === 1 && values[0].length === 0;
|
|
@@ -297,11 +303,19 @@ function handle_click_outside(event) {
|
|
|
297
303
|
$:
|
|
298
304
|
max = get_max(data);
|
|
299
305
|
$:
|
|
300
|
-
cells[0] && set_cell_widths();
|
|
306
|
+
cells[0] && cells[0]?.clientWidth && set_cell_widths();
|
|
301
307
|
let cells = [];
|
|
302
308
|
let parent;
|
|
303
309
|
let table;
|
|
310
|
+
let last_width_data_length = 0;
|
|
311
|
+
let last_width_column_count = 0;
|
|
304
312
|
function set_cell_widths() {
|
|
313
|
+
const column_count = data[0]?.length || 0;
|
|
314
|
+
if (last_width_data_length === data.length && last_width_column_count === column_count && $df_state.sort_state.sort_columns.length > 0) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
last_width_data_length = data.length;
|
|
318
|
+
last_width_column_count = column_count;
|
|
305
319
|
const widths = cells.map((el) => el?.clientWidth || 0);
|
|
306
320
|
if (widths.length === 0)
|
|
307
321
|
return;
|
|
@@ -332,21 +346,16 @@ function get_cell_width(index) {
|
|
|
332
346
|
let table_height = values.slice(0, max_height / values.length * 37).length * 37 + 37;
|
|
333
347
|
let scrollbar_width = 0;
|
|
334
348
|
function sort_data(_data, _display_value, _styling) {
|
|
335
|
-
|
|
336
|
-
if (selected && selected[0] in _data && selected[1] in _data[selected[0]]) {
|
|
337
|
-
id = _data[selected[0]][selected[1]].id;
|
|
338
|
-
}
|
|
339
|
-
sort_table_data(
|
|
349
|
+
const result = sort_data_and_preserve_selection(
|
|
340
350
|
_data,
|
|
341
351
|
_display_value,
|
|
342
352
|
_styling,
|
|
343
|
-
$df_state.sort_state.sort_columns
|
|
353
|
+
$df_state.sort_state.sort_columns,
|
|
354
|
+
selected,
|
|
355
|
+
get_current_indices
|
|
344
356
|
);
|
|
345
|
-
data = data;
|
|
346
|
-
|
|
347
|
-
const [i, j] = get_current_indices(id, data);
|
|
348
|
-
selected = [i, j];
|
|
349
|
-
}
|
|
357
|
+
data = result.data;
|
|
358
|
+
selected = result.selected;
|
|
350
359
|
}
|
|
351
360
|
$:
|
|
352
361
|
sort_data(data, display_value, styling);
|
|
@@ -856,8 +865,9 @@ $:
|
|
|
856
865
|
on_delete_row={() => delete_row_at(active_cell_menu?.row ?? -1)}
|
|
857
866
|
on_delete_col={() =>
|
|
858
867
|
delete_col_at(active_cell_menu?.col ?? active_header_menu?.col ?? -1)}
|
|
859
|
-
|
|
860
|
-
|
|
868
|
+
{editable}
|
|
869
|
+
can_delete_rows={!active_header_menu && data.length > 1 && editable}
|
|
870
|
+
can_delete_cols={data.length > 0 && data[0]?.length > 1 && editable}
|
|
861
871
|
{i18n}
|
|
862
872
|
on_sort={active_header_menu
|
|
863
873
|
? (direction) => {
|
|
@@ -11,3 +11,16 @@ export declare function sort_data(data: {
|
|
|
11
11
|
col: number;
|
|
12
12
|
direction: SortDirection;
|
|
13
13
|
}[]): number[];
|
|
14
|
+
export declare function sort_data_and_preserve_selection(data: {
|
|
15
|
+
id: string;
|
|
16
|
+
value: string | number;
|
|
17
|
+
}[][], display_value: string[][] | null, styling: string[][] | null, sort_columns: {
|
|
18
|
+
col: number;
|
|
19
|
+
direction: SortDirection;
|
|
20
|
+
}[], selected: [number, number] | false, get_current_indices: (id: string, data: {
|
|
21
|
+
id: string;
|
|
22
|
+
value: string | number;
|
|
23
|
+
}[][]) => [number, number]): {
|
|
24
|
+
data: typeof data;
|
|
25
|
+
selected: [number, number] | false;
|
|
26
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sort_table_data } from "./table_utils";
|
|
1
2
|
export function get_sort_status(name, sort_columns, headers) {
|
|
2
3
|
if (!sort_columns.length)
|
|
3
4
|
return "none";
|
|
@@ -43,3 +44,16 @@ export function sort_data(data, sort_columns) {
|
|
|
43
44
|
}
|
|
44
45
|
return [...Array(data.length)].map((_, i) => i);
|
|
45
46
|
}
|
|
47
|
+
export function sort_data_and_preserve_selection(data, display_value, styling, sort_columns, selected, get_current_indices) {
|
|
48
|
+
let id = null;
|
|
49
|
+
if (selected && selected[0] in data && selected[1] in data[selected[0]]) {
|
|
50
|
+
id = data[selected[0]][selected[1]].id;
|
|
51
|
+
}
|
|
52
|
+
sort_table_data(data, display_value, styling, sort_columns);
|
|
53
|
+
let new_selected = selected;
|
|
54
|
+
if (id) {
|
|
55
|
+
const [i, j] = get_current_indices(id, data);
|
|
56
|
+
new_selected = [i, j];
|
|
57
|
+
}
|
|
58
|
+
return { data, selected: new_selected };
|
|
59
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradio/dataframe",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"description": "Gradio UI packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "",
|
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
"marked": "^12.0.0",
|
|
20
20
|
"@gradio/atoms": "^0.14.0",
|
|
21
21
|
"@gradio/button": "^0.4.10",
|
|
22
|
-
"@gradio/markdown-code": "^0.4.1",
|
|
23
22
|
"@gradio/client": "^1.13.1",
|
|
24
|
-
"@gradio/
|
|
23
|
+
"@gradio/icons": "^0.10.0",
|
|
25
24
|
"@gradio/upload": "^0.15.5",
|
|
25
|
+
"@gradio/statustracker": "^0.10.5",
|
|
26
26
|
"@gradio/utils": "^0.10.1",
|
|
27
|
-
"@gradio/
|
|
27
|
+
"@gradio/markdown-code": "^0.4.1"
|
|
28
28
|
},
|
|
29
29
|
"exports": {
|
|
30
30
|
".": {
|
package/shared/CellMenu.svelte
CHANGED
|
@@ -21,13 +21,14 @@
|
|
|
21
21
|
export let on_clear_sort: () => void = () => {};
|
|
22
22
|
export let sort_direction: SortDirection | null = null;
|
|
23
23
|
export let sort_priority: number | null = null;
|
|
24
|
+
export let editable = true;
|
|
24
25
|
|
|
25
26
|
export let i18n: I18nFormatter;
|
|
26
27
|
let menu_element: HTMLDivElement;
|
|
27
28
|
|
|
28
29
|
$: is_header = row === -1;
|
|
29
|
-
$: can_add_rows = row_count[1] === "dynamic";
|
|
30
|
-
$: can_add_columns = col_count[1] === "dynamic";
|
|
30
|
+
$: can_add_rows = editable && row_count[1] === "dynamic";
|
|
31
|
+
$: can_add_columns = editable && col_count[1] === "dynamic";
|
|
31
32
|
|
|
32
33
|
onMount(() => {
|
|
33
34
|
position_menu();
|
|
@@ -56,9 +57,10 @@
|
|
|
56
57
|
}
|
|
57
58
|
</script>
|
|
58
59
|
|
|
59
|
-
<div bind:this={menu_element} class="cell-menu">
|
|
60
|
+
<div bind:this={menu_element} class="cell-menu" role="menu">
|
|
60
61
|
{#if is_header}
|
|
61
62
|
<button
|
|
63
|
+
role="menuitem"
|
|
62
64
|
on:click={() => on_sort("asc")}
|
|
63
65
|
class:active={sort_direction === "asc"}
|
|
64
66
|
>
|
|
@@ -69,6 +71,7 @@
|
|
|
69
71
|
{/if}
|
|
70
72
|
</button>
|
|
71
73
|
<button
|
|
74
|
+
role="menuitem"
|
|
72
75
|
on:click={() => on_sort("desc")}
|
|
73
76
|
class:active={sort_direction === "desc"}
|
|
74
77
|
>
|
|
@@ -78,39 +81,65 @@
|
|
|
78
81
|
<span class="priority">{sort_priority}</span>
|
|
79
82
|
{/if}
|
|
80
83
|
</button>
|
|
81
|
-
<button on:click={on_clear_sort}>
|
|
84
|
+
<button role="menuitem" on:click={on_clear_sort}>
|
|
82
85
|
<CellMenuIcons icon="clear-sort" />
|
|
83
86
|
{i18n("dataframe.clear_sort")}
|
|
84
87
|
</button>
|
|
85
88
|
{/if}
|
|
86
89
|
|
|
87
90
|
{#if !is_header && can_add_rows}
|
|
88
|
-
<button
|
|
91
|
+
<button
|
|
92
|
+
role="menuitem"
|
|
93
|
+
on:click={() => on_add_row_above()}
|
|
94
|
+
aria-label="Add row above"
|
|
95
|
+
>
|
|
89
96
|
<CellMenuIcons icon="add-row-above" />
|
|
90
97
|
{i18n("dataframe.add_row_above")}
|
|
91
98
|
</button>
|
|
92
|
-
<button
|
|
99
|
+
<button
|
|
100
|
+
role="menuitem"
|
|
101
|
+
on:click={() => on_add_row_below()}
|
|
102
|
+
aria-label="Add row below"
|
|
103
|
+
>
|
|
93
104
|
<CellMenuIcons icon="add-row-below" />
|
|
94
105
|
{i18n("dataframe.add_row_below")}
|
|
95
106
|
</button>
|
|
96
107
|
{#if can_delete_rows}
|
|
97
|
-
<button
|
|
108
|
+
<button
|
|
109
|
+
role="menuitem"
|
|
110
|
+
on:click={on_delete_row}
|
|
111
|
+
class="delete"
|
|
112
|
+
aria-label="Delete row"
|
|
113
|
+
>
|
|
98
114
|
<CellMenuIcons icon="delete-row" />
|
|
99
115
|
{i18n("dataframe.delete_row")}
|
|
100
116
|
</button>
|
|
101
117
|
{/if}
|
|
102
118
|
{/if}
|
|
103
119
|
{#if can_add_columns}
|
|
104
|
-
<button
|
|
120
|
+
<button
|
|
121
|
+
role="menuitem"
|
|
122
|
+
on:click={() => on_add_column_left()}
|
|
123
|
+
aria-label="Add column to the left"
|
|
124
|
+
>
|
|
105
125
|
<CellMenuIcons icon="add-column-left" />
|
|
106
126
|
{i18n("dataframe.add_column_left")}
|
|
107
127
|
</button>
|
|
108
|
-
<button
|
|
128
|
+
<button
|
|
129
|
+
role="menuitem"
|
|
130
|
+
on:click={() => on_add_column_right()}
|
|
131
|
+
aria-label="Add column to the right"
|
|
132
|
+
>
|
|
109
133
|
<CellMenuIcons icon="add-column-right" />
|
|
110
134
|
{i18n("dataframe.add_column_right")}
|
|
111
135
|
</button>
|
|
112
136
|
{#if can_delete_cols}
|
|
113
|
-
<button
|
|
137
|
+
<button
|
|
138
|
+
role="menuitem"
|
|
139
|
+
on:click={on_delete_col}
|
|
140
|
+
class="delete"
|
|
141
|
+
aria-label="Delete column"
|
|
142
|
+
>
|
|
114
143
|
<CellMenuIcons icon="delete-column" />
|
|
115
144
|
{i18n("dataframe.delete_column")}
|
|
116
145
|
</button>
|
package/shared/Table.svelte
CHANGED
|
@@ -38,8 +38,7 @@
|
|
|
38
38
|
import {
|
|
39
39
|
copy_table_data,
|
|
40
40
|
get_max,
|
|
41
|
-
handle_file_upload
|
|
42
|
-
sort_table_data
|
|
41
|
+
handle_file_upload
|
|
43
42
|
} from "./utils/table_utils";
|
|
44
43
|
import { make_headers, process_data } from "./utils/data_processing";
|
|
45
44
|
import { handle_keydown } from "./utils/keyboard_utils";
|
|
@@ -48,6 +47,7 @@
|
|
|
48
47
|
type DragState,
|
|
49
48
|
type DragHandlers
|
|
50
49
|
} from "./utils/drag_utils";
|
|
50
|
+
import { sort_data_and_preserve_selection } from "./utils/sort_utils";
|
|
51
51
|
|
|
52
52
|
export let datatype: Datatype | Datatype[];
|
|
53
53
|
export let label: string | null = null;
|
|
@@ -177,10 +177,23 @@
|
|
|
177
177
|
|
|
178
178
|
$: if (!dequal(values, old_val)) {
|
|
179
179
|
if (parent) {
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
// only clear column widths when the data structure changes
|
|
181
|
+
const is_reset =
|
|
182
|
+
values.length === 0 || (values.length === 1 && values[0].length === 0);
|
|
183
|
+
const is_different_structure =
|
|
184
|
+
old_val !== undefined &&
|
|
185
|
+
(values.length !== old_val.length ||
|
|
186
|
+
(values[0] && old_val[0] && values[0].length !== old_val[0].length));
|
|
187
|
+
|
|
188
|
+
if (is_reset || is_different_structure) {
|
|
189
|
+
for (let i = 0; i < 50; i++) {
|
|
190
|
+
parent.style.removeProperty(`--cell-width-${i}`);
|
|
191
|
+
}
|
|
192
|
+
last_width_data_length = 0;
|
|
193
|
+
last_width_column_count = 0;
|
|
182
194
|
}
|
|
183
195
|
}
|
|
196
|
+
|
|
184
197
|
// only reset sort state when values are changed
|
|
185
198
|
const is_reset =
|
|
186
199
|
values.length === 0 || (values.length === 1 && values[0].length === 0);
|
|
@@ -366,12 +379,28 @@
|
|
|
366
379
|
|
|
367
380
|
$: max = get_max(data);
|
|
368
381
|
|
|
369
|
-
|
|
382
|
+
// Modify how we trigger cell width calculations
|
|
383
|
+
// Only recalculate when cells actually change, not during sort
|
|
384
|
+
$: cells[0] && cells[0]?.clientWidth && set_cell_widths();
|
|
370
385
|
let cells: HTMLTableCellElement[] = [];
|
|
371
386
|
let parent: HTMLDivElement;
|
|
372
387
|
let table: HTMLTableElement;
|
|
388
|
+
let last_width_data_length = 0;
|
|
389
|
+
let last_width_column_count = 0;
|
|
373
390
|
|
|
374
391
|
function set_cell_widths(): void {
|
|
392
|
+
const column_count = data[0]?.length || 0;
|
|
393
|
+
if (
|
|
394
|
+
last_width_data_length === data.length &&
|
|
395
|
+
last_width_column_count === column_count &&
|
|
396
|
+
$df_state.sort_state.sort_columns.length > 0
|
|
397
|
+
) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
last_width_data_length = data.length;
|
|
402
|
+
last_width_column_count = column_count;
|
|
403
|
+
|
|
375
404
|
const widths = cells.map((el) => el?.clientWidth || 0);
|
|
376
405
|
if (widths.length === 0) return;
|
|
377
406
|
|
|
@@ -412,23 +441,17 @@
|
|
|
412
441
|
_display_value: string[][] | null,
|
|
413
442
|
_styling: string[][] | null
|
|
414
443
|
): void {
|
|
415
|
-
|
|
416
|
-
if (selected && selected[0] in _data && selected[1] in _data[selected[0]]) {
|
|
417
|
-
id = _data[selected[0]][selected[1]].id;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
sort_table_data(
|
|
444
|
+
const result = sort_data_and_preserve_selection(
|
|
421
445
|
_data,
|
|
422
446
|
_display_value,
|
|
423
447
|
_styling,
|
|
424
|
-
$df_state.sort_state.sort_columns
|
|
448
|
+
$df_state.sort_state.sort_columns,
|
|
449
|
+
selected,
|
|
450
|
+
get_current_indices
|
|
425
451
|
);
|
|
426
|
-
data = data;
|
|
427
452
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
selected = [i, j];
|
|
431
|
-
}
|
|
453
|
+
data = result.data;
|
|
454
|
+
selected = result.selected;
|
|
432
455
|
}
|
|
433
456
|
|
|
434
457
|
$: sort_data(data, display_value, styling);
|
|
@@ -968,8 +991,9 @@
|
|
|
968
991
|
on_delete_row={() => delete_row_at(active_cell_menu?.row ?? -1)}
|
|
969
992
|
on_delete_col={() =>
|
|
970
993
|
delete_col_at(active_cell_menu?.col ?? active_header_menu?.col ?? -1)}
|
|
971
|
-
|
|
972
|
-
|
|
994
|
+
{editable}
|
|
995
|
+
can_delete_rows={!active_header_menu && data.length > 1 && editable}
|
|
996
|
+
can_delete_cols={data.length > 0 && data[0]?.length > 1 && editable}
|
|
973
997
|
{i18n}
|
|
974
998
|
on_sort={active_header_menu
|
|
975
999
|
? (direction) => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Headers } from "../types";
|
|
2
|
+
import { sort_table_data } from "./table_utils";
|
|
2
3
|
|
|
3
4
|
export type SortDirection = "asc" | "desc";
|
|
4
5
|
|
|
@@ -61,3 +62,30 @@ export function sort_data(
|
|
|
61
62
|
}
|
|
62
63
|
return [...Array(data.length)].map((_, i) => i);
|
|
63
64
|
}
|
|
65
|
+
|
|
66
|
+
export function sort_data_and_preserve_selection(
|
|
67
|
+
data: { id: string; value: string | number }[][],
|
|
68
|
+
display_value: string[][] | null,
|
|
69
|
+
styling: string[][] | null,
|
|
70
|
+
sort_columns: { col: number; direction: SortDirection }[],
|
|
71
|
+
selected: [number, number] | false,
|
|
72
|
+
get_current_indices: (
|
|
73
|
+
id: string,
|
|
74
|
+
data: { id: string; value: string | number }[][]
|
|
75
|
+
) => [number, number]
|
|
76
|
+
): { data: typeof data; selected: [number, number] | false } {
|
|
77
|
+
let id = null;
|
|
78
|
+
if (selected && selected[0] in data && selected[1] in data[selected[0]]) {
|
|
79
|
+
id = data[selected[0]][selected[1]].id;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
sort_table_data(data, display_value, styling, sort_columns);
|
|
83
|
+
|
|
84
|
+
let new_selected = selected;
|
|
85
|
+
if (id) {
|
|
86
|
+
const [i, j] = get_current_indices(id, data);
|
|
87
|
+
new_selected = [i, j];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return { data, selected: new_selected };
|
|
91
|
+
}
|