@gradio/dataframe 0.23.0 → 0.23.2
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.
- package/CHANGELOG.md +26 -0
- package/Dataframe.test.ts +316 -4
- package/Index.svelte +0 -1
- package/dist/Index.svelte +0 -1
- package/dist/shared/BooleanCell.svelte +0 -1
- package/dist/shared/DataCell.svelte +88 -3
- package/dist/shared/DataCell.svelte.d.ts +1 -0
- package/dist/shared/EditableCell.svelte +52 -29
- package/dist/shared/EditableCell.svelte.d.ts +2 -0
- package/dist/shared/HeaderCell.svelte +67 -5
- package/dist/shared/HeaderCell.svelte.d.ts +4 -0
- package/dist/shared/Table.svelte +166 -50
- package/dist/shared/column_measurement.svelte.d.ts +1 -0
- package/dist/shared/column_measurement.svelte.js +86 -13
- package/package.json +7 -7
- package/shared/BooleanCell.svelte +0 -1
- package/shared/DataCell.svelte +88 -3
- package/shared/EditableCell.svelte +52 -29
- package/shared/HeaderCell.svelte +67 -5
- package/shared/Table.svelte +166 -50
- package/shared/column_measurement.svelte.ts +98 -14
|
@@ -21,13 +21,15 @@
|
|
|
21
21
|
i18n,
|
|
22
22
|
is_dragging = false,
|
|
23
23
|
wrap_text = false,
|
|
24
|
+
expanded = false,
|
|
24
25
|
show_selection_buttons = false,
|
|
25
26
|
coords,
|
|
26
27
|
on_select_column = null,
|
|
27
28
|
on_select_row = null,
|
|
28
29
|
el = $bindable(null),
|
|
29
30
|
onblur,
|
|
30
|
-
onkeydown
|
|
31
|
+
onkeydown,
|
|
32
|
+
pad_left = false
|
|
31
33
|
}: {
|
|
32
34
|
edit: boolean;
|
|
33
35
|
value?: CellValue;
|
|
@@ -55,6 +57,7 @@
|
|
|
55
57
|
i18n: I18nFormatter;
|
|
56
58
|
is_dragging?: boolean;
|
|
57
59
|
wrap_text?: boolean;
|
|
60
|
+
expanded?: boolean;
|
|
58
61
|
show_selection_buttons?: boolean;
|
|
59
62
|
coords: [number, number];
|
|
60
63
|
on_select_column?: ((col: number) => void) | null;
|
|
@@ -65,6 +68,7 @@
|
|
|
65
68
|
coords: [number, number];
|
|
66
69
|
}) => void;
|
|
67
70
|
onkeydown?: (event: KeyboardEvent) => void;
|
|
71
|
+
pad_left: boolean;
|
|
68
72
|
} = $props();
|
|
69
73
|
|
|
70
74
|
function truncate_text(
|
|
@@ -79,7 +83,9 @@
|
|
|
79
83
|
return str.slice(0, max_length) + "...";
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
let should_truncate = $derived(
|
|
86
|
+
let should_truncate = $derived(
|
|
87
|
+
!edit && !expanded && max_chars !== null && max_chars > 0
|
|
88
|
+
);
|
|
83
89
|
|
|
84
90
|
let display_content = $derived(
|
|
85
91
|
editable ? value : display_value !== null ? display_value : value
|
|
@@ -99,6 +105,22 @@
|
|
|
99
105
|
return {};
|
|
100
106
|
}
|
|
101
107
|
|
|
108
|
+
// grow the edit-mode textarea to fit its content so the overlay
|
|
109
|
+
// expands the same way the display span does.
|
|
110
|
+
function use_autosize(node: HTMLTextAreaElement): any {
|
|
111
|
+
function resize(): void {
|
|
112
|
+
node.style.height = "auto";
|
|
113
|
+
node.style.height = `${node.scrollHeight}px`;
|
|
114
|
+
}
|
|
115
|
+
node.addEventListener("input", resize);
|
|
116
|
+
requestAnimationFrame(resize);
|
|
117
|
+
return {
|
|
118
|
+
destroy() {
|
|
119
|
+
node.removeEventListener("input", resize);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
102
124
|
function handle_blur(event: FocusEvent): void {
|
|
103
125
|
onblur?.({
|
|
104
126
|
blur_event: event,
|
|
@@ -114,10 +136,12 @@
|
|
|
114
136
|
handle_blur({ target: { value } } as unknown as FocusEvent);
|
|
115
137
|
}
|
|
116
138
|
|
|
139
|
+
// returning cleanup from the effect fires the blur only when leaving edit mode, not on every render
|
|
117
140
|
$effect(() => {
|
|
118
|
-
if (
|
|
119
|
-
|
|
120
|
-
|
|
141
|
+
if (edit) {
|
|
142
|
+
return () => {
|
|
143
|
+
handle_blur({ target: { value } } as unknown as FocusEvent);
|
|
144
|
+
};
|
|
121
145
|
}
|
|
122
146
|
});
|
|
123
147
|
</script>
|
|
@@ -135,7 +159,9 @@
|
|
|
135
159
|
onmousedown={(e: MouseEvent) => e.stopPropagation()}
|
|
136
160
|
onclick={(e: MouseEvent) => e.stopPropagation()}
|
|
137
161
|
use:use_focus
|
|
162
|
+
use:use_autosize
|
|
138
163
|
onkeydown={handle_keydown}
|
|
164
|
+
class:pad_left
|
|
139
165
|
/>
|
|
140
166
|
{/if}
|
|
141
167
|
|
|
@@ -149,7 +175,7 @@
|
|
|
149
175
|
role="button"
|
|
150
176
|
class:edit
|
|
151
177
|
class:expanded={edit}
|
|
152
|
-
class:
|
|
178
|
+
class:header
|
|
153
179
|
onfocus={(e) => e.preventDefault()}
|
|
154
180
|
style={styling}
|
|
155
181
|
data-editable={editable}
|
|
@@ -205,7 +231,7 @@
|
|
|
205
231
|
textarea {
|
|
206
232
|
position: absolute;
|
|
207
233
|
flex: 1 1 0%;
|
|
208
|
-
transform:
|
|
234
|
+
transform: translate(0.2px, -0.5px);
|
|
209
235
|
outline: none;
|
|
210
236
|
border: none;
|
|
211
237
|
background: transparent;
|
|
@@ -217,24 +243,33 @@
|
|
|
217
243
|
font-size: inherit;
|
|
218
244
|
font-weight: inherit;
|
|
219
245
|
line-height: var(--line-lg);
|
|
246
|
+
left: var(--size-2);
|
|
247
|
+
user-select: text;
|
|
220
248
|
}
|
|
221
249
|
|
|
222
250
|
textarea:focus {
|
|
223
251
|
outline: none;
|
|
224
252
|
}
|
|
225
253
|
|
|
254
|
+
textarea.pad_left {
|
|
255
|
+
margin-left: var(--size-7);
|
|
256
|
+
}
|
|
257
|
+
|
|
226
258
|
span {
|
|
227
259
|
flex: 1 1 0%;
|
|
228
260
|
position: relative;
|
|
229
261
|
display: block;
|
|
230
262
|
outline: none;
|
|
231
|
-
-webkit-user-select: text;
|
|
232
|
-
-moz-user-select: text;
|
|
233
|
-
-ms-user-select: text;
|
|
234
|
-
user-select: text;
|
|
235
263
|
cursor: text;
|
|
236
264
|
width: 100%;
|
|
237
|
-
|
|
265
|
+
min-width: 0;
|
|
266
|
+
white-space: nowrap;
|
|
267
|
+
overflow: hidden;
|
|
268
|
+
text-overflow: ellipsis;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.header {
|
|
272
|
+
font-weight: var(--weight-bold);
|
|
238
273
|
}
|
|
239
274
|
|
|
240
275
|
span.text.expanded {
|
|
@@ -245,21 +280,6 @@
|
|
|
245
280
|
overflow: visible;
|
|
246
281
|
}
|
|
247
282
|
|
|
248
|
-
.multiline {
|
|
249
|
-
white-space: pre;
|
|
250
|
-
overflow: hidden;
|
|
251
|
-
text-overflow: ellipsis;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
.header {
|
|
255
|
-
transform: translateX(0);
|
|
256
|
-
font-weight: var(--weight-bold);
|
|
257
|
-
white-space: nowrap;
|
|
258
|
-
overflow: hidden;
|
|
259
|
-
text-overflow: ellipsis;
|
|
260
|
-
margin-left: var(--size-1);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
283
|
.edit {
|
|
264
284
|
opacity: 0;
|
|
265
285
|
pointer-events: none;
|
|
@@ -267,6 +287,8 @@
|
|
|
267
287
|
|
|
268
288
|
span :global(img) {
|
|
269
289
|
max-height: 100px;
|
|
290
|
+
max-width: 100%;
|
|
291
|
+
height: auto;
|
|
270
292
|
width: auto;
|
|
271
293
|
object-fit: contain;
|
|
272
294
|
}
|
|
@@ -278,8 +300,9 @@
|
|
|
278
300
|
.wrap,
|
|
279
301
|
.wrap.expanded {
|
|
280
302
|
white-space: normal;
|
|
281
|
-
|
|
303
|
+
overflow: visible;
|
|
304
|
+
text-overflow: clip;
|
|
282
305
|
overflow-wrap: break-word;
|
|
283
|
-
word-
|
|
306
|
+
word-break: break-word;
|
|
284
307
|
}
|
|
285
308
|
</style>
|
|
@@ -20,6 +20,7 @@ type $$ComponentProps = {
|
|
|
20
20
|
i18n: I18nFormatter;
|
|
21
21
|
is_dragging?: boolean;
|
|
22
22
|
wrap_text?: boolean;
|
|
23
|
+
expanded?: boolean;
|
|
23
24
|
show_selection_buttons?: boolean;
|
|
24
25
|
coords: [number, number];
|
|
25
26
|
on_select_column?: ((col: number) => void) | null;
|
|
@@ -30,6 +31,7 @@ type $$ComponentProps = {
|
|
|
30
31
|
coords: [number, number];
|
|
31
32
|
}) => void;
|
|
32
33
|
onkeydown?: (event: KeyboardEvent) => void;
|
|
34
|
+
pad_left: boolean;
|
|
33
35
|
};
|
|
34
36
|
declare const EditableCell: import("svelte").Component<$$ComponentProps, {}, "value" | "el">;
|
|
35
37
|
type EditableCell = ReturnType<typeof EditableCell>;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import FilterIcon from "./icons/FilterIcon.svelte";
|
|
6
6
|
import SortButtonUp from "./icons/SortButtonUp.svelte";
|
|
7
7
|
import SortButtonDown from "./icons/SortButtonDown.svelte";
|
|
8
|
+
import { BaseCheckbox } from "@gradio/checkbox";
|
|
8
9
|
import type { I18nFormatter } from "js/core/src/gradio_helper";
|
|
9
10
|
import type { SortDirection } from "./types";
|
|
10
11
|
|
|
@@ -14,6 +15,8 @@
|
|
|
14
15
|
is_editing = false,
|
|
15
16
|
is_selected = false,
|
|
16
17
|
is_static = false,
|
|
18
|
+
is_bool = false,
|
|
19
|
+
select_all_state = "unchecked",
|
|
17
20
|
sort_direction = null,
|
|
18
21
|
sort_priority = null,
|
|
19
22
|
multi_sort = false,
|
|
@@ -25,15 +28,19 @@
|
|
|
25
28
|
editable = true,
|
|
26
29
|
max_chars = undefined,
|
|
27
30
|
i18n,
|
|
31
|
+
wrap_text = false,
|
|
28
32
|
onclick,
|
|
29
33
|
on_menu_click,
|
|
30
|
-
on_end_edit
|
|
34
|
+
on_end_edit,
|
|
35
|
+
on_select_all
|
|
31
36
|
}: {
|
|
32
37
|
value: string;
|
|
33
38
|
col_idx: number;
|
|
34
39
|
is_editing?: boolean;
|
|
35
40
|
is_selected?: boolean;
|
|
36
41
|
is_static?: boolean;
|
|
42
|
+
is_bool?: boolean;
|
|
43
|
+
select_all_state?: "checked" | "unchecked" | "indeterminate";
|
|
37
44
|
sort_direction?: SortDirection | null;
|
|
38
45
|
sort_priority?: number | null;
|
|
39
46
|
multi_sort?: boolean;
|
|
@@ -45,10 +52,16 @@
|
|
|
45
52
|
editable?: boolean;
|
|
46
53
|
max_chars?: number | undefined;
|
|
47
54
|
i18n: I18nFormatter;
|
|
55
|
+
wrap_text?: boolean;
|
|
48
56
|
onclick: (event: MouseEvent, col: number) => void;
|
|
49
57
|
on_menu_click: (event: MouseEvent, col: number) => void;
|
|
50
58
|
on_end_edit: (key: string) => void;
|
|
59
|
+
on_select_all?: (col: number, checked: boolean) => void;
|
|
51
60
|
} = $props();
|
|
61
|
+
|
|
62
|
+
let show_select_all = $derived(
|
|
63
|
+
is_bool && editable && !is_static && !!on_select_all
|
|
64
|
+
);
|
|
52
65
|
</script>
|
|
53
66
|
|
|
54
67
|
<th
|
|
@@ -57,6 +70,7 @@
|
|
|
57
70
|
class:sorted={sort_direction !== null}
|
|
58
71
|
class:filtered={is_filtered}
|
|
59
72
|
class:first-column={is_first_column}
|
|
73
|
+
data-heading={col_idx}
|
|
60
74
|
onclick={(e) => onclick(e, col_idx)}
|
|
61
75
|
onmousedown={(e) => {
|
|
62
76
|
e.preventDefault();
|
|
@@ -66,6 +80,25 @@
|
|
|
66
80
|
>
|
|
67
81
|
<div class="cell-wrap">
|
|
68
82
|
<div class="header-content">
|
|
83
|
+
{#if show_select_all}
|
|
84
|
+
<div
|
|
85
|
+
class="select-all-checkbox"
|
|
86
|
+
role="button"
|
|
87
|
+
tabindex="-1"
|
|
88
|
+
onclick={(e) => e.stopPropagation()}
|
|
89
|
+
onmousedown={(e) => e.stopPropagation()}
|
|
90
|
+
onkeydown={(e) => e.stopPropagation()}
|
|
91
|
+
>
|
|
92
|
+
<BaseCheckbox
|
|
93
|
+
value={select_all_state === "checked"}
|
|
94
|
+
indeterminate={select_all_state === "indeterminate"}
|
|
95
|
+
label={`Toggle all: ${value}`}
|
|
96
|
+
interactive={true}
|
|
97
|
+
on_select={() =>
|
|
98
|
+
on_select_all?.(col_idx, select_all_state !== "checked")}
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
{/if}
|
|
69
102
|
<EditableCell
|
|
70
103
|
{value}
|
|
71
104
|
{latex_delimiters}
|
|
@@ -81,7 +114,9 @@
|
|
|
81
114
|
{is_static}
|
|
82
115
|
{i18n}
|
|
83
116
|
{max_chars}
|
|
117
|
+
{wrap_text}
|
|
84
118
|
coords={[col_idx, 0]}
|
|
119
|
+
pad_left={show_select_all ? true : false}
|
|
85
120
|
/>
|
|
86
121
|
</div>
|
|
87
122
|
{#if sort_direction || is_filtered || is_static}
|
|
@@ -129,6 +164,13 @@
|
|
|
129
164
|
padding: 0;
|
|
130
165
|
background: var(--table-even-background-fill) !important;
|
|
131
166
|
font-weight: var(--weight-bold, 700);
|
|
167
|
+
outline: none;
|
|
168
|
+
box-shadow:
|
|
169
|
+
inset 1px 0 0 var(--border-color-primary),
|
|
170
|
+
inset 0 0 0 1px var(--ring-color);
|
|
171
|
+
padding: 0;
|
|
172
|
+
overflow: visible;
|
|
173
|
+
box-sizing: border-box;
|
|
132
174
|
}
|
|
133
175
|
|
|
134
176
|
.header-cell.first-column {
|
|
@@ -142,10 +184,14 @@
|
|
|
142
184
|
|
|
143
185
|
.header-cell.focus {
|
|
144
186
|
--ring-color: var(--color-accent);
|
|
187
|
+
--sel-top: inset 0 2px 0 0 var(--ring-color);
|
|
188
|
+
--sel-bottom: inset 0 -2px 0 0 var(--ring-color);
|
|
189
|
+
--sel-left: inset 2px 0 0 0 var(--ring-color);
|
|
190
|
+
--sel-right: inset -2px 0 0 0 var(--ring-color);
|
|
145
191
|
box-shadow:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
192
|
+
var(--sel-top), var(--sel-bottom), var(--sel-left), var(--sel-right);
|
|
193
|
+
z-index: 2;
|
|
194
|
+
position: relative;
|
|
149
195
|
}
|
|
150
196
|
|
|
151
197
|
.header-cell.focus.first-column {
|
|
@@ -155,7 +201,7 @@
|
|
|
155
201
|
.header-content {
|
|
156
202
|
display: flex;
|
|
157
203
|
align-items: center;
|
|
158
|
-
gap: var(--size-
|
|
204
|
+
gap: var(--size-3);
|
|
159
205
|
overflow: hidden;
|
|
160
206
|
min-width: 0;
|
|
161
207
|
}
|
|
@@ -215,4 +261,20 @@
|
|
|
215
261
|
overflow: visible;
|
|
216
262
|
min-width: 0;
|
|
217
263
|
}
|
|
264
|
+
|
|
265
|
+
.select-all-checkbox {
|
|
266
|
+
display: flex;
|
|
267
|
+
align-items: center;
|
|
268
|
+
justify-content: center;
|
|
269
|
+
flex-shrink: 0;
|
|
270
|
+
width: var(--size-4);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.select-all-checkbox :global(label) {
|
|
274
|
+
margin: 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.select-all-checkbox :global(span) {
|
|
278
|
+
display: none;
|
|
279
|
+
}
|
|
218
280
|
</style>
|
|
@@ -6,6 +6,8 @@ type $$ComponentProps = {
|
|
|
6
6
|
is_editing?: boolean;
|
|
7
7
|
is_selected?: boolean;
|
|
8
8
|
is_static?: boolean;
|
|
9
|
+
is_bool?: boolean;
|
|
10
|
+
select_all_state?: "checked" | "unchecked" | "indeterminate";
|
|
9
11
|
sort_direction?: SortDirection | null;
|
|
10
12
|
sort_priority?: number | null;
|
|
11
13
|
multi_sort?: boolean;
|
|
@@ -21,9 +23,11 @@ type $$ComponentProps = {
|
|
|
21
23
|
editable?: boolean;
|
|
22
24
|
max_chars?: number | undefined;
|
|
23
25
|
i18n: I18nFormatter;
|
|
26
|
+
wrap_text?: boolean;
|
|
24
27
|
onclick: (event: MouseEvent, col: number) => void;
|
|
25
28
|
on_menu_click: (event: MouseEvent, col: number) => void;
|
|
26
29
|
on_end_edit: (key: string) => void;
|
|
30
|
+
on_select_all?: (col: number, checked: boolean) => void;
|
|
27
31
|
};
|
|
28
32
|
declare const HeaderCell: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
29
33
|
type HeaderCell = ReturnType<typeof HeaderCell>;
|