@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,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { onMount, tick } from "svelte";
2
+ import { onMount, tick, createEventDispatcher } from "svelte";
3
3
  import { _ } from "svelte-i18n";
4
4
 
5
5
  export let items: any[][] = [];
@@ -11,6 +11,13 @@
11
11
  export let end = 20;
12
12
  export let selected: number | false;
13
13
  export let disable_scroll = false;
14
+ export let show_scroll_button = false;
15
+ export let viewport: HTMLTableElement;
16
+
17
+ const dispatch = createEventDispatcher<{
18
+ scroll_top: number;
19
+ }>();
20
+
14
21
  let height = "100%";
15
22
 
16
23
  let average_height = 30;
@@ -22,7 +29,6 @@
22
29
  let mounted: boolean;
23
30
  let rows: HTMLCollectionOf<HTMLTableRowElement>;
24
31
  let top = 0;
25
- let viewport: HTMLTableElement;
26
32
  let viewport_height = 200;
27
33
  let visible: { index: number; data: any[] }[] = [];
28
34
  let viewport_box: DOMRectReadOnly;
@@ -151,6 +157,12 @@
151
157
  async function handle_scroll(e: Event): Promise<void> {
152
158
  const scroll_top = viewport.scrollTop;
153
159
 
160
+ show_scroll_button = scroll_top > 100;
161
+
162
+ if (show_scroll_button) {
163
+ dispatch("scroll_top", scroll_top);
164
+ }
165
+
154
166
  rows = contents.children as HTMLCollectionOf<HTMLTableRowElement>;
155
167
  const is_start_overflow = sortedItems.length < start;
156
168
 
@@ -293,8 +305,7 @@
293
305
  <style type="text/css">
294
306
  table {
295
307
  position: relative;
296
- overflow-y: scroll;
297
- overflow-x: scroll;
308
+ overflow: auto;
298
309
  -webkit-overflow-scrolling: touch;
299
310
  max-height: var(--max-height);
300
311
  box-sizing: border-box;
@@ -309,7 +320,52 @@
309
320
  width: 100%;
310
321
  scroll-snap-type: x proximity;
311
322
  border-collapse: separate;
323
+ scrollbar-width: thin;
324
+ scrollbar-color: rgba(128, 128, 128, 0.5) transparent;
325
+ }
326
+
327
+ table::-webkit-scrollbar {
328
+ width: 4px;
329
+ height: 4px;
330
+ }
331
+
332
+ table::-webkit-scrollbar-track {
333
+ background: transparent;
334
+ }
335
+
336
+ table::-webkit-scrollbar-thumb {
337
+ background-color: rgba(128, 128, 128, 0.5);
338
+ border-radius: 4px;
339
+ }
340
+
341
+ table:hover {
342
+ scrollbar-color: rgba(160, 160, 160, 0.7) transparent;
312
343
  }
344
+
345
+ table:hover::-webkit-scrollbar-thumb {
346
+ background-color: rgba(160, 160, 160, 0.7);
347
+ border-radius: 4px;
348
+ width: 4px;
349
+ }
350
+
351
+ @media (hover: none) {
352
+ table {
353
+ scrollbar-color: rgba(160, 160, 160, 0.7) transparent;
354
+ }
355
+
356
+ table::-webkit-scrollbar-thumb {
357
+ background-color: rgba(160, 160, 160, 0.7);
358
+ border-radius: 4px;
359
+ }
360
+ }
361
+
362
+ @media (pointer: coarse) {
363
+ table::-webkit-scrollbar {
364
+ width: 8px;
365
+ height: 8px;
366
+ }
367
+ }
368
+
313
369
  table :is(thead, tfoot, tbody) {
314
370
  display: table;
315
371
  table-layout: fixed;
@@ -344,46 +400,43 @@
344
400
  background: var(--table-even-background-fill);
345
401
  }
346
402
 
347
- tbody :global(td.frozen-column) {
403
+ tbody :global(td.pinned-column) {
348
404
  position: sticky;
349
- z-index: var(--layer-2);
405
+ z-index: 3;
350
406
  }
351
407
 
352
- tbody :global(tr:nth-child(odd)) :global(td.frozen-column) {
408
+ tbody :global(tr:nth-child(odd)) :global(td.pinned-column) {
353
409
  background: var(--table-odd-background-fill);
354
410
  }
355
411
 
356
- tbody :global(tr:nth-child(even)) :global(td.frozen-column) {
412
+ tbody :global(tr:nth-child(even)) :global(td.pinned-column) {
357
413
  background: var(--table-even-background-fill);
358
414
  }
359
415
 
360
- tbody :global(td.always-frozen) {
361
- z-index: var(--layer-3);
362
- }
363
-
364
- tbody :global(td.last-frozen) {
365
- border-right: 2px solid var(--border-color-primary);
416
+ tbody :global(td.last-pinned) {
417
+ border-right: 1px solid var(--border-color-primary);
366
418
  }
367
419
 
368
420
  thead {
369
421
  position: sticky;
370
422
  top: 0;
371
423
  left: 0;
372
- z-index: var(--layer-3);
373
424
  background: var(--background-fill-primary);
425
+ z-index: 7;
374
426
  }
375
427
 
376
428
  thead :global(th) {
377
429
  background: var(--table-even-background-fill) !important;
378
430
  }
379
431
 
380
- thead :global(th.frozen-column) {
432
+ thead :global(th.pinned-column) {
381
433
  position: sticky;
382
- z-index: var(--layer-4);
434
+ z-index: 7;
435
+ background: var(--table-even-background-fill) !important;
383
436
  }
384
437
 
385
- thead :global(th.always-frozen) {
386
- z-index: var(--layer-5);
438
+ thead :global(th.last-pinned) {
439
+ border-right: 1px solid var(--border-color-primary);
387
440
  }
388
441
 
389
442
  .table.disable-scroll {
@@ -0,0 +1,65 @@
1
+ import { getContext, setContext } from "svelte";
2
+ import type { DataFrameContext } from "./table_context";
3
+ import type { CellData } from "../selection_utils";
4
+ import type { DataframeValue } from "../utils";
5
+ import type { CellCoordinate } from "../types";
6
+
7
+ const KEYBOARD_KEY = Symbol("keyboard");
8
+
9
+ export type KeyboardContext = {
10
+ selected_header: number | false;
11
+ header_edit: number | false;
12
+ editing: [number, number] | false;
13
+ selected: [number, number] | false;
14
+ selected_cells: [number, number][];
15
+ editable: boolean;
16
+ data: CellData[][];
17
+ headers: { id: string; value: string }[];
18
+ els: Record<
19
+ string,
20
+ { cell: null | HTMLTableCellElement; input: null | HTMLInputElement }
21
+ >;
22
+ df_actions: DataFrameContext["actions"];
23
+ dispatch: {
24
+ (e: "change", detail: DataframeValue): void;
25
+ (e: "input", detail?: undefined): void;
26
+ (e: "select", detail: any): void;
27
+ (e: "search", detail: string | null): void;
28
+ };
29
+ add_row: (index?: number) => Promise<void>;
30
+ get_next_cell_coordinates: (
31
+ current: CellCoordinate,
32
+ data: CellData[][],
33
+ shift_key: boolean
34
+ ) => false | CellCoordinate;
35
+ get_range_selection: (
36
+ start: CellCoordinate,
37
+ end: CellCoordinate
38
+ ) => CellCoordinate[];
39
+ move_cursor: (
40
+ event: KeyboardEvent,
41
+ current_coords: CellCoordinate,
42
+ data: CellData[][]
43
+ ) => false | CellCoordinate;
44
+ copy_flash: boolean;
45
+ set_copy_flash: (value: boolean) => void;
46
+ parent_element?: HTMLDivElement;
47
+ };
48
+
49
+ export function create_keyboard_context(
50
+ context: KeyboardContext
51
+ ): KeyboardContext {
52
+ const instance_id = Symbol(
53
+ `keyboard_${Math.random().toString(36).substring(2)}`
54
+ );
55
+ setContext(instance_id, context);
56
+ setContext(KEYBOARD_KEY, { instance_id, context });
57
+ return context;
58
+ }
59
+
60
+ export function get_keyboard_context(): KeyboardContext | undefined {
61
+ const ctx = getContext<{ instance_id: symbol; context: KeyboardContext }>(
62
+ KEYBOARD_KEY
63
+ );
64
+ return ctx ? ctx.context : getContext<KeyboardContext>(KEYBOARD_KEY);
65
+ }
@@ -0,0 +1,168 @@
1
+ import { getContext, setContext } from "svelte";
2
+ import { tick } from "svelte";
3
+ import type { DataFrameContext } from "./table_context";
4
+ import type { CellData } from "../selection_utils";
5
+ import type { DataframeValue } from "../utils";
6
+ import { handle_selection } from "../selection_utils";
7
+
8
+ const SELECTION_KEY = Symbol("selection");
9
+
10
+ export type SelectionContext = {
11
+ df_actions: DataFrameContext["actions"];
12
+ dispatch: {
13
+ (e: "change", detail: DataframeValue): void;
14
+ (e: "input", detail?: undefined): void;
15
+ (e: "select", detail: any): void;
16
+ (e: "search", detail: string | null): void;
17
+ };
18
+ data: CellData[][];
19
+ els: Record<
20
+ string,
21
+ { cell: null | HTMLTableCellElement; input: null | HTMLInputElement }
22
+ >;
23
+ editable: boolean;
24
+ show_row_numbers: boolean;
25
+ get_data_at: (row: number, col: number) => string | number;
26
+ clear_on_focus: boolean;
27
+ selected_cells: [number, number][];
28
+ parent_element: HTMLElement;
29
+ actions: {
30
+ handle_cell_click: (event: MouseEvent, row: number, col: number) => void;
31
+ toggle_cell_menu: (event: MouseEvent, row: number, col: number) => void;
32
+ toggle_cell_button: (row: number, col: number) => void;
33
+ handle_select_column: (col: number) => void;
34
+ handle_select_row: (row: number) => void;
35
+ };
36
+ };
37
+
38
+ export function create_selection_context(
39
+ context: Omit<SelectionContext, "actions">
40
+ ): SelectionContext {
41
+ const instance_id = Symbol(
42
+ `selection_${Math.random().toString(36).substring(2)}`
43
+ );
44
+ const actions = {
45
+ handle_cell_click: (event: MouseEvent, row: number, col: number) => {
46
+ if (event.target instanceof HTMLAnchorElement) return;
47
+
48
+ event.preventDefault();
49
+ event.stopPropagation();
50
+
51
+ if (context.show_row_numbers && col === -1) return;
52
+
53
+ context.clear_on_focus = false;
54
+ context.df_actions.set_active_cell_menu(null);
55
+ context.df_actions.set_active_header_menu(null);
56
+ context.df_actions.set_selected_header(false);
57
+ context.df_actions.set_header_edit(false);
58
+
59
+ const new_selected_cells = handle_selection(
60
+ [row, col],
61
+ context.selected_cells || [],
62
+ event
63
+ );
64
+
65
+ context.df_actions.set_selected_cells(new_selected_cells);
66
+ context.df_actions.set_selected(new_selected_cells[0]);
67
+
68
+ if (context.editable) {
69
+ if (new_selected_cells.length === 1) {
70
+ context.df_actions.set_editing([row, col]);
71
+ tick().then(() => {
72
+ const input_el = context.els[context.data[row][col].id].input;
73
+ if (input_el) {
74
+ input_el.focus();
75
+ input_el.selectionStart = input_el.selectionEnd =
76
+ input_el.value.length;
77
+ }
78
+ });
79
+ } else {
80
+ context.df_actions.set_editing(false);
81
+ context.parent_element.focus();
82
+ }
83
+ } else {
84
+ context.parent_element.focus();
85
+ }
86
+
87
+ actions.toggle_cell_button(row, col);
88
+
89
+ context.dispatch("select", {
90
+ index: [row, col],
91
+ value: context.get_data_at(row, col),
92
+ row_value: context.data[row].map((d) => d.value)
93
+ });
94
+ },
95
+
96
+ toggle_cell_menu: (event: MouseEvent, row: number, col: number) => {
97
+ event.stopPropagation();
98
+ const current_menu = context.df_actions.get_active_cell_menu();
99
+ if (
100
+ current_menu &&
101
+ current_menu.row === row &&
102
+ current_menu.col === col
103
+ ) {
104
+ context.df_actions.set_active_cell_menu(null);
105
+ } else {
106
+ const cell = (event.target as HTMLElement).closest("td");
107
+ if (cell) {
108
+ const rect = cell.getBoundingClientRect();
109
+ context.df_actions.set_active_cell_menu({
110
+ row,
111
+ col,
112
+ x: rect.right,
113
+ y: rect.bottom
114
+ });
115
+ }
116
+ }
117
+ },
118
+
119
+ toggle_cell_button: (row: number, col: number) => {
120
+ const current_button = context.df_actions.get_active_button();
121
+ const new_button =
122
+ current_button?.type === "cell" &&
123
+ current_button.row === row &&
124
+ current_button.col === col
125
+ ? null
126
+ : { type: "cell" as const, row, col };
127
+ context.df_actions.set_active_button(new_button);
128
+ },
129
+
130
+ handle_select_column: (col: number) => {
131
+ const selected_cells = context.data.map(
132
+ (_, row) => [row, col] as [number, number]
133
+ );
134
+ context.df_actions.set_selected_cells(selected_cells);
135
+ context.df_actions.set_selected(selected_cells[0]);
136
+ context.df_actions.set_editing(false);
137
+
138
+ setTimeout(() => {
139
+ context.parent_element.focus();
140
+ }, 0);
141
+ },
142
+
143
+ handle_select_row: (row: number) => {
144
+ const selected_cells = context.data[0].map(
145
+ (_, col) => [row, col] as [number, number]
146
+ );
147
+ context.df_actions.set_selected_cells(selected_cells);
148
+ context.df_actions.set_selected(selected_cells[0]);
149
+ context.df_actions.set_editing(false);
150
+
151
+ setTimeout(() => {
152
+ context.parent_element.focus();
153
+ }, 0);
154
+ }
155
+ };
156
+
157
+ const selection_context = { ...context, actions };
158
+ setContext(instance_id, selection_context);
159
+ setContext(SELECTION_KEY, { instance_id, context: selection_context });
160
+ return selection_context;
161
+ }
162
+
163
+ export function get_selection_context(): SelectionContext {
164
+ const ctx = getContext<{ instance_id: symbol; context: SelectionContext }>(
165
+ SELECTION_KEY
166
+ );
167
+ return ctx ? ctx.context : getContext<SelectionContext>(SELECTION_KEY);
168
+ }