@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,39 +1,59 @@
1
- export function get_sort_status(name, sort_by, direction, headers) {
2
- if (typeof sort_by !== "number")
1
+ import { sort_table_data } from "./table_utils";
2
+ export function get_sort_status(name, sort_columns, headers) {
3
+ if (!sort_columns.length)
3
4
  return "none";
4
- if (sort_by < 0 || sort_by >= headers.length)
5
+ const sort_item = sort_columns.find((item) => {
6
+ const col = item.col;
7
+ if (col < 0 || col >= headers.length)
8
+ return false;
9
+ return headers[col] === name;
10
+ });
11
+ if (!sort_item)
5
12
  return "none";
6
- if (headers[sort_by] === name) {
7
- if (direction === "asc")
8
- return "ascending";
9
- if (direction === "des")
10
- return "descending";
11
- }
12
- return "none";
13
+ return sort_item.direction;
13
14
  }
14
- export function sort_data(data, sort_by, sort_direction) {
15
+ export function sort_data(data, sort_columns) {
15
16
  if (!data || !data.length || !data[0]) {
16
17
  return [];
17
18
  }
18
- if (typeof sort_by === "number" &&
19
- sort_direction &&
20
- sort_by >= 0 &&
21
- sort_by < data[0].length) {
19
+ if (sort_columns.length > 0) {
22
20
  const row_indices = [...Array(data.length)].map((_, i) => i);
23
21
  row_indices.sort((row_a_idx, row_b_idx) => {
24
22
  const row_a = data[row_a_idx];
25
23
  const row_b = data[row_b_idx];
26
- if (!row_a ||
27
- !row_b ||
28
- sort_by >= row_a.length ||
29
- sort_by >= row_b.length)
30
- return 0;
31
- const val_a = row_a[sort_by].value;
32
- const val_b = row_b[sort_by].value;
33
- const comparison = val_a < val_b ? -1 : val_a > val_b ? 1 : 0;
34
- return sort_direction === "asc" ? comparison : -comparison;
24
+ for (const { col: sort_by, direction } of sort_columns) {
25
+ if (!row_a ||
26
+ !row_b ||
27
+ sort_by < 0 ||
28
+ sort_by >= row_a.length ||
29
+ sort_by >= row_b.length ||
30
+ !row_a[sort_by] ||
31
+ !row_b[sort_by]) {
32
+ continue;
33
+ }
34
+ const val_a = row_a[sort_by].value;
35
+ const val_b = row_b[sort_by].value;
36
+ const comparison = val_a < val_b ? -1 : val_a > val_b ? 1 : 0;
37
+ if (comparison !== 0) {
38
+ return direction === "asc" ? comparison : -comparison;
39
+ }
40
+ }
41
+ return 0;
35
42
  });
36
43
  return row_indices;
37
44
  }
38
45
  return [...Array(data.length)].map((_, i) => i);
39
46
  }
47
+ export function sort_data_and_preserve_selection(data, display_value, styling, sort_columns, selected, get_current_indices) {
48
+ let id = null;
49
+ if (selected && selected[0] in data && selected[1] in data[selected[0]]) {
50
+ id = data[selected[0]][selected[1]].id;
51
+ }
52
+ sort_table_data(data, display_value, styling, sort_columns);
53
+ let new_selected = selected;
54
+ if (id) {
55
+ const [i, j] = get_current_indices(id, data);
56
+ new_selected = [i, j];
57
+ }
58
+ return { data, selected: new_selected };
59
+ }
@@ -1,12 +1,13 @@
1
- import type { Headers, HeadersWithIDs, TableCell, TableData, CountConfig, ElementRefs, DataBinding } from "../types";
1
+ import type { Headers, HeadersWithIDs, TableCell, TableData } from "../types";
2
2
  import type { SortDirection } from "./sort_utils";
3
3
  export declare function make_cell_id(row: number, col: number): string;
4
4
  export declare function make_header_id(col: number): string;
5
- export declare function process_data(input_values: (string | number)[][], row_count: CountConfig, col_count: CountConfig, headers: Headers, show_row_numbers: boolean, element_refs: ElementRefs, data_binding: DataBinding): TableData;
6
- export declare function make_headers(input_headers: Headers, show_row_numbers: boolean, col_count: CountConfig, element_refs: ElementRefs): HeadersWithIDs[];
7
5
  export declare function get_max(data: TableData): TableCell[];
8
- export declare function sort_table_data(data: TableData, display_value: string[][] | null, styling: string[][] | null, col: number, dir: SortDirection): void;
9
- export declare function copy_table_data(data: TableData, selected_cells: [number, number][]): Promise<void>;
6
+ export declare function sort_table_data(data: TableData, display_value: string[][] | null, styling: string[][] | null, sort_columns: {
7
+ col: number;
8
+ direction: SortDirection;
9
+ }[]): void;
10
+ export declare function copy_table_data(data: TableData, selected_cells: [number, number][] | null): Promise<void>;
10
11
  export declare function guess_delimiter(text: string, possibleDelimiters: string[]): string[];
11
12
  export declare function data_uri_to_blob(data_uri: string): Blob;
12
13
  export declare function handle_file_upload(data_uri: string, update_headers: (headers: Headers) => HeadersWithIDs[], update_values: (values: (string | number)[][]) => void): void;
@@ -6,58 +6,6 @@ export function make_cell_id(row, col) {
6
6
  export function make_header_id(col) {
7
7
  return `header-${col}`;
8
8
  }
9
- export function process_data(input_values, row_count, col_count, headers, show_row_numbers, element_refs, data_binding) {
10
- const data_row_length = input_values.length;
11
- return Array(row_count[1] === "fixed" ? row_count[0] : data_row_length)
12
- .fill(0)
13
- .map((_, row) => {
14
- return Array(col_count[1] === "fixed"
15
- ? col_count[0]
16
- : data_row_length > 0
17
- ? input_values[0].length
18
- : headers.length)
19
- .fill(0)
20
- .map((_, col) => {
21
- const cell_id = make_cell_id(row, col);
22
- element_refs[cell_id] = element_refs[cell_id] || {
23
- input: null,
24
- cell: null
25
- };
26
- const cell_obj = {
27
- value: input_values?.[row]?.[col] ?? "",
28
- id: cell_id
29
- };
30
- data_binding[cell_id] = cell_obj;
31
- return cell_obj;
32
- });
33
- });
34
- }
35
- export function make_headers(input_headers, show_row_numbers, col_count, element_refs) {
36
- let header_list = input_headers || [];
37
- if (show_row_numbers) {
38
- header_list = ["", ...header_list];
39
- }
40
- if (col_count[1] === "fixed" && header_list.length < col_count[0]) {
41
- const fill_headers = Array(col_count[0] - header_list.length)
42
- .fill("")
43
- .map((_, i) => `${i + header_list.length}`);
44
- header_list = header_list.concat(fill_headers);
45
- }
46
- if (!header_list || header_list.length === 0) {
47
- return Array(col_count[0])
48
- .fill(0)
49
- .map((_, col) => {
50
- const header_id = make_header_id(col);
51
- element_refs[header_id] = { cell: null, input: null };
52
- return { id: header_id, value: JSON.stringify(col + 1) };
53
- });
54
- }
55
- return header_list.map((header, col) => {
56
- const header_id = make_header_id(col);
57
- element_refs[header_id] = { cell: null, input: null };
58
- return { id: header_id, value: header ?? "" };
59
- });
60
- }
61
9
  export function get_max(data) {
62
10
  if (!data || !data.length)
63
11
  return [];
@@ -71,8 +19,12 @@ export function get_max(data) {
71
19
  }
72
20
  return max;
73
21
  }
74
- export function sort_table_data(data, display_value, styling, col, dir) {
75
- const indices = sort_data(data, col, dir);
22
+ export function sort_table_data(data, display_value, styling, sort_columns) {
23
+ if (!sort_columns.length)
24
+ return;
25
+ if (!data || !data.length)
26
+ return;
27
+ const indices = sort_data(data, sort_columns);
76
28
  const new_data = indices.map((i) => data[i]);
77
29
  data.splice(0, data.length, ...new_data);
78
30
  if (display_value) {
@@ -85,7 +37,11 @@ export function sort_table_data(data, display_value, styling, col, dir) {
85
37
  }
86
38
  }
87
39
  export async function copy_table_data(data, selected_cells) {
88
- const csv = selected_cells.reduce((acc, [row, col]) => {
40
+ if (!data || !data.length)
41
+ return;
42
+ const cells_to_copy = selected_cells ||
43
+ data.flatMap((row, r) => row.map((_, c) => [r, c]));
44
+ const csv = cells_to_copy.reduce((acc, [row, col]) => {
89
45
  acc[row] = acc[row] || {};
90
46
  const value = String(data[row][col].value);
91
47
  acc[row][col] =
@@ -95,6 +51,8 @@ export async function copy_table_data(data, selected_cells) {
95
51
  return acc;
96
52
  }, {});
97
53
  const rows = Object.keys(csv).sort((a, b) => +a - +b);
54
+ if (!rows.length)
55
+ return;
98
56
  const cols = Object.keys(csv[rows[0]]).sort((a, b) => +a - +b);
99
57
  const text = rows
100
58
  .map((r) => cols.map((c) => csv[r][c] || "").join(","))
@@ -103,7 +61,6 @@ export async function copy_table_data(data, selected_cells) {
103
61
  await navigator.clipboard.writeText(text);
104
62
  }
105
63
  catch (err) {
106
- console.error("Copy failed:", err);
107
64
  throw new Error("Failed to copy to clipboard: " + err.message);
108
65
  }
109
66
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradio/dataframe",
3
- "version": "0.16.5",
3
+ "version": "0.17.1",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "author": "",
@@ -17,14 +17,14 @@
17
17
  "dompurify": "^3.0.3",
18
18
  "katex": "^0.16.7",
19
19
  "marked": "^12.0.0",
20
- "@gradio/atoms": "^0.13.3",
21
- "@gradio/button": "^0.4.9",
20
+ "@gradio/atoms": "^0.14.0",
21
+ "@gradio/button": "^0.4.10",
22
22
  "@gradio/client": "^1.13.1",
23
23
  "@gradio/icons": "^0.10.0",
24
- "@gradio/markdown-code": "^0.4.0",
25
- "@gradio/statustracker": "^0.10.4",
26
- "@gradio/upload": "^0.15.4",
27
- "@gradio/utils": "^0.10.1"
24
+ "@gradio/upload": "^0.15.5",
25
+ "@gradio/statustracker": "^0.10.5",
26
+ "@gradio/utils": "^0.10.1",
27
+ "@gradio/markdown-code": "^0.4.1"
28
28
  },
29
29
  "exports": {
30
30
  ".": {
@@ -2,6 +2,7 @@
2
2
  import { onMount } from "svelte";
3
3
  import CellMenuIcons from "./CellMenuIcons.svelte";
4
4
  import type { I18nFormatter } from "js/utils/src";
5
+ import type { SortDirection } from "./context/table_context";
5
6
 
6
7
  export let x: number;
7
8
  export let y: number;
@@ -16,13 +17,18 @@
16
17
  export let on_delete_col: () => void;
17
18
  export let can_delete_rows: boolean;
18
19
  export let can_delete_cols: boolean;
20
+ export let on_sort: (direction: SortDirection) => void = () => {};
21
+ export let on_clear_sort: () => void = () => {};
22
+ export let sort_direction: SortDirection | null = null;
23
+ export let sort_priority: number | null = null;
24
+ export let editable = true;
19
25
 
20
26
  export let i18n: I18nFormatter;
21
27
  let menu_element: HTMLDivElement;
22
28
 
23
29
  $: is_header = row === -1;
24
- $: can_add_rows = row_count[1] === "dynamic";
25
- $: can_add_columns = col_count[1] === "dynamic";
30
+ $: can_add_rows = editable && row_count[1] === "dynamic";
31
+ $: can_add_columns = editable && col_count[1] === "dynamic";
26
32
 
27
33
  onMount(() => {
28
34
  position_menu();
@@ -51,34 +57,89 @@
51
57
  }
52
58
  </script>
53
59
 
54
- <div bind:this={menu_element} class="cell-menu">
60
+ <div bind:this={menu_element} class="cell-menu" role="menu">
61
+ {#if is_header}
62
+ <button
63
+ role="menuitem"
64
+ on:click={() => on_sort("asc")}
65
+ class:active={sort_direction === "asc"}
66
+ >
67
+ <CellMenuIcons icon="sort-asc" />
68
+ {i18n("dataframe.sort_ascending")}
69
+ {#if sort_direction === "asc" && sort_priority !== null}
70
+ <span class="priority">{sort_priority}</span>
71
+ {/if}
72
+ </button>
73
+ <button
74
+ role="menuitem"
75
+ on:click={() => on_sort("desc")}
76
+ class:active={sort_direction === "desc"}
77
+ >
78
+ <CellMenuIcons icon="sort-desc" />
79
+ {i18n("dataframe.sort_descending")}
80
+ {#if sort_direction === "desc" && sort_priority !== null}
81
+ <span class="priority">{sort_priority}</span>
82
+ {/if}
83
+ </button>
84
+ <button role="menuitem" on:click={on_clear_sort}>
85
+ <CellMenuIcons icon="clear-sort" />
86
+ {i18n("dataframe.clear_sort")}
87
+ </button>
88
+ {/if}
89
+
55
90
  {#if !is_header && can_add_rows}
56
- <button on:click={() => on_add_row_above()}>
91
+ <button
92
+ role="menuitem"
93
+ on:click={() => on_add_row_above()}
94
+ aria-label="Add row above"
95
+ >
57
96
  <CellMenuIcons icon="add-row-above" />
58
97
  {i18n("dataframe.add_row_above")}
59
98
  </button>
60
- <button on:click={() => on_add_row_below()}>
99
+ <button
100
+ role="menuitem"
101
+ on:click={() => on_add_row_below()}
102
+ aria-label="Add row below"
103
+ >
61
104
  <CellMenuIcons icon="add-row-below" />
62
105
  {i18n("dataframe.add_row_below")}
63
106
  </button>
64
107
  {#if can_delete_rows}
65
- <button on:click={on_delete_row} class="delete">
108
+ <button
109
+ role="menuitem"
110
+ on:click={on_delete_row}
111
+ class="delete"
112
+ aria-label="Delete row"
113
+ >
66
114
  <CellMenuIcons icon="delete-row" />
67
115
  {i18n("dataframe.delete_row")}
68
116
  </button>
69
117
  {/if}
70
118
  {/if}
71
119
  {#if can_add_columns}
72
- <button on:click={() => on_add_column_left()}>
120
+ <button
121
+ role="menuitem"
122
+ on:click={() => on_add_column_left()}
123
+ aria-label="Add column to the left"
124
+ >
73
125
  <CellMenuIcons icon="add-column-left" />
74
126
  {i18n("dataframe.add_column_left")}
75
127
  </button>
76
- <button on:click={() => on_add_column_right()}>
128
+ <button
129
+ role="menuitem"
130
+ on:click={() => on_add_column_right()}
131
+ aria-label="Add column to the right"
132
+ >
77
133
  <CellMenuIcons icon="add-column-right" />
78
134
  {i18n("dataframe.add_column_right")}
79
135
  </button>
80
136
  {#if can_delete_cols}
81
- <button on:click={on_delete_col} class="delete">
137
+ <button
138
+ role="menuitem"
139
+ on:click={on_delete_col}
140
+ class="delete"
141
+ aria-label="Delete column"
142
+ >
82
143
  <CellMenuIcons icon="delete-column" />
83
144
  {i18n("dataframe.delete_column")}
84
145
  </button>
@@ -89,7 +150,7 @@
89
150
  <style>
90
151
  .cell-menu {
91
152
  position: fixed;
92
- z-index: var(--layer-4);
153
+ z-index: 9;
93
154
  background: var(--background-fill-primary);
94
155
  border: 1px solid var(--border-color-primary);
95
156
  border-radius: var(--radius-sm);
@@ -99,6 +160,7 @@
99
160
  gap: var(--size-1);
100
161
  box-shadow: var(--shadow-drop-lg);
101
162
  min-width: 150px;
163
+ z-index: var(--layer-1);
102
164
  }
103
165
 
104
166
  .cell-menu button {
@@ -116,6 +178,11 @@
116
178
  display: flex;
117
179
  align-items: center;
118
180
  gap: var(--size-2);
181
+ position: relative;
182
+ }
183
+
184
+ .cell-menu button.active {
185
+ background-color: var(--background-fill-secondary);
119
186
  }
120
187
 
121
188
  .cell-menu button:hover {
@@ -126,4 +193,17 @@
126
193
  fill: currentColor;
127
194
  transition: fill 0.2s;
128
195
  }
196
+
197
+ .priority {
198
+ display: flex;
199
+ align-items: center;
200
+ justify-content: center;
201
+ margin-left: auto;
202
+ font-size: var(--size-2);
203
+ background-color: var(--button-secondary-background-fill);
204
+ color: var(--body-text-color);
205
+ border-radius: var(--radius-sm);
206
+ width: var(--size-2-5);
207
+ height: var(--size-2-5);
208
+ }
129
209
  </style>
@@ -0,0 +1,46 @@
1
+ <script lang="ts">
2
+ export let on_click: (event: MouseEvent) => void;
3
+ </script>
4
+
5
+ <button
6
+ aria-label="Open cell menu"
7
+ class="cell-menu-button"
8
+ aria-haspopup="menu"
9
+ on:click={on_click}
10
+ on:touchstart={(event) => {
11
+ event.preventDefault();
12
+ const touch = event.touches[0];
13
+ const mouseEvent = new MouseEvent("click", {
14
+ clientX: touch.clientX,
15
+ clientY: touch.clientY,
16
+ bubbles: true,
17
+ cancelable: true,
18
+ view: window
19
+ });
20
+ on_click(mouseEvent);
21
+ }}
22
+ >
23
+ &#8942;
24
+ </button>
25
+
26
+ <style>
27
+ .cell-menu-button {
28
+ flex-shrink: 0;
29
+ display: none;
30
+ align-items: center;
31
+ justify-content: center;
32
+ background-color: var(--block-background-fill);
33
+ border: 1px solid var(--border-color-primary);
34
+ border-radius: var(--block-radius);
35
+ width: var(--size-5);
36
+ height: var(--size-5);
37
+ min-width: var(--size-5);
38
+ padding: 0;
39
+ margin-right: var(--spacing-sm);
40
+ z-index: 2;
41
+ position: absolute;
42
+ right: var(--size-1);
43
+ top: 50%;
44
+ transform: translateY(-50%);
45
+ }
46
+ </style>
@@ -110,4 +110,83 @@
110
110
  stroke-linecap="round"
111
111
  />
112
112
  </svg>
113
+ {:else if icon == "sort-asc"}
114
+ <svg viewBox="0 0 24 24" width="16" height="16">
115
+ <path
116
+ d="M8 16L12 12L16 16"
117
+ stroke="currentColor"
118
+ stroke-width="2"
119
+ fill="none"
120
+ stroke-linecap="round"
121
+ stroke-linejoin="round"
122
+ />
123
+ <path
124
+ d="M12 12V19"
125
+ stroke="currentColor"
126
+ stroke-width="2"
127
+ stroke-linecap="round"
128
+ />
129
+ <path
130
+ d="M5 7H19"
131
+ stroke="currentColor"
132
+ stroke-width="2"
133
+ stroke-linecap="round"
134
+ />
135
+ </svg>
136
+ {:else if icon == "sort-desc"}
137
+ <svg viewBox="0 0 24 24" width="16" height="16">
138
+ <path
139
+ d="M8 12L12 16L16 12"
140
+ stroke="currentColor"
141
+ stroke-width="2"
142
+ fill="none"
143
+ stroke-linecap="round"
144
+ stroke-linejoin="round"
145
+ />
146
+ <path
147
+ d="M12 16V9"
148
+ stroke="currentColor"
149
+ stroke-width="2"
150
+ stroke-linecap="round"
151
+ />
152
+ <path
153
+ d="M5 5H19"
154
+ stroke="currentColor"
155
+ stroke-width="2"
156
+ stroke-linecap="round"
157
+ />
158
+ </svg>
159
+ {:else if icon == "clear-sort"}
160
+ <svg viewBox="0 0 24 24" width="16" height="16">
161
+ <path
162
+ d="M5 5H19"
163
+ stroke="currentColor"
164
+ stroke-width="2"
165
+ stroke-linecap="round"
166
+ />
167
+ <path
168
+ d="M5 9H15"
169
+ stroke="currentColor"
170
+ stroke-width="2"
171
+ stroke-linecap="round"
172
+ />
173
+ <path
174
+ d="M5 13H11"
175
+ stroke="currentColor"
176
+ stroke-width="2"
177
+ stroke-linecap="round"
178
+ />
179
+ <path
180
+ d="M5 17H7"
181
+ stroke="currentColor"
182
+ stroke-width="2"
183
+ stroke-linecap="round"
184
+ />
185
+ <path
186
+ d="M17 17L21 21M21 17L17 21"
187
+ stroke="currentColor"
188
+ stroke-width="2"
189
+ stroke-linecap="round"
190
+ />
191
+ </svg>
113
192
  {/if}