@gradio/dataframe 0.17.17 → 0.18.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 (40) 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 +16 -20
  10. package/dist/shared/EditableCell.svelte.d.ts +1 -2
  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 -1
  14. package/dist/shared/TableCell.svelte.d.ts +1 -1
  15. package/dist/shared/TableHeader.svelte +26 -0
  16. package/dist/shared/TableHeader.svelte.d.ts +8 -1
  17. package/dist/shared/context/dataframe_context.d.ts +20 -1
  18. package/dist/shared/context/dataframe_context.js +46 -6
  19. package/dist/shared/types.d.ts +1 -1
  20. package/dist/shared/utils/data_processing.d.ts +2 -2
  21. package/dist/shared/utils/filter_utils.d.ts +28 -0
  22. package/dist/shared/utils/filter_utils.js +123 -0
  23. package/dist/shared/utils/keyboard_utils.js +5 -1
  24. package/dist/shared/utils/table_utils.d.ts +7 -0
  25. package/dist/shared/utils/table_utils.js +29 -0
  26. package/package.json +10 -10
  27. package/shared/CellMenu.svelte +45 -1
  28. package/shared/CellMenuIcons.svelte +48 -0
  29. package/shared/EditableCell.svelte +18 -25
  30. package/shared/FilterMenu.svelte +248 -0
  31. package/shared/Table.svelte +79 -5
  32. package/shared/TableCell.svelte +1 -1
  33. package/shared/TableHeader.svelte +32 -1
  34. package/shared/Toolbar.svelte +1 -1
  35. package/shared/context/dataframe_context.ts +81 -18
  36. package/shared/types.ts +1 -1
  37. package/shared/utils/data_processing.ts +2 -2
  38. package/shared/utils/filter_utils.ts +207 -0
  39. package/shared/utils/keyboard_utils.ts +5 -2
  40. package/shared/utils/table_utils.ts +52 -0
@@ -1,8 +1,12 @@
1
1
  <script lang="ts">
2
2
  import { onMount } from "svelte";
3
3
  import CellMenuIcons from "./CellMenuIcons.svelte";
4
+ import FilterMenu from "./FilterMenu.svelte";
4
5
  import type { I18nFormatter } from "js/utils/src";
5
- import type { SortDirection } from "./context/dataframe_context";
6
+ import type {
7
+ SortDirection,
8
+ FilterDatatype
9
+ } from "./context/dataframe_context";
6
10
 
7
11
  export let x: number;
8
12
  export let y: number;
@@ -21,10 +25,18 @@
21
25
  export let on_clear_sort: () => void = () => {};
22
26
  export let sort_direction: SortDirection | null = null;
23
27
  export let sort_priority: number | null = null;
28
+ export let on_filter: (
29
+ datatype: FilterDatatype,
30
+ selected_filter: string,
31
+ value: string
32
+ ) => void = () => {};
33
+ export let on_clear_filter: () => void = () => {};
34
+ export let filter_active: boolean | null = null;
24
35
  export let editable = true;
25
36
 
26
37
  export let i18n: I18nFormatter;
27
38
  let menu_element: HTMLDivElement;
39
+ let active_filter_menu: { x: number; y: number } | null = null;
28
40
 
29
41
  $: is_header = row === -1;
30
42
  $: can_add_rows = editable && row_count[1] === "dynamic";
@@ -55,6 +67,19 @@
55
67
  menu_element.style.left = `${new_x}px`;
56
68
  menu_element.style.top = `${new_y}px`;
57
69
  }
70
+
71
+ function toggle_filter_menu(): void {
72
+ if (filter_active) {
73
+ on_filter("string", "", "");
74
+ return;
75
+ }
76
+
77
+ const menu_rect = menu_element.getBoundingClientRect();
78
+ active_filter_menu = {
79
+ x: menu_rect.right,
80
+ y: menu_rect.top + menu_rect.height / 2
81
+ };
82
+ }
58
83
  </script>
59
84
 
60
85
  <div bind:this={menu_element} class="cell-menu" role="menu">
@@ -85,6 +110,21 @@
85
110
  <CellMenuIcons icon="clear-sort" />
86
111
  {i18n("dataframe.clear_sort")}
87
112
  </button>
113
+ <button
114
+ role="menuitem"
115
+ on:click|stopPropagation={toggle_filter_menu}
116
+ class:active={filter_active || active_filter_menu}
117
+ >
118
+ <CellMenuIcons icon="filter" />
119
+ {i18n("dataframe.filter")}
120
+ {#if filter_active}
121
+ <span class="priority">1</span>
122
+ {/if}
123
+ </button>
124
+ <button role="menuitem" on:click={on_clear_filter}>
125
+ <CellMenuIcons icon="clear-filter" />
126
+ {i18n("dataframe.clear_filter")}
127
+ </button>
88
128
  {/if}
89
129
 
90
130
  {#if !is_header && can_add_rows}
@@ -147,6 +187,10 @@
147
187
  {/if}
148
188
  </div>
149
189
 
190
+ {#if active_filter_menu}
191
+ <FilterMenu {on_filter} />
192
+ {/if}
193
+
150
194
  <style>
151
195
  .cell-menu {
152
196
  position: fixed;
@@ -189,4 +189,52 @@
189
189
  stroke-linecap="round"
190
190
  />
191
191
  </svg>
192
+ {:else if icon == "filter"}
193
+ <svg viewBox="0 0 24 24" width="16" height="16">
194
+ <path
195
+ d="M5 5H19"
196
+ stroke="currentColor"
197
+ stroke-width="2"
198
+ stroke-linecap="round"
199
+ />
200
+ <path
201
+ d="M8 9H16"
202
+ stroke="currentColor"
203
+ stroke-width="2"
204
+ stroke-linecap="round"
205
+ />
206
+ <path
207
+ d="M11 13H13"
208
+ stroke="currentColor"
209
+ stroke-width="2"
210
+ stroke-linecap="round"
211
+ />
212
+ </svg>
213
+ {:else if icon == "clear-filter"}
214
+ <svg viewBox="0 0 24 24" width="16" height="16">
215
+ <path
216
+ d="M5 5H19"
217
+ stroke="currentColor"
218
+ stroke-width="2"
219
+ stroke-linecap="round"
220
+ />
221
+ <path
222
+ d="M8 9H16"
223
+ stroke="currentColor"
224
+ stroke-width="2"
225
+ stroke-linecap="round"
226
+ />
227
+ <path
228
+ d="M11 13H13"
229
+ stroke="currentColor"
230
+ stroke-width="2"
231
+ stroke-linecap="round"
232
+ />
233
+ <path
234
+ d="M17 17L21 21M21 17L17 21"
235
+ stroke="currentColor"
236
+ stroke-width="2"
237
+ stroke-linecap="round"
238
+ />
239
+ </svg>
192
240
  {/if}
@@ -36,15 +36,13 @@
36
36
  export let coords: [number, number];
37
37
  export let on_select_column: ((col: number) => void) | null = null;
38
38
  export let on_select_row: ((row: number) => void) | null = null;
39
- export let el: HTMLInputElement | null;
39
+ export let el: HTMLTextAreaElement | null;
40
40
 
41
41
  const dispatch = createEventDispatcher<{
42
42
  blur: { blur_event: FocusEvent; coords: [number, number] };
43
43
  keydown: KeyboardEvent;
44
44
  }>();
45
45
 
46
- let is_expanded = false;
47
-
48
46
  function truncate_text(
49
47
  text: string | number,
50
48
  max_length: number | null = null,
@@ -57,8 +55,7 @@
57
55
  return str.slice(0, max_length) + "...";
58
56
  }
59
57
 
60
- $: should_truncate =
61
- !edit && !is_expanded && max_chars !== null && max_chars > 0;
58
+ $: should_truncate = !edit && max_chars !== null && max_chars > 0;
62
59
 
63
60
  $: display_content = editable
64
61
  ? value
@@ -70,7 +67,7 @@
70
67
  ? truncate_text(display_content, max_chars, datatype === "image")
71
68
  : display_content;
72
69
 
73
- function use_focus(node: HTMLInputElement): any {
70
+ function use_focus(node: HTMLTextAreaElement): any {
74
71
  requestAnimationFrame(() => {
75
72
  node.focus();
76
73
  });
@@ -86,20 +83,9 @@
86
83
  }
87
84
 
88
85
  function handle_keydown(event: KeyboardEvent): void {
89
- if (event.key === "Enter") {
90
- if (!header) {
91
- is_expanded = !is_expanded;
92
- }
93
- }
94
86
  dispatch("keydown", event);
95
87
  }
96
88
 
97
- function handle_click(): void {
98
- if (!edit && !header) {
99
- is_expanded = !is_expanded;
100
- }
101
- }
102
-
103
89
  function handle_bool_change(new_value: boolean): void {
104
90
  value = new_value.toString();
105
91
  dispatch("blur", {
@@ -116,10 +102,9 @@
116
102
  </script>
117
103
 
118
104
  {#if edit && datatype !== "bool"}
119
- <input
105
+ <textarea
120
106
  readonly={is_static}
121
107
  aria-readonly={is_static}
122
- role="textbox"
123
108
  aria-label={is_static ? "Cell is read-only" : "Edit cell"}
124
109
  bind:this={el}
125
110
  bind:value
@@ -127,7 +112,6 @@
127
112
  tabindex="-1"
128
113
  on:blur={handle_blur}
129
114
  on:mousedown|stopPropagation
130
- on:mouseup|stopPropagation
131
115
  on:click|stopPropagation
132
116
  use:use_focus
133
117
  on:keydown={handle_keydown}
@@ -143,18 +127,17 @@
143
127
  {:else}
144
128
  <span
145
129
  class:dragging={is_dragging}
146
- on:click={handle_click}
147
130
  on:keydown={handle_keydown}
148
131
  tabindex="0"
149
132
  role="button"
150
133
  class:edit
151
- class:expanded={is_expanded}
134
+ class:expanded={edit}
152
135
  class:multiline={header}
153
136
  on:focus|preventDefault
154
137
  style={styling}
155
138
  data-editable={editable}
156
139
  data-max-chars={max_chars}
157
- data-expanded={is_expanded}
140
+ data-expanded={edit}
158
141
  placeholder=" "
159
142
  class:text={datatype === "str"}
160
143
  class:wrap={wrap_text}
@@ -202,7 +185,7 @@
202
185
  cursor: crosshair !important;
203
186
  }
204
187
 
205
- input {
188
+ textarea {
206
189
  position: absolute;
207
190
  flex: 1 1 0%;
208
191
  transform: translateX(-0.1px);
@@ -211,6 +194,16 @@
211
194
  background: transparent;
212
195
  cursor: text;
213
196
  width: calc(100% - var(--size-2));
197
+ resize: none;
198
+ height: 100%;
199
+ padding-left: 0;
200
+ font-size: inherit;
201
+ font-weight: inherit;
202
+ line-height: var(--line-lg);
203
+ }
204
+
205
+ textarea:focus {
206
+ outline: none;
214
207
  }
215
208
 
216
209
  span {
@@ -262,7 +255,7 @@
262
255
  object-fit: contain;
263
256
  }
264
257
 
265
- input:read-only {
258
+ textarea:read-only {
266
259
  cursor: not-allowed;
267
260
  }
268
261
 
@@ -0,0 +1,248 @@
1
+ <script lang="ts">
2
+ import { onMount } from "svelte";
3
+ import { Check } from "@gradio/icons";
4
+ import DropdownArrow from "../../icons/src/DropdownArrow.svelte";
5
+ import type { FilterDatatype } from "./context/dataframe_context";
6
+
7
+ export let on_filter: (
8
+ datatype: FilterDatatype,
9
+ selected_filter: string,
10
+ value: string
11
+ ) => void = () => {};
12
+
13
+ let menu_element: HTMLDivElement;
14
+ let datatype: "string" | "number" = "string";
15
+ let current_filter = "Contains";
16
+ let filter_dropdown_open = false;
17
+ let filter_input_value = "";
18
+
19
+ const filter_options = {
20
+ string: [
21
+ "Contains",
22
+ "Does not contain",
23
+ "Starts with",
24
+ "Ends with",
25
+ "Is",
26
+ "Is not",
27
+ "Is empty",
28
+ "Is not empty"
29
+ ],
30
+ number: ["=", "≠", ">", "<", "≥", "≤", "Is empty", "Is not empty"]
31
+ };
32
+
33
+ onMount(() => {
34
+ position_menu();
35
+ });
36
+
37
+ function position_menu(): void {
38
+ if (!menu_element) return;
39
+
40
+ const viewport_width = window.innerWidth;
41
+ const viewport_height = window.innerHeight;
42
+ const menu_rect = menu_element.getBoundingClientRect();
43
+
44
+ const x = (viewport_width - menu_rect.width) / 2;
45
+ const y = (viewport_height - menu_rect.height) / 2;
46
+
47
+ menu_element.style.left = `${x}px`;
48
+ menu_element.style.top = `${y}px`;
49
+ }
50
+
51
+ function handle_filter_input(e: Event): void {
52
+ const target = e.target as HTMLInputElement;
53
+ filter_input_value = target.value;
54
+ }
55
+ </script>
56
+
57
+ <div>
58
+ <div class="background"></div>
59
+ <div bind:this={menu_element} class="filter-menu">
60
+ <div class="filter-datatype-container">
61
+ <span>Filter as</span>
62
+ <button
63
+ on:click|stopPropagation={() => {
64
+ datatype = datatype === "string" ? "number" : "string";
65
+ current_filter = filter_options[datatype][0];
66
+ }}
67
+ aria-label={`Change filter type. Filtering ${datatype}s`}
68
+ >
69
+ {datatype}
70
+ </button>
71
+ </div>
72
+
73
+ <div class="input-container">
74
+ <div class="filter-dropdown">
75
+ <button
76
+ on:click|stopPropagation={() =>
77
+ (filter_dropdown_open = !filter_dropdown_open)}
78
+ aria-label={`Change filter. Using '${current_filter}'`}
79
+ >
80
+ {current_filter}
81
+ <DropdownArrow />
82
+ </button>
83
+
84
+ {#if filter_dropdown_open}
85
+ <div class="dropdown-filter-options">
86
+ {#each filter_options[datatype] as opt}
87
+ <button
88
+ on:click|stopPropagation={() => {
89
+ current_filter = opt;
90
+ filter_dropdown_open = !filter_dropdown_open;
91
+ }}
92
+ class="filter-option"
93
+ >
94
+ {opt}
95
+ </button>
96
+ {/each}
97
+ </div>
98
+ {/if}
99
+ </div>
100
+
101
+ <input
102
+ type="text"
103
+ value={filter_input_value}
104
+ on:click|stopPropagation
105
+ on:input={handle_filter_input}
106
+ placeholder="Type a value"
107
+ class="filter-input"
108
+ />
109
+ </div>
110
+
111
+ <button
112
+ class="check-button"
113
+ on:click={() => on_filter(datatype, current_filter, filter_input_value)}
114
+ >
115
+ <Check />
116
+ </button>
117
+ </div>
118
+ </div>
119
+
120
+ <style>
121
+ .background {
122
+ position: fixed;
123
+ top: 0;
124
+ left: 0;
125
+ width: 100vw;
126
+ height: 100vh;
127
+ background-color: rgba(0, 0, 0, 0.4);
128
+ z-index: 20;
129
+ }
130
+
131
+ .filter-menu {
132
+ position: fixed;
133
+ background: var(--background-fill-primary);
134
+ border: 1px solid var(--border-color-primary);
135
+ border-radius: var(--radius-sm);
136
+ padding: var(--size-2);
137
+ display: flex;
138
+ flex-direction: column;
139
+ gap: var(--size-2);
140
+ box-shadow: var(--shadow-drop-lg);
141
+ width: 300px;
142
+ z-index: 21;
143
+ }
144
+
145
+ .filter-datatype-container {
146
+ display: flex;
147
+ gap: var(--size-2);
148
+ align-items: center;
149
+ }
150
+
151
+ .filter-menu span {
152
+ font-size: var(--text-sm);
153
+ color: var(--body-text-color);
154
+ }
155
+
156
+ .filter-menu button {
157
+ height: var(--size-6);
158
+ background: none;
159
+ border: 1px solid var(--border-color-primary);
160
+ border-radius: var(--radius-sm);
161
+ padding: var(--size-1) var(--size-2);
162
+ color: var(--body-text-color);
163
+ font-size: var(--text-sm);
164
+ cursor: pointer;
165
+ display: flex;
166
+ align-items: center;
167
+ justify-content: center;
168
+ gap: var(--size-2);
169
+ }
170
+
171
+ .filter-menu button:hover {
172
+ background-color: var(--background-fill-secondary);
173
+ }
174
+
175
+ .filter-input {
176
+ width: var(--size-full);
177
+ height: var(--size-6);
178
+ padding: var(--size-2);
179
+ padding-right: var(--size-8);
180
+ border: 1px solid var(--border-color-primary);
181
+ border-radius: var(--table-radius);
182
+ font-size: var(--text-sm);
183
+ color: var(--body-text-color);
184
+ background: var(--background-fill-secondary);
185
+ transition: all 0.2s ease;
186
+ }
187
+
188
+ .filter-input:hover {
189
+ border-color: var(--border-color-secondary);
190
+ background: var(--background-fill-primary);
191
+ }
192
+
193
+ .filter-input:focus {
194
+ outline: none;
195
+ border-color: var(--color-accent);
196
+ background: var(--background-fill-primary);
197
+ box-shadow: 0 0 0 1px var(--color-accent);
198
+ }
199
+
200
+ .dropdown-filter-options {
201
+ display: flex;
202
+ flex-direction: column;
203
+ background: var(--background-fill-primary);
204
+ border: 1px solid var(--border-color-primary);
205
+ border-radius: var(--radius-sm);
206
+ box-shadow: var(--shadow-drop-md);
207
+ position: absolute;
208
+ z-index: var(--layer-1);
209
+ }
210
+
211
+ .dropdown-filter-options .filter-option {
212
+ border: none;
213
+ justify-content: flex-start;
214
+ }
215
+
216
+ .input-container {
217
+ display: flex;
218
+ gap: var(--size-2);
219
+ align-items: center;
220
+ }
221
+
222
+ .input-container button {
223
+ width: 130px;
224
+ }
225
+
226
+ :global(svg.dropdown-arrow) {
227
+ width: var(--size-4);
228
+ height: var(--size-4);
229
+ margin-left: auto;
230
+ }
231
+
232
+ .filter-menu .check-button {
233
+ background: var(--color-accent);
234
+ color: white;
235
+ border: none;
236
+ width: var(--size-full);
237
+ height: var(--size-6);
238
+ border-radius: var(--radius-sm);
239
+ display: flex;
240
+ align-items: center;
241
+ justify-content: center;
242
+ padding: var(--size-1);
243
+ }
244
+
245
+ .check-button:hover {
246
+ background: var(--color-accent-soft);
247
+ }
248
+ </style>
@@ -1,7 +1,8 @@
1
1
  <script lang="ts" context="module">
2
2
  import {
3
3
  create_dataframe_context,
4
- type SortDirection
4
+ type SortDirection,
5
+ type FilterDatatype
5
6
  } from "./context/dataframe_context";
6
7
  </script>
7
8
 
@@ -43,6 +44,7 @@
43
44
  type DragHandlers
44
45
  } from "./utils/drag_utils";
45
46
  import { sort_data_and_preserve_selection } from "./utils/sort_utils";
47
+ import { filter_data_and_preserve_selection } from "./utils/filter_utils";
46
48
 
47
49
  export let datatype: Datatype | Datatype[];
48
50
  export let label: string | null = null;
@@ -163,7 +165,7 @@
163
165
 
164
166
  let els: Record<
165
167
  string,
166
- { cell: null | HTMLTableCellElement; input: null | HTMLInputElement }
168
+ { cell: null | HTMLTableCellElement; input: null | HTMLTextAreaElement }
167
169
  > = {};
168
170
  let data_binding: Record<string, (typeof data)[0][0]> = {};
169
171
  let _headers = make_headers(headers, col_count, els, make_id);
@@ -261,6 +263,12 @@
261
263
  df_actions.reset_sort_state();
262
264
  }
263
265
 
266
+ if ($df_state.filter_state.filter_columns.length > 0) {
267
+ filter_data(data, display_value, styling);
268
+ } else {
269
+ df_actions.reset_filter_state();
270
+ }
271
+
264
272
  if ($df_state.current_search_query) {
265
273
  df_actions.handle_search(null);
266
274
  }
@@ -340,11 +348,33 @@
340
348
 
341
349
  function clear_sort(): void {
342
350
  df_actions.reset_sort_state();
351
+ sort_data(data, display_value, styling);
343
352
  }
344
353
 
345
- $: if ($df_state.sort_state.sort_columns.length > 0) {
346
- sort_data(data, display_value, styling);
347
- df_actions.update_row_order(data);
354
+ $: {
355
+ if ($df_state.filter_state.filter_columns.length > 0) {
356
+ filter_data(data, display_value, styling);
357
+ }
358
+
359
+ if ($df_state.sort_state.sort_columns.length > 0) {
360
+ sort_data(data, display_value, styling);
361
+ df_actions.update_row_order(data);
362
+ }
363
+ }
364
+
365
+ function handle_filter(
366
+ col: number,
367
+ datatype: FilterDatatype,
368
+ filter: string,
369
+ value: string
370
+ ): void {
371
+ df_actions.handle_filter(col, datatype, filter, value);
372
+ filter_data(data, display_value, styling);
373
+ }
374
+
375
+ function clear_filter(): void {
376
+ df_actions.reset_filter_state();
377
+ filter_data(data, display_value, styling);
348
378
  }
349
379
 
350
380
  async function edit_header(i: number, _select = false): Promise<void> {
@@ -449,6 +479,9 @@
449
479
 
450
480
  function set_cell_widths(): void {
451
481
  const column_count = data[0]?.length || 0;
482
+ if ($df_state.filter_state.filter_columns.length > 0) {
483
+ return;
484
+ }
452
485
  if (
453
486
  last_width_data_length === data.length &&
454
487
  last_width_column_count === column_count &&
@@ -513,6 +546,26 @@
513
546
  selected = result.selected;
514
547
  }
515
548
 
549
+ function filter_data(
550
+ _data: typeof data,
551
+ _display_value: string[][] | null,
552
+ _styling: string[][] | null
553
+ ): void {
554
+ const result = filter_data_and_preserve_selection(
555
+ _data,
556
+ _display_value,
557
+ _styling,
558
+ $df_state.filter_state.filter_columns,
559
+ selected,
560
+ get_current_indices,
561
+ $df_state.filter_state.initial_data?.data,
562
+ $df_state.filter_state.initial_data?.display_value,
563
+ $df_state.filter_state.initial_data?.styling
564
+ );
565
+ data = result.data;
566
+ selected = result.selected;
567
+ }
568
+
516
569
  $: selected_index = !!selected && selected[0];
517
570
 
518
571
  let is_visible = false;
@@ -802,6 +855,7 @@
802
855
  {toggle_header_menu}
803
856
  {end_header_edit}
804
857
  sort_columns={$df_state.sort_state.sort_columns}
858
+ filter_columns={$df_state.filter_state.filter_columns}
805
859
  {latex_delimiters}
806
860
  {line_breaks}
807
861
  {max_chars}
@@ -906,6 +960,7 @@
906
960
  {toggle_header_menu}
907
961
  {end_header_edit}
908
962
  sort_columns={$df_state.sort_state.sort_columns}
963
+ filter_columns={$df_state.filter_state.filter_columns}
909
964
  {latex_delimiters}
910
965
  {line_breaks}
911
966
  {max_chars}
@@ -1022,6 +1077,25 @@
1022
1077
  (item) => item.col === (active_header_menu?.col ?? -1)
1023
1078
  ) + 1 || null
1024
1079
  : null}
1080
+ on_filter={active_header_menu
1081
+ ? (datatype, filter, value) => {
1082
+ if (active_header_menu) {
1083
+ handle_filter(active_header_menu.col, datatype, filter, value);
1084
+ df_actions.set_active_header_menu(null);
1085
+ }
1086
+ }
1087
+ : undefined}
1088
+ on_clear_filter={active_header_menu
1089
+ ? () => {
1090
+ clear_filter();
1091
+ df_actions.set_active_header_menu(null);
1092
+ }
1093
+ : undefined}
1094
+ filter_active={active_header_menu
1095
+ ? $df_state.filter_state.filter_columns.some(
1096
+ (c) => c.col === (active_header_menu?.col ?? -1)
1097
+ )
1098
+ : null}
1025
1099
  />
1026
1100
  {/if}
1027
1101
 
@@ -59,7 +59,7 @@
59
59
  export let components: Record<string, any> = {};
60
60
  export let el: {
61
61
  cell: HTMLTableCellElement | null;
62
- input: HTMLInputElement | null;
62
+ input: HTMLTextAreaElement | null;
63
63
  };
64
64
  export let handle_select_column: (col: number) => void;
65
65
  export let handle_select_row: (row: number) => void;