@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.
Files changed (39) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/Index.svelte +3 -1
  3. package/dist/Index.svelte +1 -0
  4. package/dist/Index.svelte.d.ts +6 -3
  5. package/dist/shared/BooleanCell.svelte +1 -2
  6. package/dist/shared/BooleanCell.svelte.d.ts +1 -1
  7. package/dist/shared/EditableCell.svelte +7 -18
  8. package/dist/shared/EditableCell.svelte.d.ts +2 -1
  9. package/dist/shared/Table.svelte +23 -13
  10. package/dist/shared/Table.svelte.d.ts +4 -2
  11. package/dist/shared/TableCell.svelte.d.ts +2 -1
  12. package/dist/shared/TableHeader.svelte +57 -0
  13. package/dist/shared/TableHeader.svelte.d.ts +7 -0
  14. package/dist/shared/context/dataframe_context.d.ts +9 -8
  15. package/dist/shared/context/dataframe_context.js +9 -1
  16. package/dist/shared/types.d.ts +2 -1
  17. package/dist/shared/utils/data_processing.d.ts +5 -4
  18. package/dist/shared/utils/data_processing.js +4 -2
  19. package/dist/shared/utils/filter_utils.d.ts +5 -4
  20. package/dist/shared/utils/keyboard_utils.js +1 -1
  21. package/dist/shared/utils/selection_utils.d.ts +3 -3
  22. package/dist/shared/utils/sort_utils.d.ts +4 -4
  23. package/dist/shared/utils/table_utils.d.ts +2 -2
  24. package/dist/shared/utils/utils.d.ts +8 -2
  25. package/package.json +8 -8
  26. package/shared/BooleanCell.svelte +2 -5
  27. package/shared/EditableCell.svelte +12 -20
  28. package/shared/Table.svelte +43 -27
  29. package/shared/TableCell.svelte +2 -1
  30. package/shared/TableHeader.svelte +62 -0
  31. package/shared/context/dataframe_context.ts +20 -13
  32. package/shared/types.ts +3 -1
  33. package/shared/utils/data_processing.ts +10 -5
  34. package/shared/utils/filter_utils.ts +5 -4
  35. package/shared/utils/keyboard_utils.ts +1 -6
  36. package/shared/utils/selection_utils.ts +3 -3
  37. package/shared/utils/sort_utils.ts +4 -4
  38. package/shared/utils/table_utils.ts +8 -2
  39. 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: (string | number)[][]) => void): void;
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 = (string | number)[][];
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): string | number | boolean;
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.2",
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/button": "^0.5.12",
17
- "@gradio/checkbox": "^0.4.29",
18
- "@gradio/atoms": "^0.17.0",
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/markdown-code": "^0.5.1",
21
- "@gradio/statustracker": "^0.11.0",
22
- "@gradio/upload": "^0.16.17",
23
- "@gradio/client": "^1.18.0",
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: boolean | string = false;
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={bool_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: string | number = "";
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: string | number,
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 handle_bool_change(new_value: boolean): void {
90
- value = new_value.toString();
91
- dispatch("blur", {
92
- blur_event: {
93
- target: {
94
- type: "checkbox",
95
- checked: new_value,
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}
@@ -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 { Headers, DataframeValue, Datatype } from "./utils/utils";
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: (string | number)[][] = [];
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: string | number; display_value?: string }[][] =
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: string | number;
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): string | 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): (string | number)[] =>
206
+ const get_column = (col: number): CellValue[] =>
203
207
  data?.map((row) => row[col]?.value) ?? [];
204
208
 
205
- const get_row = (row: number): (string | 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 (string | number)[][],
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 (string | number)[][];
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) => String(cell.value)));
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.map((row, rowIdx) =>
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) => String(cell.value)));
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: (string | number)[][] = [];
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: (string | number)[] = [];
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>
@@ -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: string | number;
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?: (string | number)[];
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: string | number }[][];
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: string | number }[][];
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: string[][],
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) => string | number;
187
- get_column?: (col: number) => (string | number)[];
188
- get_row?: (row: number) => (string | 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: string | number }[][] | string[][] | null,
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
@@ -9,9 +9,11 @@ export interface HeadersWithIDs {
9
9
  }
10
10
  [];
11
11
 
12
+ export type CellValue = string | number | boolean;
13
+
12
14
  export interface TableCell {
13
15
  id: string;
14
- value: string | number;
16
+ value: CellValue;
15
17
  }
16
18
 
17
19
  export type TableData = TableCell[][];
@@ -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: (string | number)[][],
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
- ): { id: string; value: string | number; display_value?: string }[][] {
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: string | number }[][],
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: string | number }[][],
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: string | number }[][]
180
+ data: { id: string; value: CellValue }[][]
180
181
  ) => [number, number],
181
- original_data?: { id: string; value: string | number }[][],
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: string | number };
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: string | number }[][],
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: string | number }[][],
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: string | number }[][],
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: string | number }[][]
74
+ data: { id: string; value: CellValue }[][]
75
75
  ) => [number, number]
76
76
  ): { data: typeof data; selected: [number, number] | false } {
77
77
  let id = null;