@gradio/dataframe 0.15.0 → 0.16.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/Dataframe.stories.svelte +168 -2
  3. package/Index.svelte +20 -3
  4. package/dist/Index.svelte +16 -4
  5. package/dist/Index.svelte.d.ts +12 -0
  6. package/dist/shared/EditableCell.svelte +1 -4
  7. package/dist/shared/Table.svelte +423 -181
  8. package/dist/shared/Table.svelte.d.ts +3 -0
  9. package/dist/shared/Toolbar.svelte +122 -30
  10. package/dist/shared/Toolbar.svelte.d.ts +4 -0
  11. package/dist/shared/VirtualTable.svelte +70 -26
  12. package/dist/shared/VirtualTable.svelte.d.ts +1 -0
  13. package/dist/shared/icons/FilterIcon.svelte +11 -0
  14. package/dist/shared/icons/FilterIcon.svelte.d.ts +16 -0
  15. package/dist/shared/icons/SortIcon.svelte +90 -0
  16. package/dist/shared/icons/SortIcon.svelte.d.ts +20 -0
  17. package/dist/shared/selection_utils.d.ts +12 -2
  18. package/dist/shared/selection_utils.js +33 -5
  19. package/dist/shared/types.d.ts +16 -0
  20. package/dist/shared/types.js +1 -0
  21. package/dist/shared/utils/menu_utils.d.ts +42 -0
  22. package/dist/shared/utils/menu_utils.js +58 -0
  23. package/dist/shared/utils/sort_utils.d.ts +7 -0
  24. package/dist/shared/utils/sort_utils.js +39 -0
  25. package/dist/shared/utils/table_utils.d.ts +12 -0
  26. package/dist/shared/utils/table_utils.js +148 -0
  27. package/package.json +8 -8
  28. package/shared/EditableCell.svelte +1 -4
  29. package/shared/Table.svelte +453 -182
  30. package/shared/Toolbar.svelte +125 -30
  31. package/shared/VirtualTable.svelte +73 -26
  32. package/shared/icons/FilterIcon.svelte +12 -0
  33. package/shared/icons/SortIcon.svelte +95 -0
  34. package/shared/selection_utils.ts +51 -9
  35. package/shared/types.ts +27 -0
  36. package/shared/utils/menu_utils.ts +115 -0
  37. package/shared/utils/sort_utils.test.ts +71 -0
  38. package/shared/utils/sort_utils.ts +55 -0
  39. package/shared/utils/table_utils.test.ts +114 -0
  40. package/shared/utils/table_utils.ts +206 -0
  41. package/dist/shared/table_utils.d.ts +0 -12
  42. package/dist/shared/table_utils.js +0 -113
  43. package/shared/table_utils.ts +0 -148
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # @gradio/dataframe
2
2
 
3
+ ## 0.16.0
4
+
5
+ ### Features
6
+
7
+ - [#10561](https://github.com/gradio-app/gradio/pull/10561) [`26494ce`](https://github.com/gradio-app/gradio/commit/26494cea570ffe0ead1f8b7a7135ab5a89c6bcbd) - Allow freezing columns in `gr.Dataframe`. Thanks @hannahblair!
8
+ - [#10554](https://github.com/gradio-app/gradio/pull/10554) [`b8ff5d6`](https://github.com/gradio-app/gradio/commit/b8ff5d6bfe1a9f3379580754b1e23857e2f0c96b) - Add optional search bar to `gr.Dataframe`'s toolbar. Thanks @hannahblair!
9
+ - [#10529](https://github.com/gradio-app/gradio/pull/10529) [`196b600`](https://github.com/gradio-app/gradio/commit/196b600b3962b85781b53c512e17708644b86f6f) - Select entire row or column in dataframe. Thanks @hannahblair!
10
+ - [#10558](https://github.com/gradio-app/gradio/pull/10558) [`1113002`](https://github.com/gradio-app/gradio/commit/111300242fdf135724a304920a93fc34a8037f7d) - Fix spacing issue with `gr.Dataframe` in Safari. Thanks @hannahblair!
11
+ - [#10553](https://github.com/gradio-app/gradio/pull/10553) [`4c08b9f`](https://github.com/gradio-app/gradio/commit/4c08b9f3c0bcafb0edc56330d8d81e78a6e3763b) - Prevent scrolling when the dataframe cell menu is open. Thanks @hannahblair!
12
+ - [#10541](https://github.com/gradio-app/gradio/pull/10541) [`e505fab`](https://github.com/gradio-app/gradio/commit/e505fabecb17c50e073483ed7d6aab2e04c9fcf2) - Add copy button feedback to `gr.Dataframe`. Thanks @hannahblair!
13
+ - [#10540](https://github.com/gradio-app/gradio/pull/10540) [`deeebfb`](https://github.com/gradio-app/gradio/commit/deeebfba46f15bb3641b86e25156215d2d727087) - Revert editable text changes. Thanks @hannahblair!
14
+
15
+ ### Fixes
16
+
17
+ - [#10490](https://github.com/gradio-app/gradio/pull/10490) [`178311b`](https://github.com/gradio-app/gradio/commit/178311b72d72a3c5f4a67bee5e0098be4232e68c) - Ensure row numbers functionality in dataframe works as expected. Thanks @hannahblair!
18
+ - [#10535](https://github.com/gradio-app/gradio/pull/10535) [`d909868`](https://github.com/gradio-app/gradio/commit/d9098681f8883686a617c8f98b22c77057febed1) - Ensure `max_height` is applied in `gr.Dataframe`. Thanks @hannahblair!
19
+ - [#10521](https://github.com/gradio-app/gradio/pull/10521) [`79937fd`](https://github.com/gradio-app/gradio/commit/79937fd76021b31abdbc3f8f2c32ef123fd676aa) - Change word-break prop in dataframe headers. Thanks @hannahblair!
20
+ - [#10520](https://github.com/gradio-app/gradio/pull/10520) [`2a1fc2a`](https://github.com/gradio-app/gradio/commit/2a1fc2a92888f622579e4b2daf86be487c73004d) - Ensure links work as expected in dataframe. Thanks @hannahblair!
21
+
22
+ ### Dependency updates
23
+
24
+ - @gradio/statustracker@0.10.3
25
+ - @gradio/atoms@0.13.2
26
+ - @gradio/utils@0.10.1
27
+ - @gradio/client@1.12.0
28
+ - @gradio/markdown-code@0.4.0
29
+ - @gradio/upload@0.15.1
30
+ - @gradio/button@0.4.6
31
+
3
32
  ## 0.15.0
4
33
 
5
34
  ### Features
@@ -204,6 +204,18 @@
204
204
  }}
205
205
  />
206
206
 
207
+ <Story
208
+ name="Dataframe with link"
209
+ args={{
210
+ values: [['<a href="https://www.google.com/">google</a>']],
211
+ headers: ["link"],
212
+ datatype: ["markdown"],
213
+ interactive: false,
214
+ col_count: [1, "dynamic"],
215
+ row_count: [1, "dynamic"]
216
+ }}
217
+ />
218
+
207
219
  <Story
208
220
  name="Dataframe with dialog interactions"
209
221
  args={{
@@ -236,7 +248,7 @@
236
248
  />
237
249
 
238
250
  <Story
239
- name="Dataframe with fullscreen button"
251
+ name="Dataframe with fullscreen button and label and search"
240
252
  args={{
241
253
  col_count: [3, "dynamic"],
242
254
  row_count: [2, "dynamic"],
@@ -245,7 +257,11 @@
245
257
  [800, 100, 400],
246
258
  [200, 800, 700]
247
259
  ],
248
- show_fullscreen_button: true
260
+ show_fullscreen_button: true,
261
+ show_label: true,
262
+ show_copy_button: true,
263
+ show_search: "search",
264
+ label: "Test scores"
249
265
  }}
250
266
  />
251
267
 
@@ -319,6 +335,25 @@
319
335
  }}
320
336
  />
321
337
 
338
+ <Story
339
+ name="Dataframe with row numbers"
340
+ args={{
341
+ values: [
342
+ [95, 92, 88],
343
+ [89, 90, 85],
344
+ [92, 88, 91],
345
+ [87, 85, 89],
346
+ [91, 93, 90]
347
+ ],
348
+ headers: ["Model A", "Model B", "Model C"],
349
+ label: "Model Performance",
350
+ col_count: [3, "dynamic"],
351
+ row_count: [5, "dynamic"],
352
+ show_row_numbers: true,
353
+ editable: false
354
+ }}
355
+ />
356
+
322
357
  <Story
323
358
  name="Dataframe with truncated text"
324
359
  args={{
@@ -366,3 +401,134 @@
366
401
  editable: false
367
402
  }}
368
403
  />
404
+
405
+ <Story
406
+ name="Dataframe with row and column selection"
407
+ args={{
408
+ values: [
409
+ [1, 2, 3, 4],
410
+ [5, 6, 7, 8],
411
+ [9, 10, 11, 12],
412
+ [13, 14, 15, 16]
413
+ ],
414
+ col_count: [4, "dynamic"],
415
+ row_count: [4, "dynamic"],
416
+ headers: ["A", "B", "C", "D"],
417
+ editable: true
418
+ }}
419
+ play={async ({ canvasElement }) => {
420
+ const canvas = within(canvasElement);
421
+ const user = userEvent.setup();
422
+
423
+ const grid = canvas.getByRole("grid");
424
+ await user.click(grid);
425
+
426
+ const cells = canvas.getAllByRole("cell");
427
+ await user.click(cells[5]); // Click cell with value 6
428
+
429
+ const row_button = await canvas.findByRole("button", {
430
+ name: "Select row"
431
+ });
432
+ await user.click(row_button);
433
+
434
+ await user.click(cells[6]);
435
+
436
+ const col_button = await canvas.findByRole("button", {
437
+ name: "Select column"
438
+ });
439
+ await user.click(col_button);
440
+
441
+ await user.keyboard("{Delete}");
442
+ }}
443
+ />
444
+
445
+ <Story
446
+ name="Dataframe with lots of values"
447
+ args={{
448
+ values: [
449
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
450
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
451
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
452
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
453
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
454
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
455
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
456
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
457
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
458
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
459
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
460
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
461
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
462
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
463
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
464
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
465
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
466
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
467
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
468
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
469
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
470
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
471
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
472
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
473
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
474
+ ],
475
+ col_count: [10, "dynamic"],
476
+ row_count: [10, "dynamic"],
477
+ max_height: 700
478
+ }}
479
+ />
480
+
481
+ <Story
482
+ name="Dataframe with search and filter"
483
+ args={{
484
+ values: [
485
+ ["Cat", 5, "Pet"],
486
+ ["Horse", 3, "Farm"],
487
+ ["Snake", 1, "Pet"],
488
+ ["Cow", 4, "Farm"],
489
+ ["Dog", 6, "Pet"]
490
+ ],
491
+ headers: ["Animal", "Count", "Type"],
492
+ col_count: [3, "dynamic"],
493
+ row_count: [5, "dynamic"],
494
+ show_search: "filter",
495
+ editable: false
496
+ }}
497
+ play={async ({ canvasElement }) => {
498
+ const canvas = within(canvasElement);
499
+ const user = userEvent.setup();
500
+
501
+ const search_input = canvas.getByPlaceholderText("Search...");
502
+ await user.type(search_input, "Pet");
503
+
504
+ await new Promise((resolve) => setTimeout(resolve, 100));
505
+
506
+ const filter_button = canvas.getByLabelText(
507
+ "Apply filter and update dataframe values"
508
+ );
509
+ await user.click(filter_button);
510
+
511
+ await new Promise((resolve) => setTimeout(resolve, 100));
512
+ }}
513
+ />
514
+
515
+ <Story
516
+ name="Dataframe with frozen columns"
517
+ args={{
518
+ values: [
519
+ ["ID", "Name", "Age", "City", "Country", "Score"],
520
+ ["1", "John", "25", "New York", "USA", "95"],
521
+ ["2", "Emma", "30", "London", "UK", "88"],
522
+ ["3", "Luis", "28", "Madrid", "Spain", "92"],
523
+ ["4", "Anna", "35", "Paris", "France", "90"],
524
+ ["5", "Chen", "27", "Beijing", "China", "94"]
525
+ ],
526
+ headers: ["ID", "Name", "Age", "City", "Country", "Score"],
527
+ label: "User Data",
528
+ col_count: [6, "dynamic"],
529
+ row_count: [6, "dynamic"],
530
+ pinned_columns: 2,
531
+ show_row_numbers: true,
532
+ editable: false
533
+ }}
534
+ />
package/Index.svelte CHANGED
@@ -51,9 +51,22 @@
51
51
  export let show_fullscreen_button = false;
52
52
  export let max_chars: number | undefined = undefined;
53
53
  export let show_copy_button = false;
54
+ export let show_row_numbers = false;
55
+ export let show_search: "none" | "search" | "filter" = "none";
56
+
57
+ let search_query: string | null = null;
58
+ $: filtered_cell_values = search_query
59
+ ? value.data?.filter((row) =>
60
+ row.some(
61
+ (cell) =>
62
+ search_query &&
63
+ String(cell).toLowerCase().includes(search_query.toLowerCase())
64
+ )
65
+ )
66
+ : null;
67
+ export let pinned_columns = 0;
54
68
 
55
69
  $: _headers = [...(value.headers || headers)];
56
- $: cell_values = value.data ? [...value.data] : [];
57
70
  $: display_value = value?.metadata?.display_value
58
71
  ? [...value?.metadata?.display_value]
59
72
  : null;
@@ -71,7 +84,7 @@
71
84
  container={false}
72
85
  {scale}
73
86
  {min_width}
74
- allow_overflow={false}
87
+ overflow_behavior="visible"
75
88
  >
76
89
  <StatusTracker
77
90
  autoscroll={gradio.autoscroll}
@@ -85,7 +98,7 @@
85
98
  {show_label}
86
99
  {row_count}
87
100
  {col_count}
88
- values={cell_values}
101
+ values={filtered_cell_values || value.data}
89
102
  {display_value}
90
103
  {styling}
91
104
  headers={_headers}
@@ -95,6 +108,7 @@
95
108
  }}
96
109
  on:input={(e) => gradio.dispatch("input")}
97
110
  on:select={(e) => gradio.dispatch("select", e.detail)}
111
+ on:search={(e) => (search_query = e.detail)}
98
112
  {wrap}
99
113
  {datatype}
100
114
  {latex_delimiters}
@@ -109,5 +123,8 @@
109
123
  {show_fullscreen_button}
110
124
  {max_chars}
111
125
  {show_copy_button}
126
+ {show_row_numbers}
127
+ {show_search}
128
+ {pinned_columns}
112
129
  />
113
130
  </Block>
package/dist/Index.svelte CHANGED
@@ -36,10 +36,18 @@ export let interactive;
36
36
  export let show_fullscreen_button = false;
37
37
  export let max_chars = void 0;
38
38
  export let show_copy_button = false;
39
+ export let show_row_numbers = false;
40
+ export let show_search = "none";
41
+ let search_query = null;
39
42
  $:
40
- _headers = [...value.headers || headers];
43
+ filtered_cell_values = search_query ? value.data?.filter(
44
+ (row) => row.some(
45
+ (cell) => search_query && String(cell).toLowerCase().includes(search_query.toLowerCase())
46
+ )
47
+ ) : null;
48
+ export let pinned_columns = 0;
41
49
  $:
42
- cell_values = value.data ? [...value.data] : [];
50
+ _headers = [...value.headers || headers];
43
51
  $:
44
52
  display_value = value?.metadata?.display_value ? [...value?.metadata?.display_value] : null;
45
53
  $:
@@ -54,7 +62,7 @@ $:
54
62
  container={false}
55
63
  {scale}
56
64
  {min_width}
57
- allow_overflow={false}
65
+ overflow_behavior="visible"
58
66
  >
59
67
  <StatusTracker
60
68
  autoscroll={gradio.autoscroll}
@@ -68,7 +76,7 @@ $:
68
76
  {show_label}
69
77
  {row_count}
70
78
  {col_count}
71
- values={cell_values}
79
+ values={filtered_cell_values || value.data}
72
80
  {display_value}
73
81
  {styling}
74
82
  headers={_headers}
@@ -78,6 +86,7 @@ $:
78
86
  }}
79
87
  on:input={(e) => gradio.dispatch("input")}
80
88
  on:select={(e) => gradio.dispatch("select", e.detail)}
89
+ on:search={(e) => (search_query = e.detail)}
81
90
  {wrap}
82
91
  {datatype}
83
92
  {latex_delimiters}
@@ -92,5 +101,8 @@ $:
92
101
  {show_fullscreen_button}
93
102
  {max_chars}
94
103
  {show_copy_button}
104
+ {show_row_numbers}
105
+ {show_search}
106
+ {pinned_columns}
95
107
  />
96
108
  </Block>
@@ -40,6 +40,9 @@ declare const __propDef: {
40
40
  show_fullscreen_button?: boolean | undefined;
41
41
  max_chars?: number | undefined;
42
42
  show_copy_button?: boolean | undefined;
43
+ show_row_numbers?: boolean | undefined;
44
+ show_search?: ("none" | "search" | "filter") | undefined;
45
+ pinned_columns?: number | undefined;
43
46
  };
44
47
  events: {
45
48
  [evt: string]: CustomEvent<any>;
@@ -143,4 +146,13 @@ export default class Index extends SvelteComponent<IndexProps, IndexEvents, Inde
143
146
  get show_copy_button(): boolean | undefined;
144
147
  /**accessor*/
145
148
  set show_copy_button(_: boolean | undefined);
149
+ get show_row_numbers(): boolean | undefined;
150
+ /**accessor*/
151
+ set show_row_numbers(_: boolean | undefined);
152
+ get show_search(): "filter" | "none" | "search" | undefined;
153
+ /**accessor*/
154
+ set show_search(_: "filter" | "none" | "search" | undefined);
155
+ get pinned_columns(): number | undefined;
156
+ /**accessor*/
157
+ set pinned_columns(_: number | undefined);
146
158
  }
@@ -124,6 +124,7 @@ function handle_click() {
124
124
  display: inline-block;
125
125
  outline: none;
126
126
  padding: var(--size-2);
127
+ padding-right: 0;
127
128
  -webkit-user-select: text;
128
129
  -moz-user-select: text;
129
130
  -ms-user-select: text;
@@ -133,10 +134,6 @@ function handle_click() {
133
134
  height: 100%;
134
135
  }
135
136
 
136
- input:where(:not(.header), [data-editable="true"]) {
137
- width: calc(100% - var(--size-10));
138
- }
139
-
140
137
  span.expanded {
141
138
  height: auto;
142
139
  min-height: 100%;