@gradio/dataframe 0.19.2 → 0.19.4
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 +29 -0
- package/Index.svelte +3 -1
- package/dist/Index.svelte +1 -0
- package/dist/Index.svelte.d.ts +6 -3
- package/dist/shared/BooleanCell.svelte +1 -2
- package/dist/shared/BooleanCell.svelte.d.ts +1 -1
- package/dist/shared/EditableCell.svelte +7 -18
- package/dist/shared/EditableCell.svelte.d.ts +2 -1
- package/dist/shared/Table.svelte +23 -13
- package/dist/shared/Table.svelte.d.ts +4 -2
- package/dist/shared/TableCell.svelte.d.ts +2 -1
- package/dist/shared/TableHeader.svelte +57 -0
- package/dist/shared/TableHeader.svelte.d.ts +7 -0
- package/dist/shared/context/dataframe_context.d.ts +9 -8
- package/dist/shared/context/dataframe_context.js +9 -1
- package/dist/shared/types.d.ts +2 -1
- package/dist/shared/utils/data_processing.d.ts +5 -4
- package/dist/shared/utils/data_processing.js +4 -2
- package/dist/shared/utils/filter_utils.d.ts +5 -4
- package/dist/shared/utils/keyboard_utils.js +1 -1
- package/dist/shared/utils/selection_utils.d.ts +3 -3
- package/dist/shared/utils/sort_utils.d.ts +4 -4
- package/dist/shared/utils/table_utils.d.ts +2 -2
- package/dist/shared/utils/utils.d.ts +8 -2
- package/package.json +8 -8
- package/shared/BooleanCell.svelte +2 -5
- package/shared/EditableCell.svelte +12 -20
- package/shared/Table.svelte +43 -27
- package/shared/TableCell.svelte +2 -1
- package/shared/TableHeader.svelte +62 -0
- package/shared/context/dataframe_context.ts +20 -13
- package/shared/types.ts +3 -1
- package/shared/utils/data_processing.ts +10 -5
- package/shared/utils/filter_utils.ts +5 -4
- package/shared/utils/keyboard_utils.ts +1 -6
- package/shared/utils/selection_utils.ts +3 -3
- package/shared/utils/sort_utils.ts +4 -4
- package/shared/utils/table_utils.ts +8 -2
- package/shared/utils/utils.ts +10 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Headers, HeadersWithIDs, TableCell, TableData } from "../types";
|
|
1
|
+
import type { CellValue, Headers, HeadersWithIDs, TableCell, TableData } from "../types";
|
|
2
2
|
import type { SortDirection } from "./sort_utils";
|
|
3
3
|
import type { FilterDatatype } from "./filter_utils";
|
|
4
4
|
export declare function make_cell_id(row: number, col: number): string;
|
|
@@ -17,4 +17,4 @@ export declare function filter_table_data(data: TableData, display_value: string
|
|
|
17
17
|
export declare function copy_table_data(data: TableData, selected_cells: [number, number][] | null): Promise<void>;
|
|
18
18
|
export declare function guess_delimiter(text: string, possibleDelimiters: string[]): string[];
|
|
19
19
|
export declare function data_uri_to_blob(data_uri: string): Blob;
|
|
20
|
-
export declare function handle_file_upload(data_uri: string, update_headers: (headers: Headers) => HeadersWithIDs[], update_values: (values:
|
|
20
|
+
export declare function handle_file_upload(data_uri: string, update_headers: (headers: Headers) => HeadersWithIDs[], update_values: (values: CellValue[][]) => void): void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { CellValue } from "../types";
|
|
1
2
|
export type Headers = string[];
|
|
2
|
-
export type Data =
|
|
3
|
+
export type Data = CellValue[][];
|
|
3
4
|
export type Datatype = "str" | "number" | "bool" | "date" | "markdown" | "html" | "image";
|
|
4
5
|
export type Metadata = {
|
|
5
6
|
[key: string]: string[][] | null;
|
|
@@ -19,4 +20,9 @@ export type DataframeValue = {
|
|
|
19
20
|
* @param t - The type to coerce to.
|
|
20
21
|
* @returns The coerced value.
|
|
21
22
|
*/
|
|
22
|
-
export declare function cast_value_to_type(v: any, t: Datatype):
|
|
23
|
+
export declare function cast_value_to_type(v: any, t: Datatype): CellValue;
|
|
24
|
+
export interface EditData {
|
|
25
|
+
index: number | [number, number];
|
|
26
|
+
value: string;
|
|
27
|
+
previous_value: string;
|
|
28
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradio/dataframe",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.4",
|
|
4
4
|
"description": "Gradio UI packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "",
|
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
"@types/katex": "^0.16.0",
|
|
14
14
|
"d3-dsv": "^3.0.1",
|
|
15
15
|
"dequal": "^2.0.2",
|
|
16
|
-
"@gradio/
|
|
17
|
-
"@gradio/checkbox": "^0.4.
|
|
18
|
-
"@gradio/
|
|
16
|
+
"@gradio/atoms": "^0.18.0",
|
|
17
|
+
"@gradio/checkbox": "^0.4.30",
|
|
18
|
+
"@gradio/button": "^0.5.13",
|
|
19
19
|
"@gradio/icons": "^0.14.0",
|
|
20
|
-
"@gradio/
|
|
21
|
-
"@gradio/
|
|
22
|
-
"@gradio/
|
|
23
|
-
"@gradio/
|
|
20
|
+
"@gradio/statustracker": "^0.11.1",
|
|
21
|
+
"@gradio/markdown-code": "^0.5.2",
|
|
22
|
+
"@gradio/client": "^1.19.0",
|
|
23
|
+
"@gradio/upload": "^0.17.0",
|
|
24
24
|
"@gradio/utils": "^0.10.2"
|
|
25
25
|
},
|
|
26
26
|
"exports": {
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { BaseCheckbox } from "@gradio/checkbox";
|
|
3
3
|
|
|
4
|
-
export let value
|
|
4
|
+
export let value = false;
|
|
5
5
|
export let editable = true;
|
|
6
6
|
export let on_change: (value: boolean) => void;
|
|
7
7
|
|
|
8
|
-
$: bool_value =
|
|
9
|
-
typeof value === "string" ? value.toLowerCase() === "true" : !!value;
|
|
10
|
-
|
|
11
8
|
function handle_change(event: CustomEvent<boolean>): void {
|
|
12
9
|
if (editable) {
|
|
13
10
|
on_change(event.detail);
|
|
@@ -17,7 +14,7 @@
|
|
|
17
14
|
|
|
18
15
|
<div class="bool-cell" role="button" tabindex="-1">
|
|
19
16
|
<BaseCheckbox
|
|
20
|
-
bind:value
|
|
17
|
+
bind:value
|
|
21
18
|
label=""
|
|
22
19
|
interactive={editable}
|
|
23
20
|
on:change={handle_change}
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
import { createEventDispatcher } from "svelte";
|
|
3
3
|
import { MarkdownCode } from "@gradio/markdown-code";
|
|
4
4
|
import type { I18nFormatter } from "@gradio/utils";
|
|
5
|
+
import type { CellValue } from "./types";
|
|
5
6
|
import SelectionButtons from "./icons/SelectionButtons.svelte";
|
|
6
7
|
import BooleanCell from "./BooleanCell.svelte";
|
|
7
8
|
|
|
8
9
|
export let edit: boolean;
|
|
9
|
-
export let value:
|
|
10
|
+
export let value: CellValue = "";
|
|
10
11
|
export let display_value: string | null = null;
|
|
11
12
|
export let styling = "";
|
|
12
13
|
export let header = false;
|
|
@@ -44,7 +45,7 @@
|
|
|
44
45
|
}>();
|
|
45
46
|
|
|
46
47
|
function truncate_text(
|
|
47
|
-
text:
|
|
48
|
+
text: CellValue,
|
|
48
49
|
max_length: number | null = null,
|
|
49
50
|
is_image = false
|
|
50
51
|
): string {
|
|
@@ -86,18 +87,13 @@
|
|
|
86
87
|
dispatch("keydown", event);
|
|
87
88
|
}
|
|
88
89
|
|
|
89
|
-
function
|
|
90
|
-
value
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
value: new_value.toString()
|
|
97
|
-
}
|
|
98
|
-
} as unknown as FocusEvent,
|
|
99
|
-
coords: coords
|
|
100
|
-
});
|
|
90
|
+
function commit_change(checked: boolean): void {
|
|
91
|
+
handle_blur({ target: { value } } as unknown as FocusEvent);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
$: if (!edit) {
|
|
95
|
+
// Shim blur on removal for Safari and Firefox
|
|
96
|
+
handle_blur({ target: { value } } as unknown as FocusEvent);
|
|
101
97
|
}
|
|
102
98
|
</script>
|
|
103
99
|
|
|
@@ -118,12 +114,8 @@
|
|
|
118
114
|
/>
|
|
119
115
|
{/if}
|
|
120
116
|
|
|
121
|
-
{#if datatype === "bool"}
|
|
122
|
-
<BooleanCell
|
|
123
|
-
value={String(display_content)}
|
|
124
|
-
{editable}
|
|
125
|
-
on_change={handle_bool_change}
|
|
126
|
-
/>
|
|
117
|
+
{#if datatype === "bool" && typeof value === "boolean"}
|
|
118
|
+
<BooleanCell bind:value {editable} on_change={commit_change} />
|
|
127
119
|
{:else}
|
|
128
120
|
<span
|
|
129
121
|
class:dragging={is_dragging}
|
package/shared/Table.svelte
CHANGED
|
@@ -20,10 +20,15 @@
|
|
|
20
20
|
import type { I18nFormatter } from "js/core/src/gradio_helper";
|
|
21
21
|
import { type Client } from "@gradio/client";
|
|
22
22
|
import VirtualTable from "./VirtualTable.svelte";
|
|
23
|
-
import type {
|
|
23
|
+
import type {
|
|
24
|
+
Headers,
|
|
25
|
+
DataframeValue,
|
|
26
|
+
Datatype,
|
|
27
|
+
EditData
|
|
28
|
+
} from "./utils/utils";
|
|
24
29
|
import CellMenu from "./CellMenu.svelte";
|
|
25
30
|
import Toolbar from "./Toolbar.svelte";
|
|
26
|
-
import type { CellCoordinate } from "./types";
|
|
31
|
+
import type { CellCoordinate, CellValue } from "./types";
|
|
27
32
|
import {
|
|
28
33
|
is_cell_selected,
|
|
29
34
|
should_show_cell_menu,
|
|
@@ -37,7 +42,6 @@
|
|
|
37
42
|
handle_file_upload
|
|
38
43
|
} from "./utils/table_utils";
|
|
39
44
|
import { make_headers, process_data } from "./utils/data_processing";
|
|
40
|
-
import { cast_value_to_type } from "./utils/utils";
|
|
41
45
|
import { handle_keydown, handle_cell_blur } from "./utils/keyboard_utils";
|
|
42
46
|
import {
|
|
43
47
|
create_drag_handlers,
|
|
@@ -51,7 +55,7 @@
|
|
|
51
55
|
export let label: string | null = null;
|
|
52
56
|
export let show_label = true;
|
|
53
57
|
export let headers: Headers = [];
|
|
54
|
-
export let values:
|
|
58
|
+
export let values: CellValue[][] = [];
|
|
55
59
|
export let col_count: [number, "fixed" | "dynamic"];
|
|
56
60
|
export let row_count: [number, "fixed" | "dynamic"];
|
|
57
61
|
export let latex_delimiters: {
|
|
@@ -163,6 +167,7 @@
|
|
|
163
167
|
input: undefined;
|
|
164
168
|
select: SelectData;
|
|
165
169
|
search: string | null;
|
|
170
|
+
edit: EditData;
|
|
166
171
|
}>();
|
|
167
172
|
|
|
168
173
|
let els: Record<
|
|
@@ -172,12 +177,11 @@
|
|
|
172
177
|
let data_binding: Record<string, (typeof data)[0][0]> = {};
|
|
173
178
|
let _headers = make_headers(headers, col_count, els, make_id);
|
|
174
179
|
let old_headers: string[] = headers;
|
|
175
|
-
let data: { id: string; value:
|
|
176
|
-
|
|
177
|
-
let old_val: undefined | (string | number)[][] = undefined;
|
|
180
|
+
let data: { id: string; value: CellValue; display_value?: string }[][] = [[]];
|
|
181
|
+
let old_val: undefined | CellValue[][] = undefined;
|
|
178
182
|
let search_results: {
|
|
179
183
|
id: string;
|
|
180
|
-
value:
|
|
184
|
+
value: CellValue;
|
|
181
185
|
display_value?: string;
|
|
182
186
|
styling?: string;
|
|
183
187
|
}[][] = [[]];
|
|
@@ -196,13 +200,13 @@
|
|
|
196
200
|
);
|
|
197
201
|
});
|
|
198
202
|
|
|
199
|
-
const get_data_at = (row: number, col: number):
|
|
203
|
+
const get_data_at = (row: number, col: number): CellValue =>
|
|
200
204
|
data?.[row]?.[col]?.value;
|
|
201
205
|
|
|
202
|
-
const get_column = (col: number):
|
|
206
|
+
const get_column = (col: number): CellValue[] =>
|
|
203
207
|
data?.map((row) => row[col]?.value) ?? [];
|
|
204
208
|
|
|
205
|
-
const get_row = (row: number):
|
|
209
|
+
const get_row = (row: number): CellValue[] =>
|
|
206
210
|
data?.[row]?.map((cell) => cell.value) ?? [];
|
|
207
211
|
|
|
208
212
|
$: {
|
|
@@ -248,13 +252,14 @@
|
|
|
248
252
|
(values[0] && old_val[0] && values[0].length !== old_val[0].length));
|
|
249
253
|
|
|
250
254
|
data = process_data(
|
|
251
|
-
values as
|
|
255
|
+
values as CellValue[][],
|
|
252
256
|
els,
|
|
253
257
|
data_binding,
|
|
254
258
|
make_id,
|
|
255
|
-
display_value
|
|
259
|
+
display_value,
|
|
260
|
+
datatype
|
|
256
261
|
);
|
|
257
|
-
old_val = JSON.parse(JSON.stringify(values)) as
|
|
262
|
+
old_val = JSON.parse(JSON.stringify(values)) as CellValue[][];
|
|
258
263
|
|
|
259
264
|
if (is_reset || is_different_structure) {
|
|
260
265
|
df_actions.reset_sort_state();
|
|
@@ -326,27 +331,19 @@
|
|
|
326
331
|
}
|
|
327
332
|
|
|
328
333
|
let previous_headers = _headers.map((h) => h.value);
|
|
329
|
-
let previous_data = data.map((row) => row.map((cell) =>
|
|
334
|
+
let previous_data = data.map((row) => row.map((cell) => cell.value));
|
|
330
335
|
|
|
331
336
|
$: {
|
|
332
337
|
if (data || _headers) {
|
|
333
338
|
df_actions.trigger_change(
|
|
334
|
-
data
|
|
335
|
-
row.map((cell, colIdx) => {
|
|
336
|
-
const dtype = Array.isArray(datatype) ? datatype[colIdx] : datatype;
|
|
337
|
-
return {
|
|
338
|
-
...cell,
|
|
339
|
-
value: cast_value_to_type(cell.value, dtype)
|
|
340
|
-
};
|
|
341
|
-
})
|
|
342
|
-
),
|
|
339
|
+
data,
|
|
343
340
|
_headers,
|
|
344
341
|
previous_data,
|
|
345
342
|
previous_headers,
|
|
346
343
|
value_is_output,
|
|
347
344
|
dispatch
|
|
348
345
|
);
|
|
349
|
-
previous_data = data.map((row) => row.map((cell) =>
|
|
346
|
+
previous_data = data.map((row) => row.map((cell) => cell.value));
|
|
350
347
|
previous_headers = _headers.map((h) => h.value);
|
|
351
348
|
}
|
|
352
349
|
}
|
|
@@ -675,12 +672,12 @@
|
|
|
675
672
|
|
|
676
673
|
function commit_filter(): void {
|
|
677
674
|
if ($df_state.current_search_query && show_search === "filter") {
|
|
678
|
-
const filtered_data:
|
|
675
|
+
const filtered_data: CellValue[][] = [];
|
|
679
676
|
const filtered_display_values: string[][] = [];
|
|
680
677
|
const filtered_styling: string[][] = [];
|
|
681
678
|
|
|
682
679
|
search_results.forEach((row) => {
|
|
683
|
-
const data_row:
|
|
680
|
+
const data_row: CellValue[] = [];
|
|
684
681
|
const display_row: string[] = [];
|
|
685
682
|
const styling_row: string[] = [];
|
|
686
683
|
|
|
@@ -755,6 +752,19 @@
|
|
|
755
752
|
df_actions.reset_sort_state();
|
|
756
753
|
}
|
|
757
754
|
|
|
755
|
+
function handle_select_all(col: number, checked: boolean): void {
|
|
756
|
+
data = data.map((row) => {
|
|
757
|
+
const new_row = [...row];
|
|
758
|
+
if (new_row[col]) {
|
|
759
|
+
new_row[col] = {
|
|
760
|
+
...new_row[col],
|
|
761
|
+
value: checked.toString()
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
return new_row;
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
|
|
758
768
|
let is_dragging = false;
|
|
759
769
|
let drag_start: [number, number] | null = null;
|
|
760
770
|
let mouse_down_pos: { x: number; y: number } | null = null;
|
|
@@ -877,6 +887,9 @@
|
|
|
877
887
|
{i18n}
|
|
878
888
|
bind:el={els[id].input}
|
|
879
889
|
{col_count}
|
|
890
|
+
datatype={Array.isArray(datatype) ? datatype[i] : datatype}
|
|
891
|
+
{data}
|
|
892
|
+
on_select_all={handle_select_all}
|
|
880
893
|
/>
|
|
881
894
|
{/each}
|
|
882
895
|
</tr>
|
|
@@ -980,6 +993,9 @@
|
|
|
980
993
|
{i18n}
|
|
981
994
|
bind:el={els[id].input}
|
|
982
995
|
{col_count}
|
|
996
|
+
datatype={Array.isArray(datatype) ? datatype[i] : datatype}
|
|
997
|
+
{data}
|
|
998
|
+
on_select_all={handle_select_all}
|
|
983
999
|
/>
|
|
984
1000
|
{/each}
|
|
985
1001
|
</tr>
|
package/shared/TableCell.svelte
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
import CellMenuButton from "./CellMenuButton.svelte";
|
|
4
4
|
import type { I18nFormatter } from "js/core/src/gradio_helper";
|
|
5
5
|
import type { Datatype } from "./utils/utils";
|
|
6
|
+
import type { CellValue } from "./types";
|
|
6
7
|
import { is_cell_in_selection } from "./utils/selection_utils";
|
|
7
8
|
|
|
8
|
-
export let value:
|
|
9
|
+
export let value: CellValue;
|
|
9
10
|
export let index: number;
|
|
10
11
|
export let j: number;
|
|
11
12
|
export let actual_pinned_columns: number;
|
|
@@ -9,8 +9,11 @@
|
|
|
9
9
|
import type { SortDirection } from "./context/dataframe_context";
|
|
10
10
|
import CellMenuIcons from "./CellMenuIcons.svelte";
|
|
11
11
|
import type { FilterDatatype } from "./context/dataframe_context";
|
|
12
|
+
import type { Datatype } from "./utils/utils";
|
|
13
|
+
import { BaseCheckbox } from "@gradio/checkbox";
|
|
12
14
|
export let value: string;
|
|
13
15
|
export let i: number;
|
|
16
|
+
export let datatype: Datatype = "str";
|
|
14
17
|
export let actual_pinned_columns: number;
|
|
15
18
|
export let header_edit: number | false;
|
|
16
19
|
export let selected_header: number | false;
|
|
@@ -39,8 +42,24 @@
|
|
|
39
42
|
export let el: HTMLTextAreaElement | null;
|
|
40
43
|
export let is_static: boolean;
|
|
41
44
|
export let col_count: [number, "fixed" | "dynamic"];
|
|
45
|
+
export let data: any[] = [];
|
|
46
|
+
export let on_select_all:
|
|
47
|
+
| ((col: number, checked: boolean) => void)
|
|
48
|
+
| undefined = undefined;
|
|
42
49
|
|
|
43
50
|
$: can_add_columns = col_count && col_count[1] === "dynamic";
|
|
51
|
+
$: is_bool_column = datatype === "bool";
|
|
52
|
+
|
|
53
|
+
$: select_all_state = (() => {
|
|
54
|
+
if (!is_bool_column || data.length === 0) return "unchecked";
|
|
55
|
+
const true_count = data.filter(
|
|
56
|
+
(row) => row[i]?.value === true || row[i]?.value === "true"
|
|
57
|
+
).length;
|
|
58
|
+
if (true_count === 0) return "unchecked";
|
|
59
|
+
if (true_count === data.length) return "checked";
|
|
60
|
+
return "indeterminate";
|
|
61
|
+
})();
|
|
62
|
+
|
|
44
63
|
$: sort_index = sort_columns.findIndex((item) => item.col === i);
|
|
45
64
|
$: filter_index = filter_columns.findIndex((item) => item.col === i);
|
|
46
65
|
$: sort_priority = sort_index !== -1 ? sort_index + 1 : null;
|
|
@@ -88,6 +107,33 @@
|
|
|
88
107
|
>
|
|
89
108
|
<div class="cell-wrap">
|
|
90
109
|
<div class="header-content">
|
|
110
|
+
{#if is_bool_column && editable && on_select_all}
|
|
111
|
+
<div
|
|
112
|
+
class="select-all-checkbox"
|
|
113
|
+
role="button"
|
|
114
|
+
tabindex="0"
|
|
115
|
+
on:click|stopPropagation
|
|
116
|
+
on:keydown|stopPropagation={(e) => {
|
|
117
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
118
|
+
e.preventDefault();
|
|
119
|
+
}
|
|
120
|
+
}}
|
|
121
|
+
on:mousedown|stopPropagation
|
|
122
|
+
>
|
|
123
|
+
<BaseCheckbox
|
|
124
|
+
value={select_all_state === "checked"}
|
|
125
|
+
indeterminate={select_all_state === "indeterminate"}
|
|
126
|
+
label=""
|
|
127
|
+
interactive={true}
|
|
128
|
+
on:select={() => {
|
|
129
|
+
if (on_select_all) {
|
|
130
|
+
const new_value = select_all_state !== "checked";
|
|
131
|
+
on_select_all(i, new_value);
|
|
132
|
+
}
|
|
133
|
+
}}
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
136
|
+
{/if}
|
|
91
137
|
<button
|
|
92
138
|
class="header-button"
|
|
93
139
|
on:click={(event) => handle_header_click(event, i)}
|
|
@@ -279,4 +325,20 @@
|
|
|
279
325
|
z-index: 5;
|
|
280
326
|
border-right: none;
|
|
281
327
|
}
|
|
328
|
+
|
|
329
|
+
.select-all-checkbox {
|
|
330
|
+
display: flex;
|
|
331
|
+
align-items: center;
|
|
332
|
+
justify-content: center;
|
|
333
|
+
margin-right: var(--size-1);
|
|
334
|
+
flex-shrink: 0;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.select-all-checkbox :global(label) {
|
|
338
|
+
margin: 0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.select-all-checkbox :global(span) {
|
|
342
|
+
display: none;
|
|
343
|
+
}
|
|
282
344
|
</style>
|
|
@@ -2,6 +2,7 @@ import { getContext, setContext } from "svelte";
|
|
|
2
2
|
import { dequal } from "dequal";
|
|
3
3
|
import { writable, get } from "svelte/store";
|
|
4
4
|
import { sort_table_data } from "../utils/table_utils";
|
|
5
|
+
import type { CellValue } from "../types";
|
|
5
6
|
import { tick } from "svelte";
|
|
6
7
|
import {
|
|
7
8
|
handle_selection,
|
|
@@ -30,14 +31,14 @@ interface DataFrameState {
|
|
|
30
31
|
max_height: number;
|
|
31
32
|
column_widths: string[];
|
|
32
33
|
max_chars?: number;
|
|
33
|
-
static_columns?:
|
|
34
|
+
static_columns?: CellValue[];
|
|
34
35
|
};
|
|
35
36
|
current_search_query: string | null;
|
|
36
37
|
sort_state: {
|
|
37
38
|
sort_columns: { col: number; direction: SortDirection }[];
|
|
38
39
|
row_order: number[];
|
|
39
40
|
initial_data: {
|
|
40
|
-
data: { id: string; value:
|
|
41
|
+
data: { id: string; value: CellValue }[][];
|
|
41
42
|
display_value: string[][] | null;
|
|
42
43
|
styling: string[][] | null;
|
|
43
44
|
} | null;
|
|
@@ -50,7 +51,7 @@ interface DataFrameState {
|
|
|
50
51
|
value: string;
|
|
51
52
|
}[];
|
|
52
53
|
initial_data: {
|
|
53
|
-
data: { id: string; value:
|
|
54
|
+
data: { id: string; value: CellValue }[][];
|
|
54
55
|
display_value: string[][] | null;
|
|
55
56
|
styling: string[][] | null;
|
|
56
57
|
} | null;
|
|
@@ -124,10 +125,10 @@ interface DataFrameActions {
|
|
|
124
125
|
trigger_change: (
|
|
125
126
|
data: any[][],
|
|
126
127
|
headers: any[],
|
|
127
|
-
previous_data:
|
|
128
|
+
previous_data: any[][],
|
|
128
129
|
previous_headers: string[],
|
|
129
130
|
value_is_output: boolean,
|
|
130
|
-
dispatch: (e: "change" | "input", detail?: any) => void
|
|
131
|
+
dispatch: (e: "change" | "input" | "edit", detail?: any) => void
|
|
131
132
|
) => Promise<void>;
|
|
132
133
|
reset_sort_state: () => void;
|
|
133
134
|
reset_filter_state: () => void;
|
|
@@ -183,10 +184,10 @@ export interface DataFrameContext {
|
|
|
183
184
|
{ cell: HTMLTableCellElement | null; input: HTMLTextAreaElement | null }
|
|
184
185
|
>;
|
|
185
186
|
parent_element?: HTMLElement;
|
|
186
|
-
get_data_at?: (row: number, col: number) =>
|
|
187
|
-
get_column?: (col: number) =>
|
|
188
|
-
get_row?: (row: number) =>
|
|
189
|
-
dispatch?: (e: "change" | "select" | "search", detail?: any) => void;
|
|
187
|
+
get_data_at?: (row: number, col: number) => CellValue;
|
|
188
|
+
get_column?: (col: number) => CellValue[];
|
|
189
|
+
get_row?: (row: number) => CellValue[];
|
|
190
|
+
dispatch?: (e: "change" | "select" | "search" | "edit", detail?: any) => void;
|
|
190
191
|
}
|
|
191
192
|
|
|
192
193
|
function create_actions(
|
|
@@ -230,7 +231,7 @@ function create_actions(
|
|
|
230
231
|
};
|
|
231
232
|
|
|
232
233
|
const update_array = (
|
|
233
|
-
source: { id: string; value:
|
|
234
|
+
source: { id: string; value: CellValue }[][] | string[][] | null,
|
|
234
235
|
target: any[] | null | undefined
|
|
235
236
|
): void => {
|
|
236
237
|
if (source && target) {
|
|
@@ -397,9 +398,7 @@ function create_actions(
|
|
|
397
398
|
if (s.current_search_query) return;
|
|
398
399
|
|
|
399
400
|
const current_headers = headers.map((h) => h.value);
|
|
400
|
-
const current_data = data.map((row) =>
|
|
401
|
-
row.map((cell) => String(cell.value))
|
|
402
|
-
);
|
|
401
|
+
const current_data = data.map((row) => row.map((cell) => cell.value));
|
|
403
402
|
|
|
404
403
|
if (
|
|
405
404
|
!dequal(current_data, previous_data) ||
|
|
@@ -416,6 +415,14 @@ function create_actions(
|
|
|
416
415
|
headers: current_headers,
|
|
417
416
|
metadata: null
|
|
418
417
|
});
|
|
418
|
+
const index = s.ui_state.selected;
|
|
419
|
+
if (index) {
|
|
420
|
+
dispatch("edit", {
|
|
421
|
+
index,
|
|
422
|
+
value: data[index[0]][index[1]].value,
|
|
423
|
+
previous_value: previous_data[index[0]][index[1]]
|
|
424
|
+
});
|
|
425
|
+
}
|
|
419
426
|
if (!value_is_output) dispatch("input");
|
|
420
427
|
}
|
|
421
428
|
},
|
package/shared/types.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type { Headers, HeadersWithIDs } from "./utils";
|
|
1
|
+
import type { Datatype, Headers, HeadersWithIDs } from "./utils";
|
|
2
|
+
import type { CellValue } from "../types";
|
|
3
|
+
import { cast_value_to_type } from "./utils";
|
|
2
4
|
|
|
3
5
|
export function make_headers(
|
|
4
6
|
_head: Headers,
|
|
@@ -35,15 +37,16 @@ export function make_headers(
|
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
export function process_data(
|
|
38
|
-
values:
|
|
40
|
+
values: CellValue[][],
|
|
39
41
|
els: Record<
|
|
40
42
|
string,
|
|
41
43
|
{ cell: null | HTMLTableCellElement; input: null | HTMLTextAreaElement }
|
|
42
44
|
>,
|
|
43
45
|
data_binding: Record<string, any>,
|
|
44
46
|
make_id: () => string,
|
|
45
|
-
display_value: string[][] | null = null
|
|
46
|
-
|
|
47
|
+
display_value: string[][] | null = null,
|
|
48
|
+
datatype: Datatype | Datatype[]
|
|
49
|
+
): { id: string; value: CellValue; display_value?: string }[][] {
|
|
47
50
|
if (!values || values.length === 0) {
|
|
48
51
|
return [];
|
|
49
52
|
}
|
|
@@ -60,9 +63,11 @@ export function process_data(
|
|
|
60
63
|
display = String(value);
|
|
61
64
|
}
|
|
62
65
|
|
|
66
|
+
const dtype = Array.isArray(datatype) ? datatype[j] : datatype;
|
|
67
|
+
|
|
63
68
|
return {
|
|
64
69
|
id: _id,
|
|
65
|
-
value,
|
|
70
|
+
value: cast_value_to_type(value, dtype),
|
|
66
71
|
display_value: display
|
|
67
72
|
};
|
|
68
73
|
});
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { filter_table_data } from "./table_utils";
|
|
2
|
+
import type { CellValue } from "../types";
|
|
2
3
|
|
|
3
4
|
export type FilterDatatype = "string" | "number";
|
|
4
5
|
|
|
5
6
|
export function filter_data(
|
|
6
|
-
data: { id: string; value:
|
|
7
|
+
data: { id: string; value: CellValue }[][],
|
|
7
8
|
filter_columns: {
|
|
8
9
|
col: number;
|
|
9
10
|
datatype: FilterDatatype;
|
|
@@ -164,7 +165,7 @@ export function filter_data(
|
|
|
164
165
|
}
|
|
165
166
|
|
|
166
167
|
export function filter_data_and_preserve_selection(
|
|
167
|
-
data: { id: string; value:
|
|
168
|
+
data: { id: string; value: CellValue }[][],
|
|
168
169
|
display_value: string[][] | null,
|
|
169
170
|
styling: string[][] | null,
|
|
170
171
|
filter_columns: {
|
|
@@ -176,9 +177,9 @@ export function filter_data_and_preserve_selection(
|
|
|
176
177
|
selected: [number, number] | false,
|
|
177
178
|
get_current_indices: (
|
|
178
179
|
id: string,
|
|
179
|
-
data: { id: string; value:
|
|
180
|
+
data: { id: string; value: CellValue }[][]
|
|
180
181
|
) => [number, number],
|
|
181
|
-
original_data?: { id: string; value:
|
|
182
|
+
original_data?: { id: string; value: CellValue }[][],
|
|
182
183
|
original_display_value?: string[][] | null,
|
|
183
184
|
original_styling?: string[][] | null
|
|
184
185
|
): { data: typeof data; selected: [number, number] | false } {
|
|
@@ -40,12 +40,7 @@ export async function handle_cell_blur(
|
|
|
40
40
|
const input_el = event.target as HTMLInputElement;
|
|
41
41
|
if (!input_el || input_el.value === undefined) return;
|
|
42
42
|
|
|
43
|
-
await save_cell_value(
|
|
44
|
-
input_el.type === "checkbox" ? String(input_el.checked) : input_el.value,
|
|
45
|
-
ctx,
|
|
46
|
-
coords[0],
|
|
47
|
-
coords[1]
|
|
48
|
-
);
|
|
43
|
+
await save_cell_value(input_el.value, ctx, coords[0], coords[1]);
|
|
49
44
|
}
|
|
50
45
|
|
|
51
46
|
function handle_header_navigation(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { CellCoordinate } from "./../types";
|
|
1
|
+
import type { CellCoordinate, CellValue } from "./../types";
|
|
2
2
|
|
|
3
|
-
export type CellData = { id: string; value:
|
|
3
|
+
export type CellData = { id: string; value: CellValue };
|
|
4
4
|
|
|
5
5
|
export function is_cell_in_selection(
|
|
6
6
|
coords: [number, number],
|
|
@@ -208,7 +208,7 @@ export function select_row(data: any[][], row: number): CellCoordinate[] {
|
|
|
208
208
|
|
|
209
209
|
export function calculate_selection_positions(
|
|
210
210
|
selected: CellCoordinate,
|
|
211
|
-
data: { id: string; value:
|
|
211
|
+
data: { id: string; value: CellValue }[][],
|
|
212
212
|
els: Record<string, { cell: HTMLTableCellElement | null }>,
|
|
213
213
|
parent: HTMLElement,
|
|
214
214
|
table: HTMLElement
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Headers } from "../types";
|
|
1
|
+
import type { Headers, CellValue } from "../types";
|
|
2
2
|
import { sort_table_data } from "./table_utils";
|
|
3
3
|
|
|
4
4
|
export type SortDirection = "asc" | "desc";
|
|
@@ -21,7 +21,7 @@ export function get_sort_status(
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export function sort_data(
|
|
24
|
-
data: { id: string; value:
|
|
24
|
+
data: { id: string; value: CellValue }[][],
|
|
25
25
|
sort_columns: { col: number; direction: SortDirection }[]
|
|
26
26
|
): number[] {
|
|
27
27
|
if (!data || !data.length || !data[0]) {
|
|
@@ -64,14 +64,14 @@ export function sort_data(
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
export function sort_data_and_preserve_selection(
|
|
67
|
-
data: { id: string; value:
|
|
67
|
+
data: { id: string; value: CellValue }[][],
|
|
68
68
|
display_value: string[][] | null,
|
|
69
69
|
styling: string[][] | null,
|
|
70
70
|
sort_columns: { col: number; direction: SortDirection }[],
|
|
71
71
|
selected: [number, number] | false,
|
|
72
72
|
get_current_indices: (
|
|
73
73
|
id: string,
|
|
74
|
-
data: { id: string; value:
|
|
74
|
+
data: { id: string; value: CellValue }[][]
|
|
75
75
|
) => [number, number]
|
|
76
76
|
): { data: typeof data; selected: [number, number] | false } {
|
|
77
77
|
let id = null;
|