@gradio/dataframe 0.16.5 → 0.17.1

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 (87) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/Dataframe.stories.svelte +202 -9
  3. package/Index.svelte +7 -13
  4. package/dist/Index.svelte +5 -9
  5. package/dist/Index.svelte.d.ts +9 -2
  6. package/dist/shared/CellMenu.svelte +91 -10
  7. package/dist/shared/CellMenu.svelte.d.ts +6 -0
  8. package/dist/shared/CellMenuButton.svelte +45 -0
  9. package/dist/shared/CellMenuButton.svelte.d.ts +16 -0
  10. package/dist/shared/CellMenuIcons.svelte +79 -0
  11. package/dist/shared/EditableCell.svelte +83 -14
  12. package/dist/shared/EditableCell.svelte.d.ts +12 -3
  13. package/dist/shared/EmptyRowButton.svelte +28 -0
  14. package/dist/shared/EmptyRowButton.svelte.d.ts +16 -0
  15. package/dist/shared/RowNumber.svelte +40 -0
  16. package/dist/shared/RowNumber.svelte.d.ts +17 -0
  17. package/dist/shared/Table.svelte +564 -1121
  18. package/dist/shared/Table.svelte.d.ts +4 -0
  19. package/dist/shared/TableCell.svelte +291 -0
  20. package/dist/shared/TableCell.svelte.d.ts +57 -0
  21. package/dist/shared/TableHeader.svelte +239 -0
  22. package/dist/shared/TableHeader.svelte.d.ts +45 -0
  23. package/dist/shared/Toolbar.svelte +18 -8
  24. package/dist/shared/VirtualTable.svelte +66 -19
  25. package/dist/shared/VirtualTable.svelte.d.ts +4 -0
  26. package/dist/shared/context/keyboard_context.d.ts +37 -0
  27. package/dist/shared/context/keyboard_context.js +12 -0
  28. package/dist/shared/context/selection_context.d.ts +32 -0
  29. package/dist/shared/context/selection_context.js +107 -0
  30. package/dist/shared/context/table_context.d.ts +141 -0
  31. package/dist/shared/context/table_context.js +375 -0
  32. package/dist/shared/icons/Padlock.svelte +24 -0
  33. package/dist/shared/icons/Padlock.svelte.d.ts +23 -0
  34. package/dist/shared/icons/SelectionButtons.svelte +85 -0
  35. package/dist/shared/icons/SelectionButtons.svelte.d.ts +18 -0
  36. package/dist/shared/icons/SortArrowDown.svelte +24 -0
  37. package/dist/shared/icons/SortArrowDown.svelte.d.ts +16 -0
  38. package/dist/shared/icons/SortArrowUp.svelte +24 -0
  39. package/dist/shared/icons/SortArrowUp.svelte.d.ts +16 -0
  40. package/dist/shared/icons/SortButtonDown.svelte +14 -0
  41. package/dist/shared/icons/SortButtonDown.svelte.d.ts +23 -0
  42. package/dist/shared/icons/SortButtonUp.svelte +15 -0
  43. package/dist/shared/icons/SortButtonUp.svelte.d.ts +23 -0
  44. package/dist/shared/icons/SortIcon.svelte +46 -68
  45. package/dist/shared/icons/SortIcon.svelte.d.ts +3 -2
  46. package/dist/shared/selection_utils.d.ts +2 -1
  47. package/dist/shared/selection_utils.js +39 -10
  48. package/dist/shared/utils/data_processing.d.ts +13 -0
  49. package/dist/shared/utils/data_processing.js +45 -0
  50. package/dist/shared/utils/drag_utils.d.ts +15 -0
  51. package/dist/shared/utils/drag_utils.js +57 -0
  52. package/dist/shared/utils/keyboard_utils.d.ts +2 -0
  53. package/dist/shared/utils/keyboard_utils.js +186 -0
  54. package/dist/shared/utils/sort_utils.d.ts +22 -3
  55. package/dist/shared/utils/sort_utils.js +44 -24
  56. package/dist/shared/utils/table_utils.d.ts +6 -5
  57. package/dist/shared/utils/table_utils.js +13 -56
  58. package/package.json +7 -7
  59. package/shared/CellMenu.svelte +90 -10
  60. package/shared/CellMenuButton.svelte +46 -0
  61. package/shared/CellMenuIcons.svelte +79 -0
  62. package/shared/EditableCell.svelte +97 -18
  63. package/shared/EmptyRowButton.svelte +29 -0
  64. package/shared/RowNumber.svelte +41 -0
  65. package/shared/Table.svelte +604 -1235
  66. package/shared/TableCell.svelte +324 -0
  67. package/shared/TableHeader.svelte +256 -0
  68. package/shared/Toolbar.svelte +19 -8
  69. package/shared/VirtualTable.svelte +72 -19
  70. package/shared/context/keyboard_context.ts +65 -0
  71. package/shared/context/selection_context.ts +168 -0
  72. package/shared/context/table_context.ts +625 -0
  73. package/shared/icons/Padlock.svelte +24 -0
  74. package/shared/icons/SelectionButtons.svelte +93 -0
  75. package/shared/icons/SortArrowDown.svelte +25 -0
  76. package/shared/icons/SortArrowUp.svelte +25 -0
  77. package/shared/icons/SortButtonDown.svelte +14 -0
  78. package/shared/icons/SortButtonUp.svelte +15 -0
  79. package/shared/icons/SortIcon.svelte +47 -70
  80. package/shared/selection_utils.ts +39 -13
  81. package/shared/utils/data_processing.ts +72 -0
  82. package/shared/utils/drag_utils.ts +92 -0
  83. package/shared/utils/keyboard_utils.ts +238 -0
  84. package/shared/utils/sort_utils.test.ts +262 -14
  85. package/shared/utils/sort_utils.ts +67 -31
  86. package/shared/utils/table_utils.test.ts +66 -45
  87. package/shared/utils/table_utils.ts +16 -86
@@ -1,10 +1,10 @@
1
1
  import { describe, test, expect } from "vitest";
2
- import {
3
- make_cell_id,
4
- make_header_id,
5
- process_data,
6
- make_headers
7
- } from "./table_utils";
2
+ import { make_cell_id, make_header_id } from "./table_utils";
3
+ import { process_data, make_headers } from "./data_processing";
4
+
5
+ function make_id(): string {
6
+ return Math.random().toString(36).substring(2, 15);
7
+ }
8
8
 
9
9
  describe("table_utils", () => {
10
10
  describe("id generation", () => {
@@ -20,8 +20,8 @@ describe("table_utils", () => {
20
20
 
21
21
  test("generates unique header ids", () => {
22
22
  const id_set = new Set();
23
- for (let col = 0; col < 10; col++) {
24
- id_set.add(make_header_id(col));
23
+ for (let i = 0; i < 10; i++) {
24
+ id_set.add(make_header_id(i));
25
25
  }
26
26
  expect(id_set.size).toBe(10);
27
27
  });
@@ -38,12 +38,9 @@ describe("table_utils", () => {
38
38
  ["1", "2"],
39
39
  ["3", "4"]
40
40
  ],
41
- [2, "fixed"],
42
- [2, "fixed"],
43
- ["A", "B"],
44
- true,
45
41
  element_refs,
46
- data_binding
42
+ data_binding,
43
+ make_id
47
44
  );
48
45
 
49
46
  expect(test_result[0].map((item) => item.value)).toEqual(["1", "2"]);
@@ -56,12 +53,9 @@ describe("table_utils", () => {
56
53
  ["1", "2"],
57
54
  ["3", "4"]
58
55
  ],
59
- [2, "fixed"],
60
- [2, "fixed"],
61
- ["A", "B"],
62
- false,
63
56
  element_refs,
64
- data_binding
57
+ data_binding,
58
+ make_id
65
59
  );
66
60
 
67
61
  expect(test_result.length).toBe(2);
@@ -71,44 +65,71 @@ describe("table_utils", () => {
71
65
  });
72
66
 
73
67
  test("handles empty data", () => {
74
- const test_result = process_data(
75
- [],
76
- [0, "dynamic"],
77
- [0, "dynamic"],
78
- [],
79
- false,
80
- element_refs,
81
- data_binding
82
- );
68
+ const test_result = process_data([], element_refs, data_binding, make_id);
83
69
 
84
70
  expect(test_result.length).toBe(0);
85
71
  });
86
72
  });
87
73
 
88
74
  describe("make_headers", () => {
89
- const element_refs: Record<string, { cell: null; input: null }> = {};
75
+ test("creates headers with ids when headers are provided", () => {
76
+ const els = {};
77
+ const headers = ["Name", "Age", "City"];
78
+ const col_count: [number, "fixed" | "dynamic"] = [3, "fixed"];
90
79
 
91
- test("adds empty column for row numbers", () => {
92
- const test_result = make_headers(
93
- ["A", "B"],
94
- true,
95
- [2, "fixed"],
96
- element_refs
97
- );
80
+ const result = make_headers(headers, col_count, els, make_id);
98
81
 
99
- expect(test_result.length).toBe(3);
100
- expect(test_result[0].value).toBe("");
101
- expect(test_result[1].value).toBe("A");
102
- expect(test_result[2].value).toBe("B");
82
+ expect(result.length).toBe(3);
83
+ expect(result[0].value).toBe("Name");
84
+ expect(result[1].value).toBe("Age");
85
+ expect(result[2].value).toBe("City");
86
+ expect(result[0].id).toBeDefined();
87
+ expect(result[1].id).toBeDefined();
88
+ expect(result[2].id).toBeDefined();
89
+ expect(Object.keys(els).length).toBe(3);
103
90
  });
104
91
 
105
- test("handles empty headers with fixed columns", () => {
106
- const test_result = make_headers([], false, [3, "fixed"], element_refs);
92
+ test("fills missing headers when col_count is fixed", () => {
93
+ const els = {};
94
+ const headers = ["Name", "Age"];
95
+ const col_count: [number, "fixed" | "dynamic"] = [4, "fixed"];
96
+
97
+ const result = make_headers(headers, col_count, els, make_id);
98
+
99
+ expect(result.length).toBe(4);
100
+ expect(result[0].value).toBe("Name");
101
+ expect(result[1].value).toBe("Age");
102
+ expect(result[2].value).toBe("2");
103
+ expect(result[3].value).toBe("3");
104
+ expect(Object.keys(els).length).toBe(4);
105
+ });
106
+
107
+ test("creates default headers when no headers are provided", () => {
108
+ const els = {};
109
+ const headers = [];
110
+ const col_count: [number, "fixed" | "dynamic"] = [3, "fixed"];
111
+
112
+ const result = make_headers(headers, col_count, els, make_id);
113
+
114
+ expect(result.length).toBe(3);
115
+ expect(result[0].value).toBe("0");
116
+ expect(result[1].value).toBe("1");
117
+ expect(result[2].value).toBe("2");
118
+ expect(Object.keys(els).length).toBe(3);
119
+ });
120
+
121
+ test("handles null values in headers", () => {
122
+ const els = {};
123
+ const headers = ["Name", null, "City"] as any;
124
+ const col_count: [number, "fixed" | "dynamic"] = [3, "fixed"];
125
+
126
+ const result = make_headers(headers, col_count, els, make_id);
107
127
 
108
- expect(test_result.length).toBe(3);
109
- expect(
110
- test_result.every((header) => typeof header.value === "string")
111
- ).toBe(true);
128
+ expect(result.length).toBe(3);
129
+ expect(result[0].value).toBe("Name");
130
+ expect(result[1].value).toBe("");
131
+ expect(result[2].value).toBe("City");
132
+ expect(Object.keys(els).length).toBe(3);
112
133
  });
113
134
  });
114
135
  });
@@ -1,12 +1,4 @@
1
- import type {
2
- Headers,
3
- HeadersWithIDs,
4
- TableCell,
5
- TableData,
6
- CountConfig,
7
- ElementRefs,
8
- DataBinding
9
- } from "../types";
1
+ import type { Headers, HeadersWithIDs, TableCell, TableData } from "../types";
10
2
  import { sort_data } from "./sort_utils";
11
3
  import type { SortDirection } from "./sort_utils";
12
4
  import { dsvFormat } from "d3-dsv";
@@ -19,77 +11,6 @@ export function make_header_id(col: number): string {
19
11
  return `header-${col}`;
20
12
  }
21
13
 
22
- export function process_data(
23
- input_values: (string | number)[][],
24
- row_count: CountConfig,
25
- col_count: CountConfig,
26
- headers: Headers,
27
- show_row_numbers: boolean,
28
- element_refs: ElementRefs,
29
- data_binding: DataBinding
30
- ): TableData {
31
- const data_row_length = input_values.length;
32
- return Array(row_count[1] === "fixed" ? row_count[0] : data_row_length)
33
- .fill(0)
34
- .map((_, row) => {
35
- return Array(
36
- col_count[1] === "fixed"
37
- ? col_count[0]
38
- : data_row_length > 0
39
- ? input_values[0].length
40
- : headers.length
41
- )
42
- .fill(0)
43
- .map((_, col) => {
44
- const cell_id = make_cell_id(row, col);
45
- element_refs[cell_id] = element_refs[cell_id] || {
46
- input: null,
47
- cell: null
48
- };
49
- const cell_obj: TableCell = {
50
- value: input_values?.[row]?.[col] ?? "",
51
- id: cell_id
52
- };
53
- data_binding[cell_id] = cell_obj;
54
- return cell_obj;
55
- });
56
- });
57
- }
58
-
59
- export function make_headers(
60
- input_headers: Headers,
61
- show_row_numbers: boolean,
62
- col_count: CountConfig,
63
- element_refs: ElementRefs
64
- ): HeadersWithIDs[] {
65
- let header_list = input_headers || [];
66
- if (show_row_numbers) {
67
- header_list = ["", ...header_list];
68
- }
69
- if (col_count[1] === "fixed" && header_list.length < col_count[0]) {
70
- const fill_headers = Array(col_count[0] - header_list.length)
71
- .fill("")
72
- .map((_, i) => `${i + header_list.length}`);
73
- header_list = header_list.concat(fill_headers);
74
- }
75
-
76
- if (!header_list || header_list.length === 0) {
77
- return Array(col_count[0])
78
- .fill(0)
79
- .map((_, col) => {
80
- const header_id = make_header_id(col);
81
- element_refs[header_id] = { cell: null, input: null };
82
- return { id: header_id, value: JSON.stringify(col + 1) };
83
- });
84
- }
85
-
86
- return header_list.map((header: string | null, col: number) => {
87
- const header_id = make_header_id(col);
88
- element_refs[header_id] = { cell: null, input: null };
89
- return { id: header_id, value: header ?? "" };
90
- });
91
- }
92
-
93
14
  export function get_max(data: TableData): TableCell[] {
94
15
  if (!data || !data.length) return [];
95
16
  let max = data[0].slice();
@@ -107,10 +28,12 @@ export function sort_table_data(
107
28
  data: TableData,
108
29
  display_value: string[][] | null,
109
30
  styling: string[][] | null,
110
- col: number,
111
- dir: SortDirection
31
+ sort_columns: { col: number; direction: SortDirection }[]
112
32
  ): void {
113
- const indices = sort_data(data, col, dir);
33
+ if (!sort_columns.length) return;
34
+ if (!data || !data.length) return;
35
+
36
+ const indices = sort_data(data, sort_columns);
114
37
 
115
38
  const new_data = indices.map((i: number) => data[i]);
116
39
  data.splice(0, data.length, ...new_data);
@@ -128,9 +51,15 @@ export function sort_table_data(
128
51
 
129
52
  export async function copy_table_data(
130
53
  data: TableData,
131
- selected_cells: [number, number][]
54
+ selected_cells: [number, number][] | null
132
55
  ): Promise<void> {
133
- const csv = selected_cells.reduce(
56
+ if (!data || !data.length) return;
57
+
58
+ const cells_to_copy =
59
+ selected_cells ||
60
+ data.flatMap((row, r) => row.map((_, c) => [r, c] as [number, number]));
61
+
62
+ const csv = cells_to_copy.reduce(
134
63
  (acc: { [key: string]: { [key: string]: string } }, [row, col]) => {
135
64
  acc[row] = acc[row] || {};
136
65
  const value = String(data[row][col].value);
@@ -144,6 +73,8 @@ export async function copy_table_data(
144
73
  );
145
74
 
146
75
  const rows = Object.keys(csv).sort((a, b) => +a - +b);
76
+ if (!rows.length) return;
77
+
147
78
  const cols = Object.keys(csv[rows[0]]).sort((a, b) => +a - +b);
148
79
  const text = rows
149
80
  .map((r) => cols.map((c) => csv[r][c] || "").join(","))
@@ -152,7 +83,6 @@ export async function copy_table_data(
152
83
  try {
153
84
  await navigator.clipboard.writeText(text);
154
85
  } catch (err) {
155
- console.error("Copy failed:", err);
156
86
  throw new Error("Failed to copy to clipboard: " + (err as Error).message);
157
87
  }
158
88
  }