@gradio/dataframe 0.18.2 → 0.18.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 CHANGED
@@ -1,5 +1,31 @@
1
1
  # @gradio/dataframe
2
2
 
3
+ ## 0.18.4
4
+
5
+ ### Fixes
6
+
7
+ - [#11559](https://github.com/gradio-app/gradio/pull/11559) [`dd9d8f1`](https://github.com/gradio-app/gradio/commit/dd9d8f1ed677e2d09a3061764c312f40133ab50d) - `gr.Dataframe` returns a `number` \ `bool` when the corresponding column is edited. Thanks @janosch6!
8
+
9
+ ### Dependency updates
10
+
11
+ - @gradio/upload@0.16.12
12
+ - @gradio/client@1.15.7
13
+ - @gradio/button@0.5.8
14
+
15
+ ## 0.18.3
16
+
17
+ ### Fixes
18
+
19
+ - [#11534](https://github.com/gradio-app/gradio/pull/11534) [`5259f22`](https://github.com/gradio-app/gradio/commit/5259f229939177cc2027db5164c9321566fb3eeb) - Allow changing value with single click instead of double click. Thanks @hannahblair!
20
+
21
+ ### Dependency updates
22
+
23
+ - @gradio/client@1.15.6
24
+ - @gradio/statustracker@0.10.15
25
+ - @gradio/button@0.5.7
26
+ - @gradio/upload@0.16.11
27
+ - @gradio/checkbox@0.4.26
28
+
3
29
  ## 0.18.2
4
30
 
5
31
  ### Fixes
@@ -5,25 +5,13 @@ export let on_change;
5
5
  $:
6
6
  bool_value = typeof value === "string" ? value.toLowerCase() === "true" : !!value;
7
7
  function handle_change(event) {
8
- on_change(event.detail);
9
- }
10
- function handle_click(event) {
11
- event.stopPropagation();
12
- }
13
- function handle_keydown(event) {
14
- if (event.key === "Enter" || event.key === " ") {
15
- event.stopPropagation();
8
+ if (editable) {
9
+ on_change(event.detail);
16
10
  }
17
11
  }
18
12
  </script>
19
13
 
20
- <div
21
- class="bool-cell checkbox"
22
- on:click={handle_click}
23
- on:keydown={handle_keydown}
24
- role="button"
25
- tabindex="-1"
26
- >
14
+ <div class="bool-cell" role="button" tabindex="-1">
27
15
  <BaseCheckbox
28
16
  bind:value={bool_value}
29
17
  label=""
@@ -37,15 +25,13 @@ function handle_keydown(event) {
37
25
  display: flex;
38
26
  align-items: center;
39
27
  justify-content: center;
40
- width: var(--size-full);
28
+ width: min-content;
41
29
  height: var(--size-full);
42
- }
43
- .bool-cell :global(input:disabled) {
44
- opacity: 0.8;
30
+ margin: 0 auto;
45
31
  }
46
32
 
47
- .bool-cell.checkbox {
48
- justify-content: center;
33
+ .bool-cell :global(input:disabled) {
34
+ cursor: not-allowed;
49
35
  }
50
36
 
51
37
  .bool-cell :global(label) {
@@ -28,6 +28,7 @@ import {
28
28
  handle_file_upload
29
29
  } from "./utils/table_utils";
30
30
  import { make_headers, process_data } from "./utils/data_processing";
31
+ import { cast_value_to_type } from "./utils";
31
32
  import { handle_keydown, handle_cell_blur } from "./utils/keyboard_utils";
32
33
  import {
33
34
  create_drag_handlers
@@ -249,7 +250,15 @@ let previous_data = data.map((row) => row.map((cell) => String(cell.value)));
249
250
  $: {
250
251
  if (data || _headers) {
251
252
  df_actions.trigger_change(
252
- data,
253
+ data.map(
254
+ (row, rowIdx) => row.map((cell, colIdx) => {
255
+ const dtype = Array.isArray(datatype) ? datatype[colIdx] : datatype;
256
+ return {
257
+ ...cell,
258
+ value: cast_value_to_type(cell.value, dtype)
259
+ };
260
+ })
261
+ ),
253
262
  _headers,
254
263
  previous_data,
255
264
  previous_headers,
@@ -1,8 +1,13 @@
1
1
  import { get_range_selection } from "../selection_utils";
2
2
  export function create_drag_handlers(state, set_is_dragging, set_selected_cells, set_selected, handle_cell_click, show_row_numbers, parent_element) {
3
3
  const start_drag = (event, row, col) => {
4
+ const target = event.target;
5
+ const is_checkbox_click = target.type === "checkbox" ||
6
+ target.closest('input[type="checkbox"]') ||
7
+ target.closest(".bool-cell");
4
8
  if (event.target instanceof HTMLAnchorElement ||
5
- (show_row_numbers && col === -1))
9
+ (show_row_numbers && col === -1) ||
10
+ is_checkbox_click)
6
11
  return;
7
12
  event.preventDefault();
8
13
  event.stopPropagation();
@@ -13,3 +13,10 @@ export type DataframeValue = {
13
13
  headers: Headers;
14
14
  metadata: Metadata;
15
15
  };
16
+ /**
17
+ * Coerce a value to a given type.
18
+ * @param v - The value to coerce.
19
+ * @param t - The type to coerce to.
20
+ * @returns The coerced value.
21
+ */
22
+ export declare function cast_value_to_type(v: any, t: Datatype): string | number | boolean;
@@ -1 +1,29 @@
1
- export {};
1
+ /**
2
+ * Coerce a value to a given type.
3
+ * @param v - The value to coerce.
4
+ * @param t - The type to coerce to.
5
+ * @returns The coerced value.
6
+ */
7
+ export function cast_value_to_type(v, t) {
8
+ if (t === "number") {
9
+ const n = Number(v);
10
+ return isNaN(n) ? v : n;
11
+ }
12
+ if (t === "bool") {
13
+ if (typeof v === "boolean")
14
+ return v;
15
+ if (typeof v === "number")
16
+ return v !== 0;
17
+ const s = String(v).toLowerCase();
18
+ if (s === "true" || s === "1")
19
+ return true;
20
+ if (s === "false" || s === "0")
21
+ return false;
22
+ return v;
23
+ }
24
+ if (t === "date") {
25
+ const d = new Date(v);
26
+ return isNaN(d.getTime()) ? v : d.toISOString();
27
+ }
28
+ return v;
29
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradio/dataframe",
3
- "version": "0.18.2",
3
+ "version": "0.18.4",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "author": "",
@@ -18,14 +18,14 @@
18
18
  "katex": "^0.16.7",
19
19
  "marked": "^12.0.0",
20
20
  "@gradio/atoms": "^0.16.3",
21
- "@gradio/checkbox": "^0.4.25",
22
- "@gradio/button": "^0.5.6",
23
- "@gradio/client": "^1.15.5",
21
+ "@gradio/checkbox": "^0.4.26",
22
+ "@gradio/button": "^0.5.8",
23
+ "@gradio/client": "^1.15.7",
24
24
  "@gradio/icons": "^0.12.0",
25
- "@gradio/statustracker": "^0.10.14",
26
25
  "@gradio/markdown-code": "^0.5.0",
27
- "@gradio/utils": "^0.10.2",
28
- "@gradio/upload": "^0.16.10"
26
+ "@gradio/statustracker": "^0.10.15",
27
+ "@gradio/upload": "^0.16.12",
28
+ "@gradio/utils": "^0.10.2"
29
29
  },
30
30
  "exports": {
31
31
  ".": {
@@ -9,27 +9,13 @@
9
9
  typeof value === "string" ? value.toLowerCase() === "true" : !!value;
10
10
 
11
11
  function handle_change(event: CustomEvent<boolean>): void {
12
- on_change(event.detail);
13
- }
14
-
15
- function handle_click(event: MouseEvent): void {
16
- event.stopPropagation();
17
- }
18
-
19
- function handle_keydown(event: KeyboardEvent): void {
20
- if (event.key === "Enter" || event.key === " ") {
21
- event.stopPropagation();
12
+ if (editable) {
13
+ on_change(event.detail);
22
14
  }
23
15
  }
24
16
  </script>
25
17
 
26
- <div
27
- class="bool-cell checkbox"
28
- on:click={handle_click}
29
- on:keydown={handle_keydown}
30
- role="button"
31
- tabindex="-1"
32
- >
18
+ <div class="bool-cell" role="button" tabindex="-1">
33
19
  <BaseCheckbox
34
20
  bind:value={bool_value}
35
21
  label=""
@@ -43,15 +29,13 @@
43
29
  display: flex;
44
30
  align-items: center;
45
31
  justify-content: center;
46
- width: var(--size-full);
32
+ width: min-content;
47
33
  height: var(--size-full);
48
- }
49
- .bool-cell :global(input:disabled) {
50
- opacity: 0.8;
34
+ margin: 0 auto;
51
35
  }
52
36
 
53
- .bool-cell.checkbox {
54
- justify-content: center;
37
+ .bool-cell :global(input:disabled) {
38
+ cursor: not-allowed;
55
39
  }
56
40
 
57
41
  .bool-cell :global(label) {
@@ -37,6 +37,7 @@
37
37
  handle_file_upload
38
38
  } from "./utils/table_utils";
39
39
  import { make_headers, process_data } from "./utils/data_processing";
40
+ import { cast_value_to_type } from "./utils";
40
41
  import { handle_keydown, handle_cell_blur } from "./utils/keyboard_utils";
41
42
  import {
42
43
  create_drag_handlers,
@@ -330,7 +331,15 @@
330
331
  $: {
331
332
  if (data || _headers) {
332
333
  df_actions.trigger_change(
333
- data,
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
+ ),
334
343
  _headers,
335
344
  previous_data,
336
345
  previous_headers,
@@ -23,9 +23,16 @@ export function create_drag_handlers(
23
23
  parent_element?: HTMLElement
24
24
  ): DragHandlers {
25
25
  const start_drag = (event: MouseEvent, row: number, col: number): void => {
26
+ const target = event.target as HTMLElement;
27
+ const is_checkbox_click =
28
+ (target as HTMLInputElement).type === "checkbox" ||
29
+ target.closest('input[type="checkbox"]') ||
30
+ target.closest(".bool-cell");
31
+
26
32
  if (
27
33
  event.target instanceof HTMLAnchorElement ||
28
- (show_row_numbers && col === -1)
34
+ (show_row_numbers && col === -1) ||
35
+ is_checkbox_click
29
36
  )
30
37
  return;
31
38
 
package/shared/utils.ts CHANGED
@@ -10,3 +10,32 @@ export type DataframeValue = {
10
10
  headers: Headers;
11
11
  metadata: Metadata;
12
12
  };
13
+
14
+ /**
15
+ * Coerce a value to a given type.
16
+ * @param v - The value to coerce.
17
+ * @param t - The type to coerce to.
18
+ * @returns The coerced value.
19
+ */
20
+ export function cast_value_to_type(
21
+ v: any,
22
+ t: Datatype
23
+ ): string | number | boolean {
24
+ if (t === "number") {
25
+ const n = Number(v);
26
+ return isNaN(n) ? v : n;
27
+ }
28
+ if (t === "bool") {
29
+ if (typeof v === "boolean") return v;
30
+ if (typeof v === "number") return v !== 0;
31
+ const s = String(v).toLowerCase();
32
+ if (s === "true" || s === "1") return true;
33
+ if (s === "false" || s === "0") return false;
34
+ return v;
35
+ }
36
+ if (t === "date") {
37
+ const d = new Date(v);
38
+ return isNaN(d.getTime()) ? v : d.toISOString();
39
+ }
40
+ return v;
41
+ }
@@ -1,6 +1,7 @@
1
1
  import { describe, test, expect } from "vitest";
2
2
  import { make_cell_id, make_header_id } from "../shared/utils/table_utils";
3
3
  import { process_data, make_headers } from "../shared/utils/data_processing";
4
+ import { cast_value_to_type } from "../shared/utils";
4
5
 
5
6
  function make_id(): string {
6
7
  return Math.random().toString(36).substring(2, 15);
@@ -133,3 +134,33 @@ describe("table_utils", () => {
133
134
  });
134
135
  });
135
136
  });
137
+
138
+ describe("cast_value_to_type", () => {
139
+ test("casts to number", () => {
140
+ expect(cast_value_to_type("42", "number")).toBe(42);
141
+ expect(cast_value_to_type(3.14, "number")).toBe(3.14);
142
+ expect(cast_value_to_type("not a number", "number")).toBe("not a number");
143
+ });
144
+ test("casts to bool", () => {
145
+ expect(cast_value_to_type("True", "bool")).toBe(true);
146
+ expect(cast_value_to_type("False", "bool")).toBe(false);
147
+ expect(cast_value_to_type(1, "bool")).toBe(true);
148
+ expect(cast_value_to_type(0, "bool")).toBe(false);
149
+ expect(cast_value_to_type("1", "bool")).toBe(true);
150
+ expect(cast_value_to_type("0", "bool")).toBe(false);
151
+ expect(cast_value_to_type("yes", "bool")).toBe("yes");
152
+ expect(cast_value_to_type("no", "bool")).toBe("no");
153
+ expect(cast_value_to_type("on", "bool")).toBe("on");
154
+ expect(cast_value_to_type("off", "bool")).toBe("off");
155
+ expect(cast_value_to_type("random", "bool")).toBe("random");
156
+ });
157
+ test("casts to date", () => {
158
+ const result = cast_value_to_type("2023-01-01", "date");
159
+ expect(result).toBe("2023-01-01T00:00:00.000Z");
160
+ expect(typeof cast_value_to_type("not a date", "date")).toBe("string");
161
+ });
162
+ test("returns value as-is for str", () => {
163
+ expect(cast_value_to_type("hello", "str")).toBe("hello");
164
+ expect(cast_value_to_type(123, "str")).toBe(123);
165
+ });
166
+ });