@gradio/dataframe 0.17.16 → 0.18.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 (34) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/Dataframe.stories.svelte +1 -2
  3. package/Index.svelte +3 -13
  4. package/dist/Index.svelte +3 -10
  5. package/dist/Index.svelte.d.ts +1 -5
  6. package/dist/shared/CellMenu.svelte +37 -0
  7. package/dist/shared/CellMenu.svelte.d.ts +4 -1
  8. package/dist/shared/CellMenuIcons.svelte +48 -0
  9. package/dist/shared/EditableCell.svelte +0 -2
  10. package/dist/shared/EditableCell.svelte.d.ts +0 -1
  11. package/dist/shared/FilterMenu.svelte +235 -0
  12. package/dist/shared/FilterMenu.svelte.d.ts +19 -0
  13. package/dist/shared/Table.svelte +59 -5
  14. package/dist/shared/TableCell.svelte +0 -2
  15. package/dist/shared/TableCell.svelte.d.ts +0 -1
  16. package/dist/shared/TableHeader.svelte +26 -2
  17. package/dist/shared/TableHeader.svelte.d.ts +7 -1
  18. package/dist/shared/context/dataframe_context.d.ts +19 -0
  19. package/dist/shared/context/dataframe_context.js +46 -6
  20. package/dist/shared/utils/filter_utils.d.ts +28 -0
  21. package/dist/shared/utils/filter_utils.js +123 -0
  22. package/dist/shared/utils/table_utils.d.ts +7 -0
  23. package/dist/shared/utils/table_utils.js +29 -0
  24. package/package.json +9 -9
  25. package/shared/CellMenu.svelte +45 -1
  26. package/shared/CellMenuIcons.svelte +48 -0
  27. package/shared/EditableCell.svelte +0 -2
  28. package/shared/FilterMenu.svelte +248 -0
  29. package/shared/Table.svelte +78 -8
  30. package/shared/TableCell.svelte +0 -2
  31. package/shared/TableHeader.svelte +31 -2
  32. package/shared/context/dataframe_context.ts +80 -17
  33. package/shared/utils/filter_utils.ts +207 -0
  34. package/shared/utils/table_utils.ts +52 -0
@@ -33,6 +33,7 @@ import {
33
33
  create_drag_handlers
34
34
  } from "./utils/drag_utils";
35
35
  import { sort_data_and_preserve_selection } from "./utils/sort_utils";
36
+ import { filter_data_and_preserve_selection } from "./utils/filter_utils";
36
37
  export let datatype;
37
38
  export let label = null;
38
39
  export let show_label = true;
@@ -198,6 +199,11 @@ $:
198
199
  df_actions.handle_sort(-1, "asc");
199
200
  df_actions.reset_sort_state();
200
201
  }
202
+ if ($df_state.filter_state.filter_columns.length > 0) {
203
+ filter_data(data, display_value, styling);
204
+ } else {
205
+ df_actions.reset_filter_state();
206
+ }
201
207
  if ($df_state.current_search_query) {
202
208
  df_actions.handle_search(null);
203
209
  }
@@ -259,12 +265,25 @@ function handle_sort(col, direction) {
259
265
  }
260
266
  function clear_sort() {
261
267
  df_actions.reset_sort_state();
268
+ sort_data(data, display_value, styling);
262
269
  }
263
- $:
270
+ $: {
271
+ if ($df_state.filter_state.filter_columns.length > 0) {
272
+ filter_data(data, display_value, styling);
273
+ }
264
274
  if ($df_state.sort_state.sort_columns.length > 0) {
265
275
  sort_data(data, display_value, styling);
266
276
  df_actions.update_row_order(data);
267
277
  }
278
+ }
279
+ function handle_filter(col, datatype2, filter, value) {
280
+ df_actions.handle_filter(col, datatype2, filter, value);
281
+ filter_data(data, display_value, styling);
282
+ }
283
+ function clear_filter() {
284
+ df_actions.reset_filter_state();
285
+ filter_data(data, display_value, styling);
286
+ }
268
287
  async function edit_header(i, _select = false) {
269
288
  if (!editable || header_edit === i || col_count[1] !== "dynamic")
270
289
  return;
@@ -355,6 +374,9 @@ let last_width_data_length = 0;
355
374
  let last_width_column_count = 0;
356
375
  function set_cell_widths() {
357
376
  const column_count = data[0]?.length || 0;
377
+ if ($df_state.filter_state.filter_columns.length > 0) {
378
+ return;
379
+ }
358
380
  if (last_width_data_length === data.length && last_width_column_count === column_count && $df_state.sort_state.sort_columns.length > 0) {
359
381
  return;
360
382
  }
@@ -401,6 +423,21 @@ function sort_data(_data, _display_value, _styling) {
401
423
  data = result.data;
402
424
  selected = result.selected;
403
425
  }
426
+ function filter_data(_data, _display_value, _styling) {
427
+ const result = filter_data_and_preserve_selection(
428
+ _data,
429
+ _display_value,
430
+ _styling,
431
+ $df_state.filter_state.filter_columns,
432
+ selected,
433
+ get_current_indices,
434
+ $df_state.filter_state.initial_data?.data,
435
+ $df_state.filter_state.initial_data?.display_value,
436
+ $df_state.filter_state.initial_data?.styling
437
+ );
438
+ data = result.data;
439
+ selected = result.selected;
440
+ }
404
441
  $:
405
442
  selected_index = !!selected && selected[0];
406
443
  let is_visible = false;
@@ -656,10 +693,10 @@ function get_cell_display_value(row, col) {
656
693
  {toggle_header_menu}
657
694
  {end_header_edit}
658
695
  sort_columns={$df_state.sort_state.sort_columns}
696
+ filter_columns={$df_state.filter_state.filter_columns}
659
697
  {latex_delimiters}
660
698
  {line_breaks}
661
699
  {max_chars}
662
- {root}
663
700
  {editable}
664
701
  is_static={static_columns.includes(i)}
665
702
  {i18n}
@@ -684,7 +721,6 @@ function get_cell_display_value(row, col) {
684
721
  datatype={Array.isArray(datatype) ? datatype[j] : datatype}
685
722
  edit={false}
686
723
  el={null}
687
- {root}
688
724
  {editable}
689
725
  {i18n}
690
726
  show_selection_buttons={selected_cells.length === 1 &&
@@ -762,10 +798,10 @@ function get_cell_display_value(row, col) {
762
798
  {toggle_header_menu}
763
799
  {end_header_edit}
764
800
  sort_columns={$df_state.sort_state.sort_columns}
801
+ filter_columns={$df_state.filter_state.filter_columns}
765
802
  {latex_delimiters}
766
803
  {line_breaks}
767
804
  {max_chars}
768
- {root}
769
805
  {editable}
770
806
  is_static={static_columns.includes(i)}
771
807
  {i18n}
@@ -803,7 +839,6 @@ function get_cell_display_value(row, col) {
803
839
  datatype={Array.isArray(datatype) ? datatype[j] : datatype}
804
840
  {editing}
805
841
  {max_chars}
806
- {root}
807
842
  {editable}
808
843
  is_static={static_columns.includes(j)}
809
844
  {i18n}
@@ -880,6 +915,25 @@ function get_cell_display_value(row, col) {
880
915
  (item) => item.col === (active_header_menu?.col ?? -1)
881
916
  ) + 1 || null
882
917
  : null}
918
+ on_filter={active_header_menu
919
+ ? (datatype, filter, value) => {
920
+ if (active_header_menu) {
921
+ handle_filter(active_header_menu.col, datatype, filter, value);
922
+ df_actions.set_active_header_menu(null);
923
+ }
924
+ }
925
+ : undefined}
926
+ on_clear_filter={active_header_menu
927
+ ? () => {
928
+ clear_filter();
929
+ df_actions.set_active_header_menu(null);
930
+ }
931
+ : undefined}
932
+ filter_active={active_header_menu
933
+ ? $df_state.filter_state.filter_columns.some(
934
+ (c) => c.col === (active_header_menu?.col ?? -1)
935
+ )
936
+ : null}
883
937
  />
884
938
  {/if}
885
939
 
@@ -20,7 +20,6 @@ export let line_breaks;
20
20
  export let datatype;
21
21
  export let editing;
22
22
  export let max_chars;
23
- export let root;
24
23
  export let editable;
25
24
  export let is_static = false;
26
25
  export let i18n;
@@ -101,7 +100,6 @@ $:
101
100
  }
102
101
  }}
103
102
  on:blur={handle_blur}
104
- {root}
105
103
  {max_chars}
106
104
  {i18n}
107
105
  {components}
@@ -34,7 +34,6 @@ declare const __propDef: {
34
34
  datatype: Datatype;
35
35
  editing: [number, number] | false;
36
36
  max_chars: number | undefined;
37
- root: string;
38
37
  editable: boolean;
39
38
  is_static?: boolean | undefined;
40
39
  i18n: I18nFormatter;
@@ -4,6 +4,7 @@ import { get_sort_status } from "./utils/sort_utils";
4
4
  import Padlock from "./icons/Padlock.svelte";
5
5
  import SortArrowUp from "./icons/SortArrowUp.svelte";
6
6
  import SortArrowDown from "./icons/SortArrowDown.svelte";
7
+ import CellMenuIcons from "./CellMenuIcons.svelte";
7
8
  export let value;
8
9
  export let i;
9
10
  export let actual_pinned_columns;
@@ -15,10 +16,10 @@ export let handle_header_click;
15
16
  export let toggle_header_menu;
16
17
  export let end_header_edit;
17
18
  export let sort_columns = [];
19
+ export let filter_columns = [];
18
20
  export let latex_delimiters;
19
21
  export let line_breaks;
20
22
  export let max_chars;
21
- export let root;
22
23
  export let editable;
23
24
  export let i18n;
24
25
  export let el;
@@ -28,6 +29,8 @@ $:
28
29
  can_add_columns = col_count && col_count[1] === "dynamic";
29
30
  $:
30
31
  sort_index = sort_columns.findIndex((item) => item.col === i);
32
+ $:
33
+ filter_index = filter_columns.findIndex((item) => item.col === i);
31
34
  $:
32
35
  sort_priority = sort_index !== -1 ? sort_index + 1 : null;
33
36
  $:
@@ -51,6 +54,7 @@ function get_header_position(col_index) {
51
54
  class:last-pinned={i === actual_pinned_columns - 1}
52
55
  class:focus={header_edit === i || selected_header === i}
53
56
  class:sorted={sort_index !== -1}
57
+ class:filtered={filter_index !== -1}
54
58
  aria-sort={get_sort_status(value, sort_columns, headers) === "none"
55
59
  ? "none"
56
60
  : get_sort_status(value, sort_columns, headers) === "asc"
@@ -92,7 +96,6 @@ function get_header_position(col_index) {
92
96
  }
93
97
  }}
94
98
  header
95
- {root}
96
99
  {editable}
97
100
  {is_static}
98
101
  {i18n}
@@ -114,6 +117,13 @@ function get_header_position(col_index) {
114
117
  {/if}
115
118
  </div>
116
119
  {/if}
120
+ {#if filter_index !== -1}
121
+ <div class="filter-indicators">
122
+ <span class="filter-icon">
123
+ <CellMenuIcons icon="filter" />
124
+ </span>
125
+ </div>
126
+ {/if}
117
127
  </button>
118
128
  {#if is_static}
119
129
  <Padlock />
@@ -232,6 +242,20 @@ function get_header_position(col_index) {
232
242
  padding: var(--size-1-5);
233
243
  }
234
244
 
245
+ .filter-indicators {
246
+ display: flex;
247
+ align-items: center;
248
+ margin-left: var(--size-1);
249
+ gap: var(--size-1);
250
+ }
251
+
252
+ .filter-icon {
253
+ display: flex;
254
+ align-items: center;
255
+ justify-content: center;
256
+ color: var(--body-text-color);
257
+ }
258
+
235
259
  .pinned-column {
236
260
  position: sticky;
237
261
  z-index: 5;
@@ -1,6 +1,7 @@
1
1
  import { SvelteComponent } from "svelte";
2
2
  import type { I18nFormatter } from "js/core/src/gradio_helper";
3
3
  import type { SortDirection } from "./context/dataframe_context";
4
+ import type { FilterDatatype } from "./context/dataframe_context";
4
5
  declare const __propDef: {
5
6
  props: {
6
7
  value: string;
@@ -17,6 +18,12 @@ declare const __propDef: {
17
18
  col: number;
18
19
  direction: SortDirection;
19
20
  }[] | undefined;
21
+ filter_columns?: {
22
+ col: number;
23
+ datatype: FilterDatatype;
24
+ filter: string;
25
+ value: string;
26
+ }[] | undefined;
20
27
  latex_delimiters: {
21
28
  left: string;
22
29
  right: string;
@@ -24,7 +31,6 @@ declare const __propDef: {
24
31
  }[];
25
32
  line_breaks: boolean;
26
33
  max_chars: number | undefined;
27
- root: string;
28
34
  editable: boolean;
29
35
  i18n: I18nFormatter;
30
36
  el: HTMLInputElement | null;
@@ -2,6 +2,7 @@ import { writable } from "svelte/store";
2
2
  import { get_next_cell_coordinates, get_range_selection, move_cursor } from "../selection_utils";
3
3
  export declare const DATAFRAME_KEY: unique symbol;
4
4
  export type SortDirection = "asc" | "desc";
5
+ export type FilterDatatype = "string" | "number";
5
6
  export type CellCoordinate = [number, number];
6
7
  interface DataFrameState {
7
8
  config: {
@@ -34,6 +35,22 @@ interface DataFrameState {
34
35
  styling: string[][] | null;
35
36
  } | null;
36
37
  };
38
+ filter_state: {
39
+ filter_columns: {
40
+ col: number;
41
+ datatype: FilterDatatype;
42
+ filter: string;
43
+ value: string;
44
+ }[];
45
+ initial_data: {
46
+ data: {
47
+ id: string;
48
+ value: string | number;
49
+ }[][];
50
+ display_value: string[][] | null;
51
+ styling: string[][] | null;
52
+ } | null;
53
+ };
37
54
  ui_state: {
38
55
  active_cell_menu: {
39
56
  row: number;
@@ -62,6 +79,7 @@ interface DataFrameState {
62
79
  interface DataFrameActions {
63
80
  handle_search: (query: string | null) => void;
64
81
  handle_sort: (col: number, direction: SortDirection) => void;
82
+ handle_filter: (col: number, datatype: FilterDatatype, filter: string, value: string) => void;
65
83
  get_sort_status: (name: string, headers: string[]) => "none" | "asc" | "desc";
66
84
  sort_data: (data: any[][], display_value: string[][] | null, styling: string[][] | null) => void;
67
85
  update_row_order: (data: any[][]) => void;
@@ -88,6 +106,7 @@ interface DataFrameActions {
88
106
  };
89
107
  trigger_change: (data: any[][], headers: any[], previous_data: string[][], previous_headers: string[], value_is_output: boolean, dispatch: (e: "change" | "input", detail?: any) => void) => Promise<void>;
90
108
  reset_sort_state: () => void;
109
+ reset_filter_state: () => void;
91
110
  set_active_cell_menu: (menu: {
92
111
  row: number;
93
112
  col: number;
@@ -30,6 +30,11 @@ function create_actions(state, context) {
30
30
  }
31
31
  return { data: new_data, headers: new_headers };
32
32
  };
33
+ const update_array = (source, target) => {
34
+ if (source && target) {
35
+ target.splice(0, target.length, ...JSON.parse(JSON.stringify(source)));
36
+ }
37
+ };
33
38
  return {
34
39
  handle_search: (query) => update_state((s) => ({ current_search_query: query })),
35
40
  handle_sort: (col, direction) => update_state((s) => {
@@ -57,6 +62,33 @@ function create_actions(state, context) {
57
62
  }
58
63
  };
59
64
  }),
65
+ handle_filter: (col, datatype, filter, value) => update_state((s) => {
66
+ const filter_cols = s.filter_state.filter_columns.some((c) => c.col === col)
67
+ ? s.filter_state.filter_columns.filter((c) => c.col !== col)
68
+ : [
69
+ ...s.filter_state.filter_columns,
70
+ { col, datatype, filter, value }
71
+ ];
72
+ const initial_data = s.filter_state.initial_data ||
73
+ (context.data && filter_cols.length > 0
74
+ ? {
75
+ data: JSON.parse(JSON.stringify(context.data)),
76
+ display_value: context.display_value
77
+ ? JSON.parse(JSON.stringify(context.display_value))
78
+ : null,
79
+ styling: context.styling
80
+ ? JSON.parse(JSON.stringify(context.styling))
81
+ : null
82
+ }
83
+ : null);
84
+ return {
85
+ filter_state: {
86
+ ...s.filter_state,
87
+ filter_columns: filter_cols,
88
+ initial_data: initial_data
89
+ }
90
+ };
91
+ }),
60
92
  get_sort_status: (name, headers) => {
61
93
  const s = get(state);
62
94
  const sort_item = s.sort_state.sort_columns.find((item) => headers[item.col] === name);
@@ -127,7 +159,8 @@ function create_actions(state, context) {
127
159
  !dequal(current_headers, previous_headers)) {
128
160
  if (!dequal(current_headers, previous_headers)) {
129
161
  update_state((s) => ({
130
- sort_state: { sort_columns: [], row_order: [], initial_data: null }
162
+ sort_state: { sort_columns: [], row_order: [], initial_data: null },
163
+ filter_state: { filter_columns: [], initial_data: null }
131
164
  }));
132
165
  }
133
166
  dispatch("change", {
@@ -142,11 +175,6 @@ function create_actions(state, context) {
142
175
  reset_sort_state: () => update_state((s) => {
143
176
  if (s.sort_state.initial_data && context.data) {
144
177
  const original = s.sort_state.initial_data;
145
- const update_array = (source, target) => {
146
- if (source && target) {
147
- target.splice(0, target.length, ...JSON.parse(JSON.stringify(source)));
148
- }
149
- };
150
178
  update_array(original.data, context.data);
151
179
  update_array(original.display_value, context.display_value);
152
180
  update_array(original.styling, context.styling);
@@ -155,6 +183,17 @@ function create_actions(state, context) {
155
183
  sort_state: { sort_columns: [], row_order: [], initial_data: null }
156
184
  };
157
185
  }),
186
+ reset_filter_state: () => update_state((s) => {
187
+ if (s.filter_state.initial_data && context.data) {
188
+ const original = s.filter_state.initial_data;
189
+ update_array(original.data, context.data);
190
+ update_array(original.display_value, context.display_value);
191
+ update_array(original.styling, context.styling);
192
+ }
193
+ return {
194
+ filter_state: { filter_columns: [], initial_data: null }
195
+ };
196
+ }),
158
197
  set_active_cell_menu: (menu) => update_state((s) => ({
159
198
  ui_state: { ...s.ui_state, active_cell_menu: menu }
160
199
  })),
@@ -341,6 +380,7 @@ export function create_dataframe_context(config) {
341
380
  config,
342
381
  current_search_query: null,
343
382
  sort_state: { sort_columns: [], row_order: [], initial_data: null },
383
+ filter_state: { filter_columns: [], initial_data: null },
344
384
  ui_state: {
345
385
  active_cell_menu: null,
346
386
  active_header_menu: null,
@@ -0,0 +1,28 @@
1
+ export type FilterDatatype = "string" | "number";
2
+ export declare function filter_data(data: {
3
+ id: string;
4
+ value: string | number;
5
+ }[][], filter_columns: {
6
+ col: number;
7
+ datatype: FilterDatatype;
8
+ filter: string;
9
+ value: string;
10
+ }[]): number[];
11
+ export declare function filter_data_and_preserve_selection(data: {
12
+ id: string;
13
+ value: string | number;
14
+ }[][], display_value: string[][] | null, styling: string[][] | null, filter_columns: {
15
+ col: number;
16
+ datatype: FilterDatatype;
17
+ filter: string;
18
+ value: string;
19
+ }[], selected: [number, number] | false, get_current_indices: (id: string, data: {
20
+ id: string;
21
+ value: string | number;
22
+ }[][]) => [number, number], original_data?: {
23
+ id: string;
24
+ value: string | number;
25
+ }[][], original_display_value?: string[][] | null, original_styling?: string[][] | null): {
26
+ data: typeof data;
27
+ selected: [number, number] | false;
28
+ };
@@ -0,0 +1,123 @@
1
+ import { filter_table_data } from "./table_utils";
2
+ export function filter_data(data, filter_columns) {
3
+ if (!data || !data.length || !data[0]) {
4
+ return [];
5
+ }
6
+ let row_indices = [...Array(data.length)].map((_, i) => i);
7
+ if (filter_columns.length > 0) {
8
+ filter_columns.forEach((column) => {
9
+ if (column.datatype === "string") {
10
+ switch (column.filter) {
11
+ case "Contains":
12
+ row_indices = row_indices.filter((i) => data[i][column.col]?.value.toString().includes(column.value));
13
+ break;
14
+ case "Does not contain":
15
+ row_indices = row_indices.filter((i) => !data[i][column.col]?.value.toString().includes(column.value));
16
+ break;
17
+ case "Starts with":
18
+ row_indices = row_indices.filter((i) => data[i][column.col]?.value.toString().startsWith(column.value));
19
+ break;
20
+ case "Ends with":
21
+ row_indices = row_indices.filter((i) => data[i][column.col]?.value.toString().endsWith(column.value));
22
+ break;
23
+ case "Is":
24
+ row_indices = row_indices.filter((i) => data[i][column.col]?.value.toString() === column.value);
25
+ break;
26
+ case "Is not":
27
+ row_indices = row_indices.filter((i) => !(data[i][column.col]?.value.toString() === column.value));
28
+ break;
29
+ case "Is empty":
30
+ row_indices = row_indices.filter((i) => data[i][column.col]?.value.toString() === "");
31
+ break;
32
+ case "Is not empty":
33
+ row_indices = row_indices.filter((i) => !(data[i][column.col]?.value.toString() === ""));
34
+ break;
35
+ }
36
+ }
37
+ else if (column.datatype === "number") {
38
+ switch (column.filter) {
39
+ case "=":
40
+ row_indices = row_indices.filter((i) => {
41
+ if (!isNaN(Number(data[i][column.col]?.value)) &&
42
+ !isNaN(Number(column.value))) {
43
+ return (Number(data[i][column.col]?.value) === Number(column.value));
44
+ }
45
+ return false;
46
+ });
47
+ break;
48
+ case "≠":
49
+ row_indices = row_indices.filter((i) => {
50
+ if (!isNaN(Number(data[i][column.col]?.value)) &&
51
+ !isNaN(Number(column.value))) {
52
+ return !(Number(data[i][column.col]?.value) === Number(column.value));
53
+ }
54
+ return false;
55
+ });
56
+ break;
57
+ case ">":
58
+ row_indices = row_indices.filter((i) => {
59
+ if (!isNaN(Number(data[i][column.col]?.value)) &&
60
+ !isNaN(Number(column.value))) {
61
+ return (Number(data[i][column.col]?.value) > Number(column.value));
62
+ }
63
+ return false;
64
+ });
65
+ break;
66
+ case "<":
67
+ row_indices = row_indices.filter((i) => {
68
+ if (!isNaN(Number(data[i][column.col]?.value)) &&
69
+ !isNaN(Number(column.value))) {
70
+ return (Number(data[i][column.col]?.value) < Number(column.value));
71
+ }
72
+ return false;
73
+ });
74
+ break;
75
+ case "≥":
76
+ row_indices = row_indices.filter((i) => {
77
+ if (!isNaN(Number(data[i][column.col]?.value)) &&
78
+ !isNaN(Number(column.value))) {
79
+ return (Number(data[i][column.col]?.value) >= Number(column.value));
80
+ }
81
+ return false;
82
+ });
83
+ break;
84
+ case "≤":
85
+ row_indices = row_indices.filter((i) => {
86
+ if (!isNaN(Number(data[i][column.col]?.value)) &&
87
+ !isNaN(Number(column.value))) {
88
+ return (Number(data[i][column.col]?.value) <= Number(column.value));
89
+ }
90
+ return false;
91
+ });
92
+ break;
93
+ case "Is empty":
94
+ row_indices = row_indices.filter((i) => data[i][column.col]?.value.toString() === "");
95
+ break;
96
+ case "Is not empty":
97
+ row_indices = row_indices.filter((i) => {
98
+ if (!isNaN(Number(data[i][column.col]?.value))) {
99
+ return !(data[i][column.col]?.value.toString() === "");
100
+ }
101
+ return false;
102
+ });
103
+ break;
104
+ }
105
+ }
106
+ });
107
+ return row_indices;
108
+ }
109
+ return [...Array(data.length)].map((_, i) => i);
110
+ }
111
+ export function filter_data_and_preserve_selection(data, display_value, styling, filter_columns, selected, get_current_indices, original_data, original_display_value, original_styling) {
112
+ let id = null;
113
+ if (selected && selected[0] in data && selected[1] in data[selected[0]]) {
114
+ id = data[selected[0]][selected[1]].id;
115
+ }
116
+ filter_table_data(data, display_value, styling, filter_columns, original_data, original_display_value, original_styling);
117
+ let new_selected = selected;
118
+ if (id) {
119
+ const [i, j] = get_current_indices(id, data);
120
+ new_selected = [i, j];
121
+ }
122
+ return { data, selected: new_selected };
123
+ }
@@ -1,5 +1,6 @@
1
1
  import type { Headers, HeadersWithIDs, TableCell, TableData } from "../types";
2
2
  import type { SortDirection } from "./sort_utils";
3
+ import type { FilterDatatype } from "./filter_utils";
3
4
  export declare function make_cell_id(row: number, col: number): string;
4
5
  export declare function make_header_id(col: number): string;
5
6
  export declare function get_max(data: TableData): TableCell[];
@@ -7,6 +8,12 @@ export declare function sort_table_data(data: TableData, display_value: string[]
7
8
  col: number;
8
9
  direction: SortDirection;
9
10
  }[]): void;
11
+ export declare function filter_table_data(data: TableData, display_value: string[][] | null, styling: string[][] | null, filter_columns: {
12
+ col: number;
13
+ datatype: FilterDatatype;
14
+ filter: string;
15
+ value: string;
16
+ }[], original_data?: TableData, original_display_value?: string[][] | null, original_styling?: string[][] | null): void;
10
17
  export declare function copy_table_data(data: TableData, selected_cells: [number, number][] | null): Promise<void>;
11
18
  export declare function guess_delimiter(text: string, possibleDelimiters: string[]): string[];
12
19
  export declare function data_uri_to_blob(data_uri: string): Blob;
@@ -1,4 +1,5 @@
1
1
  import { sort_data } from "./sort_utils";
2
+ import { filter_data } from "./filter_utils";
2
3
  import { dsvFormat } from "d3-dsv";
3
4
  export function make_cell_id(row, col) {
4
5
  return `cell-${row}-${col}`;
@@ -36,6 +37,34 @@ export function sort_table_data(data, display_value, styling, sort_columns) {
36
37
  styling.splice(0, styling.length, ...new_styling);
37
38
  }
38
39
  }
40
+ export function filter_table_data(data, display_value, styling, filter_columns, original_data, original_display_value, original_styling) {
41
+ const base_data = original_data ?? data;
42
+ const base_display_value = original_display_value ?? display_value;
43
+ const base_styling = original_styling ?? styling;
44
+ if (!filter_columns.length) {
45
+ data.splice(0, data.length, ...base_data.map((row) => [...row]));
46
+ if (display_value && base_display_value) {
47
+ display_value.splice(0, display_value.length, ...base_display_value.map((row) => [...row]));
48
+ }
49
+ if (styling && base_styling) {
50
+ styling.splice(0, styling.length, ...base_styling.map((row) => [...row]));
51
+ }
52
+ return;
53
+ }
54
+ if (!data || !data.length)
55
+ return;
56
+ const indices = filter_data(base_data, filter_columns);
57
+ const new_data = indices.map((i) => base_data[i]);
58
+ data.splice(0, data.length, ...new_data);
59
+ if (display_value && base_display_value) {
60
+ const new_display = indices.map((i) => base_display_value[i]);
61
+ display_value.splice(0, display_value.length, ...new_display);
62
+ }
63
+ if (styling && base_styling) {
64
+ const new_styling = indices.map((i) => base_styling[i]);
65
+ styling.splice(0, styling.length, ...new_styling);
66
+ }
67
+ }
39
68
  export async function copy_table_data(data, selected_cells) {
40
69
  if (!data || !data.length)
41
70
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradio/dataframe",
3
- "version": "0.17.16",
3
+ "version": "0.18.0",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "author": "",
@@ -17,15 +17,15 @@
17
17
  "dompurify": "^3.0.3",
18
18
  "katex": "^0.16.7",
19
19
  "marked": "^12.0.0",
20
- "@gradio/atoms": "^0.16.1",
21
- "@gradio/button": "^0.5.3",
20
+ "@gradio/atoms": "^0.16.2",
21
+ "@gradio/checkbox": "^0.4.24",
22
+ "@gradio/client": "^1.15.4",
23
+ "@gradio/button": "^0.5.5",
24
+ "@gradio/statustracker": "^0.10.13",
22
25
  "@gradio/icons": "^0.12.0",
23
- "@gradio/statustracker": "^0.10.12",
24
- "@gradio/checkbox": "^0.4.23",
25
- "@gradio/upload": "^0.16.7",
26
- "@gradio/markdown-code": "^0.4.3",
27
- "@gradio/client": "^1.15.2",
28
- "@gradio/utils": "^0.10.2"
26
+ "@gradio/upload": "^0.16.9",
27
+ "@gradio/utils": "^0.10.2",
28
+ "@gradio/markdown-code": "^0.4.4"
29
29
  },
30
30
  "exports": {
31
31
  ".": {