@gradio/dataframe 0.14.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.
- package/CHANGELOG.md +45 -0
- package/Dataframe.stories.svelte +283 -7
- package/Index.svelte +22 -3
- package/dist/Index.svelte +18 -4
- package/dist/Index.svelte.d.ts +16 -0
- package/dist/shared/EditableCell.svelte +49 -7
- package/dist/shared/EditableCell.svelte.d.ts +1 -1
- package/dist/shared/Table.svelte +692 -411
- package/dist/shared/Table.svelte.d.ts +4 -0
- package/dist/shared/Toolbar.svelte +122 -30
- package/dist/shared/Toolbar.svelte.d.ts +4 -0
- package/dist/shared/VirtualTable.svelte +70 -26
- package/dist/shared/VirtualTable.svelte.d.ts +1 -0
- package/dist/shared/icons/FilterIcon.svelte +11 -0
- package/dist/shared/icons/FilterIcon.svelte.d.ts +16 -0
- package/dist/shared/icons/SortIcon.svelte +90 -0
- package/dist/shared/icons/SortIcon.svelte.d.ts +20 -0
- package/dist/shared/selection_utils.d.ts +30 -0
- package/dist/shared/selection_utils.js +139 -0
- package/dist/shared/types.d.ts +18 -0
- package/dist/shared/types.js +2 -0
- package/dist/shared/utils/menu_utils.d.ts +42 -0
- package/dist/shared/utils/menu_utils.js +58 -0
- package/dist/shared/utils/sort_utils.d.ts +7 -0
- package/dist/shared/utils/sort_utils.js +39 -0
- package/dist/shared/utils/table_utils.d.ts +12 -0
- package/dist/shared/utils/table_utils.js +148 -0
- package/package.json +8 -8
- package/shared/EditableCell.svelte +55 -7
- package/shared/Table.svelte +762 -478
- package/shared/Toolbar.svelte +125 -30
- package/shared/VirtualTable.svelte +73 -26
- package/shared/icons/FilterIcon.svelte +12 -0
- package/shared/icons/SortIcon.svelte +95 -0
- package/shared/selection_utils.ts +230 -0
- package/shared/types.ts +29 -0
- package/shared/utils/menu_utils.ts +115 -0
- package/shared/utils/sort_utils.test.ts +71 -0
- package/shared/utils/sort_utils.ts +55 -0
- package/shared/utils/table_utils.test.ts +114 -0
- package/shared/utils/table_utils.ts +206 -0
- package/dist/shared/table_utils.d.ts +0 -6
- package/dist/shared/table_utils.js +0 -27
- package/shared/table_utils.ts +0 -38
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,50 @@
|
|
|
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
|
+
|
|
32
|
+
## 0.15.0
|
|
33
|
+
|
|
34
|
+
### Features
|
|
35
|
+
|
|
36
|
+
- [#10456](https://github.com/gradio-app/gradio/pull/10456) [`8e40c15`](https://github.com/gradio-app/gradio/commit/8e40c15669ed1244d6f2288e55c2223279bd37a4) - Implement multiple cell selection. Thanks @hannahblair!
|
|
37
|
+
- [#10463](https://github.com/gradio-app/gradio/pull/10463) [`ed7a091`](https://github.com/gradio-app/gradio/commit/ed7a0919ab6b31184dc4d686b722dbeb013e9ce9) - Expand and collapse dataframe cells. Thanks @hannahblair!
|
|
38
|
+
- [#10478](https://github.com/gradio-app/gradio/pull/10478) [`afb96c6`](https://github.com/gradio-app/gradio/commit/afb96c64451e5a282bfee89445d831d1c87f9746) - Improve dataframe's upload accessibility. Thanks @hannahblair!
|
|
39
|
+
- [#10491](https://github.com/gradio-app/gradio/pull/10491) [`ff5f976`](https://github.com/gradio-app/gradio/commit/ff5f976bbb685fdd4f7c1faeda79e094f55a9f56) - Allow multiline headers in gr.Dataframe. Thanks @hannahblair!
|
|
40
|
+
- [#10494](https://github.com/gradio-app/gradio/pull/10494) [`10932a2`](https://github.com/gradio-app/gradio/commit/10932a291ac7f591bb1d56e4e353b51f10ecc6e3) - Ensure dataframe is not editable when `interactive` is False. Thanks @hannahblair!
|
|
41
|
+
|
|
42
|
+
### Dependency updates
|
|
43
|
+
|
|
44
|
+
- @gradio/client@1.11.0
|
|
45
|
+
- @gradio/upload@0.15.0
|
|
46
|
+
- @gradio/button@0.4.5
|
|
47
|
+
|
|
3
48
|
## 0.14.0
|
|
4
49
|
|
|
5
50
|
### Features
|
package/Dataframe.stories.svelte
CHANGED
|
@@ -93,6 +93,26 @@
|
|
|
93
93
|
row_count: [3, "dynamic"],
|
|
94
94
|
editable: false
|
|
95
95
|
}}
|
|
96
|
+
play={async ({ canvasElement }) => {
|
|
97
|
+
// tests that the cell is not editable
|
|
98
|
+
|
|
99
|
+
const canvas = within(canvasElement);
|
|
100
|
+
const cells = canvas.getAllByRole("cell");
|
|
101
|
+
const initial_value = cells[0].textContent;
|
|
102
|
+
|
|
103
|
+
await userEvent.click(cells[0]);
|
|
104
|
+
await userEvent.keyboard("new value");
|
|
105
|
+
|
|
106
|
+
const final_value = cells[0].textContent;
|
|
107
|
+
if (initial_value !== final_value) {
|
|
108
|
+
throw new Error("Cell content changed when it should be non-editable");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const inputs = canvas.queryAllByRole("textbox");
|
|
112
|
+
if (inputs.length > 0) {
|
|
113
|
+
throw new Error("Input field appeared when table should be non-editable");
|
|
114
|
+
}
|
|
115
|
+
}}
|
|
96
116
|
/>
|
|
97
117
|
|
|
98
118
|
<Story
|
|
@@ -184,6 +204,18 @@
|
|
|
184
204
|
}}
|
|
185
205
|
/>
|
|
186
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
|
+
|
|
187
219
|
<Story
|
|
188
220
|
name="Dataframe with dialog interactions"
|
|
189
221
|
args={{
|
|
@@ -200,9 +232,11 @@
|
|
|
200
232
|
const canvas = within(canvasElement);
|
|
201
233
|
|
|
202
234
|
const cell_400 = canvas.getAllByRole("cell")[5];
|
|
203
|
-
userEvent.click(cell_400);
|
|
235
|
+
await userEvent.click(cell_400);
|
|
204
236
|
|
|
205
|
-
const open_dialog_btn = within(cell_400).
|
|
237
|
+
const open_dialog_btn = await within(cell_400).findByRole("button", {
|
|
238
|
+
name: "⋮"
|
|
239
|
+
});
|
|
206
240
|
await userEvent.click(open_dialog_btn);
|
|
207
241
|
|
|
208
242
|
const add_row_btn = canvas.getByText("Add row above");
|
|
@@ -214,7 +248,7 @@
|
|
|
214
248
|
/>
|
|
215
249
|
|
|
216
250
|
<Story
|
|
217
|
-
name="Dataframe with fullscreen button"
|
|
251
|
+
name="Dataframe with fullscreen button and label and search"
|
|
218
252
|
args={{
|
|
219
253
|
col_count: [3, "dynamic"],
|
|
220
254
|
row_count: [2, "dynamic"],
|
|
@@ -223,7 +257,51 @@
|
|
|
223
257
|
[800, 100, 400],
|
|
224
258
|
[200, 800, 700]
|
|
225
259
|
],
|
|
226
|
-
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"
|
|
265
|
+
}}
|
|
266
|
+
/>
|
|
267
|
+
|
|
268
|
+
<Story
|
|
269
|
+
name="Dataframe with multiple selection interactions"
|
|
270
|
+
args={{
|
|
271
|
+
values: [
|
|
272
|
+
[1, 2, 3, 4],
|
|
273
|
+
[5, 6, 7, 8],
|
|
274
|
+
[9, 10, 11, 12],
|
|
275
|
+
[13, 14, 15, 16]
|
|
276
|
+
],
|
|
277
|
+
col_count: [4, "dynamic"],
|
|
278
|
+
row_count: [4, "dynamic"],
|
|
279
|
+
headers: ["A", "B", "C", "D"],
|
|
280
|
+
editable: true
|
|
281
|
+
}}
|
|
282
|
+
play={async ({ canvasElement }) => {
|
|
283
|
+
const canvas = within(canvasElement);
|
|
284
|
+
const cells = canvas.getAllByRole("cell");
|
|
285
|
+
const user = userEvent.setup();
|
|
286
|
+
|
|
287
|
+
// cmd+click to select non-contiguous cells
|
|
288
|
+
await user.keyboard("[MetaLeft>]");
|
|
289
|
+
await user.click(cells[4]);
|
|
290
|
+
await user.click(cells[6]);
|
|
291
|
+
await user.click(cells[2]);
|
|
292
|
+
await user.keyboard("[/MetaLeft]");
|
|
293
|
+
|
|
294
|
+
// shift+click to select a range
|
|
295
|
+
await user.keyboard("[ShiftLeft>]");
|
|
296
|
+
await user.click(cells[7]);
|
|
297
|
+
await user.click(cells[6]);
|
|
298
|
+
await user.keyboard("[/ShiftLeft]");
|
|
299
|
+
|
|
300
|
+
// clear selected cells
|
|
301
|
+
await user.keyboard("{Delete}");
|
|
302
|
+
|
|
303
|
+
// verify cells were cleared by clicking one
|
|
304
|
+
await user.click(cells[2]);
|
|
227
305
|
}}
|
|
228
306
|
/>
|
|
229
307
|
|
|
@@ -232,7 +310,7 @@
|
|
|
232
310
|
args={{
|
|
233
311
|
col_count: [3, "dynamic"],
|
|
234
312
|
row_count: [2, "dynamic"],
|
|
235
|
-
headers: ["Math", "Reading", "
|
|
313
|
+
headers: ["Math", "Reading", "Writing"],
|
|
236
314
|
values: [
|
|
237
315
|
[800, 100, 400],
|
|
238
316
|
[200, 800, 700]
|
|
@@ -244,15 +322,213 @@
|
|
|
244
322
|
const canvas = within(canvasElement);
|
|
245
323
|
|
|
246
324
|
const copy_button = canvas.getByRole("button", {
|
|
247
|
-
name:
|
|
325
|
+
name: "Copy table data"
|
|
248
326
|
});
|
|
249
327
|
await userEvent.click(copy_button);
|
|
250
328
|
|
|
251
329
|
const fullscreen_button = canvas.getByRole("button", {
|
|
252
|
-
name:
|
|
330
|
+
name: "Enter fullscreen"
|
|
253
331
|
});
|
|
254
332
|
await userEvent.click(fullscreen_button);
|
|
255
333
|
|
|
256
334
|
await userEvent.click(fullscreen_button);
|
|
257
335
|
}}
|
|
258
336
|
/>
|
|
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
|
+
|
|
357
|
+
<Story
|
|
358
|
+
name="Dataframe with truncated text"
|
|
359
|
+
args={{
|
|
360
|
+
values: [
|
|
361
|
+
[
|
|
362
|
+
"This is a very long text that should be truncated",
|
|
363
|
+
"Short text",
|
|
364
|
+
"Another very long text that needs truncation"
|
|
365
|
+
],
|
|
366
|
+
[
|
|
367
|
+
"Short",
|
|
368
|
+
"This text is also quite long and should be truncated as well",
|
|
369
|
+
"Medium length text here"
|
|
370
|
+
],
|
|
371
|
+
[
|
|
372
|
+
"Medium text",
|
|
373
|
+
"Brief",
|
|
374
|
+
"This is the longest text in the entire table and it should definitely be truncated"
|
|
375
|
+
]
|
|
376
|
+
],
|
|
377
|
+
headers: ["Column A", "Column B", "Column C"],
|
|
378
|
+
label: "Truncated Text Example",
|
|
379
|
+
max_chars: 20,
|
|
380
|
+
col_count: [3, "dynamic"],
|
|
381
|
+
row_count: [3, "dynamic"]
|
|
382
|
+
}}
|
|
383
|
+
/>
|
|
384
|
+
|
|
385
|
+
<Story
|
|
386
|
+
name="Dataframe with multiline headers"
|
|
387
|
+
args={{
|
|
388
|
+
values: [
|
|
389
|
+
[95, 92, 88],
|
|
390
|
+
[89, 90, 85],
|
|
391
|
+
[92, 88, 91]
|
|
392
|
+
],
|
|
393
|
+
headers: [
|
|
394
|
+
"Dataset A\nAccuracy",
|
|
395
|
+
"Dataset B\nPrecision",
|
|
396
|
+
"Dataset C\nRecall"
|
|
397
|
+
],
|
|
398
|
+
label: "Model Metrics",
|
|
399
|
+
col_count: [3, "dynamic"],
|
|
400
|
+
row_count: [3, "dynamic"],
|
|
401
|
+
editable: false
|
|
402
|
+
}}
|
|
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
|
@@ -49,10 +49,24 @@
|
|
|
49
49
|
export let loading_status: LoadingStatus;
|
|
50
50
|
export let interactive: boolean;
|
|
51
51
|
export let show_fullscreen_button = false;
|
|
52
|
+
export let max_chars: number | undefined = undefined;
|
|
52
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;
|
|
53
68
|
|
|
54
69
|
$: _headers = [...(value.headers || headers)];
|
|
55
|
-
$: cell_values = value.data ? [...value.data] : [];
|
|
56
70
|
$: display_value = value?.metadata?.display_value
|
|
57
71
|
? [...value?.metadata?.display_value]
|
|
58
72
|
: null;
|
|
@@ -70,7 +84,7 @@
|
|
|
70
84
|
container={false}
|
|
71
85
|
{scale}
|
|
72
86
|
{min_width}
|
|
73
|
-
|
|
87
|
+
overflow_behavior="visible"
|
|
74
88
|
>
|
|
75
89
|
<StatusTracker
|
|
76
90
|
autoscroll={gradio.autoscroll}
|
|
@@ -84,7 +98,7 @@
|
|
|
84
98
|
{show_label}
|
|
85
99
|
{row_count}
|
|
86
100
|
{col_count}
|
|
87
|
-
values={
|
|
101
|
+
values={filtered_cell_values || value.data}
|
|
88
102
|
{display_value}
|
|
89
103
|
{styling}
|
|
90
104
|
headers={_headers}
|
|
@@ -94,6 +108,7 @@
|
|
|
94
108
|
}}
|
|
95
109
|
on:input={(e) => gradio.dispatch("input")}
|
|
96
110
|
on:select={(e) => gradio.dispatch("select", e.detail)}
|
|
111
|
+
on:search={(e) => (search_query = e.detail)}
|
|
97
112
|
{wrap}
|
|
98
113
|
{datatype}
|
|
99
114
|
{latex_delimiters}
|
|
@@ -106,6 +121,10 @@
|
|
|
106
121
|
stream_handler={(...args) => gradio.client.stream(...args)}
|
|
107
122
|
bind:value_is_output
|
|
108
123
|
{show_fullscreen_button}
|
|
124
|
+
{max_chars}
|
|
109
125
|
{show_copy_button}
|
|
126
|
+
{show_row_numbers}
|
|
127
|
+
{show_search}
|
|
128
|
+
{pinned_columns}
|
|
110
129
|
/>
|
|
111
130
|
</Block>
|
package/dist/Index.svelte
CHANGED
|
@@ -34,11 +34,20 @@ export let max_height = void 0;
|
|
|
34
34
|
export let loading_status;
|
|
35
35
|
export let interactive;
|
|
36
36
|
export let show_fullscreen_button = false;
|
|
37
|
+
export let max_chars = void 0;
|
|
37
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;
|
|
38
42
|
$:
|
|
39
|
-
|
|
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;
|
|
40
49
|
$:
|
|
41
|
-
|
|
50
|
+
_headers = [...value.headers || headers];
|
|
42
51
|
$:
|
|
43
52
|
display_value = value?.metadata?.display_value ? [...value?.metadata?.display_value] : null;
|
|
44
53
|
$:
|
|
@@ -53,7 +62,7 @@ $:
|
|
|
53
62
|
container={false}
|
|
54
63
|
{scale}
|
|
55
64
|
{min_width}
|
|
56
|
-
|
|
65
|
+
overflow_behavior="visible"
|
|
57
66
|
>
|
|
58
67
|
<StatusTracker
|
|
59
68
|
autoscroll={gradio.autoscroll}
|
|
@@ -67,7 +76,7 @@ $:
|
|
|
67
76
|
{show_label}
|
|
68
77
|
{row_count}
|
|
69
78
|
{col_count}
|
|
70
|
-
values={
|
|
79
|
+
values={filtered_cell_values || value.data}
|
|
71
80
|
{display_value}
|
|
72
81
|
{styling}
|
|
73
82
|
headers={_headers}
|
|
@@ -77,6 +86,7 @@ $:
|
|
|
77
86
|
}}
|
|
78
87
|
on:input={(e) => gradio.dispatch("input")}
|
|
79
88
|
on:select={(e) => gradio.dispatch("select", e.detail)}
|
|
89
|
+
on:search={(e) => (search_query = e.detail)}
|
|
80
90
|
{wrap}
|
|
81
91
|
{datatype}
|
|
82
92
|
{latex_delimiters}
|
|
@@ -89,6 +99,10 @@ $:
|
|
|
89
99
|
stream_handler={(...args) => gradio.client.stream(...args)}
|
|
90
100
|
bind:value_is_output
|
|
91
101
|
{show_fullscreen_button}
|
|
102
|
+
{max_chars}
|
|
92
103
|
{show_copy_button}
|
|
104
|
+
{show_row_numbers}
|
|
105
|
+
{show_search}
|
|
106
|
+
{pinned_columns}
|
|
93
107
|
/>
|
|
94
108
|
</Block>
|
package/dist/Index.svelte.d.ts
CHANGED
|
@@ -38,7 +38,11 @@ declare const __propDef: {
|
|
|
38
38
|
loading_status: LoadingStatus;
|
|
39
39
|
interactive: boolean;
|
|
40
40
|
show_fullscreen_button?: boolean | undefined;
|
|
41
|
+
max_chars?: number | undefined;
|
|
41
42
|
show_copy_button?: boolean | undefined;
|
|
43
|
+
show_row_numbers?: boolean | undefined;
|
|
44
|
+
show_search?: ("none" | "search" | "filter") | undefined;
|
|
45
|
+
pinned_columns?: number | undefined;
|
|
42
46
|
};
|
|
43
47
|
events: {
|
|
44
48
|
[evt: string]: CustomEvent<any>;
|
|
@@ -136,7 +140,19 @@ export default class Index extends SvelteComponent<IndexProps, IndexEvents, Inde
|
|
|
136
140
|
get show_fullscreen_button(): boolean | undefined;
|
|
137
141
|
/**accessor*/
|
|
138
142
|
set show_fullscreen_button(_: boolean | undefined);
|
|
143
|
+
get max_chars(): number | undefined;
|
|
144
|
+
/**accessor*/
|
|
145
|
+
set max_chars(_: number | undefined);
|
|
139
146
|
get show_copy_button(): boolean | undefined;
|
|
140
147
|
/**accessor*/
|
|
141
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);
|
|
142
158
|
}
|
|
@@ -11,10 +11,20 @@ export let clear_on_focus = false;
|
|
|
11
11
|
export let line_breaks = true;
|
|
12
12
|
export let editable = true;
|
|
13
13
|
export let root;
|
|
14
|
+
export let max_chars = null;
|
|
14
15
|
const dispatch = createEventDispatcher();
|
|
16
|
+
let is_expanded = false;
|
|
15
17
|
export let el;
|
|
16
18
|
$:
|
|
17
19
|
_value = value;
|
|
20
|
+
function truncate_text(text, max_length = null) {
|
|
21
|
+
const str = String(text);
|
|
22
|
+
if (!max_length || str.length <= max_length)
|
|
23
|
+
return str;
|
|
24
|
+
return str.slice(0, max_length) + "...";
|
|
25
|
+
}
|
|
26
|
+
$:
|
|
27
|
+
display_text = is_expanded ? value : truncate_text(display_value || value, max_chars);
|
|
18
28
|
function use_focus(node) {
|
|
19
29
|
if (clear_on_focus) {
|
|
20
30
|
_value = "";
|
|
@@ -32,11 +42,20 @@ function handle_blur({
|
|
|
32
42
|
}
|
|
33
43
|
function handle_keydown(event) {
|
|
34
44
|
if (event.key === "Enter") {
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
if (edit) {
|
|
46
|
+
value = _value;
|
|
47
|
+
dispatch("blur");
|
|
48
|
+
} else if (!header) {
|
|
49
|
+
is_expanded = !is_expanded;
|
|
50
|
+
}
|
|
37
51
|
}
|
|
38
52
|
dispatch("keydown", event);
|
|
39
53
|
}
|
|
54
|
+
function handle_click() {
|
|
55
|
+
if (!edit && !header) {
|
|
56
|
+
is_expanded = !is_expanded;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
40
59
|
</script>
|
|
41
60
|
|
|
42
61
|
{#if edit}
|
|
@@ -56,27 +75,31 @@ function handle_keydown(event) {
|
|
|
56
75
|
{/if}
|
|
57
76
|
|
|
58
77
|
<span
|
|
59
|
-
on:
|
|
60
|
-
|
|
78
|
+
on:click={handle_click}
|
|
79
|
+
on:keydown={handle_keydown}
|
|
80
|
+
tabindex="0"
|
|
61
81
|
role="button"
|
|
62
82
|
class:edit
|
|
83
|
+
class:expanded={is_expanded}
|
|
84
|
+
class:multiline={header}
|
|
63
85
|
on:focus|preventDefault
|
|
64
86
|
style={styling}
|
|
65
87
|
class="table-cell-text"
|
|
88
|
+
data-editable={editable}
|
|
66
89
|
placeholder=" "
|
|
67
90
|
>
|
|
68
91
|
{#if datatype === "html"}
|
|
69
|
-
{@html
|
|
92
|
+
{@html display_text}
|
|
70
93
|
{:else if datatype === "markdown"}
|
|
71
94
|
<MarkdownCode
|
|
72
|
-
message={
|
|
95
|
+
message={display_text.toLocaleString()}
|
|
73
96
|
{latex_delimiters}
|
|
74
97
|
{line_breaks}
|
|
75
98
|
chatbot={false}
|
|
76
99
|
{root}
|
|
77
100
|
/>
|
|
78
101
|
{:else}
|
|
79
|
-
{editable ?
|
|
102
|
+
{editable ? display_text : display_value || display_text}
|
|
80
103
|
{/if}
|
|
81
104
|
</span>
|
|
82
105
|
|
|
@@ -97,18 +120,37 @@ function handle_keydown(event) {
|
|
|
97
120
|
|
|
98
121
|
span {
|
|
99
122
|
flex: 1 1 0%;
|
|
123
|
+
position: relative;
|
|
124
|
+
display: inline-block;
|
|
100
125
|
outline: none;
|
|
101
126
|
padding: var(--size-2);
|
|
127
|
+
padding-right: 0;
|
|
102
128
|
-webkit-user-select: text;
|
|
103
129
|
-moz-user-select: text;
|
|
104
130
|
-ms-user-select: text;
|
|
105
131
|
user-select: text;
|
|
106
132
|
cursor: text;
|
|
133
|
+
width: 100%;
|
|
134
|
+
height: 100%;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
span.expanded {
|
|
138
|
+
height: auto;
|
|
139
|
+
min-height: 100%;
|
|
140
|
+
white-space: pre-wrap;
|
|
141
|
+
word-break: break-word;
|
|
142
|
+
white-space: normal;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.multiline {
|
|
146
|
+
white-space: pre-line;
|
|
107
147
|
}
|
|
108
148
|
|
|
109
149
|
.header {
|
|
110
150
|
transform: translateX(0);
|
|
111
151
|
font-weight: var(--weight-bold);
|
|
152
|
+
white-space: normal;
|
|
153
|
+
word-break: break-word;
|
|
112
154
|
}
|
|
113
155
|
|
|
114
156
|
.edit {
|
|
@@ -16,13 +16,13 @@ declare const __propDef: {
|
|
|
16
16
|
line_breaks?: boolean | undefined;
|
|
17
17
|
editable?: boolean | undefined;
|
|
18
18
|
root: string;
|
|
19
|
+
max_chars?: (number | null) | undefined;
|
|
19
20
|
el: HTMLInputElement | null;
|
|
20
21
|
};
|
|
21
22
|
events: {
|
|
22
23
|
mousedown: MouseEvent;
|
|
23
24
|
mouseup: MouseEvent;
|
|
24
25
|
click: MouseEvent;
|
|
25
|
-
dblclick: MouseEvent;
|
|
26
26
|
focus: FocusEvent;
|
|
27
27
|
blur: CustomEvent<any>;
|
|
28
28
|
keydown: CustomEvent<any>;
|