@gradio/dataframe 0.23.1 → 0.23.3
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 +24 -0
- package/Dataframe.test.ts +232 -1
- 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 +9 -9
- 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
|
@@ -8,20 +8,87 @@ export function create_column_measurement(opts) {
|
|
|
8
8
|
let header_height = $state(0);
|
|
9
9
|
// use offsets (not just widths) avoids accumulated subpixel rounding errors
|
|
10
10
|
let col_lefts = $state([]);
|
|
11
|
+
function resolve_user_width(raw, vw) {
|
|
12
|
+
if (!raw || raw === "auto")
|
|
13
|
+
return null;
|
|
14
|
+
if (raw.endsWith("%")) {
|
|
15
|
+
const pct = parseFloat(raw);
|
|
16
|
+
if (!isFinite(pct) || vw <= 0)
|
|
17
|
+
return null;
|
|
18
|
+
return (pct / 100) * vw;
|
|
19
|
+
}
|
|
20
|
+
if (raw.endsWith("px")) {
|
|
21
|
+
const n = parseFloat(raw);
|
|
22
|
+
return isFinite(n) ? n : null;
|
|
23
|
+
}
|
|
24
|
+
const n = parseFloat(raw);
|
|
25
|
+
return isFinite(n) ? n : null;
|
|
26
|
+
}
|
|
27
|
+
function clear_pin(el) {
|
|
28
|
+
if (el.style.width)
|
|
29
|
+
el.style.width = "";
|
|
30
|
+
if (el.style.minWidth)
|
|
31
|
+
el.style.minWidth = "";
|
|
32
|
+
if (el.style.maxWidth)
|
|
33
|
+
el.style.maxWidth = "";
|
|
34
|
+
}
|
|
35
|
+
function pin(el, target) {
|
|
36
|
+
if (el.style.width !== target)
|
|
37
|
+
el.style.width = target;
|
|
38
|
+
if (el.style.minWidth !== target)
|
|
39
|
+
el.style.minWidth = target;
|
|
40
|
+
if (el.style.maxWidth !== target)
|
|
41
|
+
el.style.maxWidth = target;
|
|
42
|
+
}
|
|
11
43
|
function measure() {
|
|
12
44
|
const current_row_el = opts.header_row_el();
|
|
13
45
|
const current_table_el = opts.header_table_el();
|
|
14
|
-
if (!current_row_el)
|
|
46
|
+
if (!current_row_el || !current_table_el)
|
|
15
47
|
return;
|
|
16
|
-
const cells = current_row_el.querySelectorAll(".header-cell");
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
48
|
+
const cells = Array.from(current_row_el.querySelectorAll(".header-cell"));
|
|
49
|
+
// sizing-body mirrors the data columns to give auto-layout a read on
|
|
50
|
+
// body-content widths. we also pin its cells so user widths are
|
|
51
|
+
// honored exactly (otherwise the sizing row's nowrap min-content
|
|
52
|
+
// forces the column wider than the user asked for).
|
|
53
|
+
const sizing_tds_all = Array.from(current_table_el.querySelectorAll(".sizing-body > tr > td"));
|
|
54
|
+
const sizing_data_tds = opts.show_row_numbers()
|
|
55
|
+
? sizing_tds_all.slice(1)
|
|
56
|
+
: sizing_tds_all;
|
|
57
|
+
cells.forEach(clear_pin);
|
|
58
|
+
sizing_data_tds.forEach(clear_pin);
|
|
59
|
+
current_table_el.style.width = "auto";
|
|
60
|
+
current_table_el.getBoundingClientRect(); // force layout flush
|
|
61
|
+
const vw = opts.viewport_width();
|
|
62
|
+
const user_widths = opts.column_widths();
|
|
63
|
+
const next_widths = cells.map((cell, i) => {
|
|
64
|
+
const resolved = resolve_user_width(user_widths[i], vw);
|
|
65
|
+
if (resolved != null)
|
|
66
|
+
return resolved;
|
|
67
|
+
// cap auto-sized columns at the viewport so a single column
|
|
68
|
+
// can never be wider than the visible scroll area
|
|
69
|
+
const measured = cell.getBoundingClientRect().width;
|
|
70
|
+
return vw > 0 ? Math.min(measured, vw) : measured;
|
|
71
|
+
});
|
|
72
|
+
cells.forEach((cell, i) => pin(cell, `${next_widths[i]}px`));
|
|
73
|
+
sizing_data_tds.forEach((cell, i) => {
|
|
74
|
+
if (next_widths[i] == null)
|
|
75
|
+
return;
|
|
76
|
+
pin(cell, `${next_widths[i]}px`);
|
|
77
|
+
});
|
|
78
|
+
// set the table width to the sum of columns so auto-layout
|
|
79
|
+
// has no extra space to redistribute
|
|
80
|
+
let table_w = next_widths.reduce((a, b) => a + b, 0);
|
|
81
|
+
if (opts.show_row_numbers()) {
|
|
82
|
+
const rn = current_row_el.querySelector(".row-number-header");
|
|
83
|
+
if (rn)
|
|
84
|
+
table_w += rn.getBoundingClientRect().width;
|
|
24
85
|
}
|
|
86
|
+
current_table_el.style.width = `${table_w}px`;
|
|
87
|
+
const after_rect = current_table_el.getBoundingClientRect();
|
|
88
|
+
col_lefts = cells.map((c) => c.getBoundingClientRect().left - after_rect.left);
|
|
89
|
+
col_widths = next_widths;
|
|
90
|
+
total_header_width = after_rect.width;
|
|
91
|
+
header_height = after_rect.height;
|
|
25
92
|
opts.on_resize?.();
|
|
26
93
|
}
|
|
27
94
|
$effect(() => {
|
|
@@ -40,6 +107,11 @@ export function create_column_measurement(opts) {
|
|
|
40
107
|
cells.forEach((cell) => ro.observe(cell));
|
|
41
108
|
return () => ro.disconnect();
|
|
42
109
|
});
|
|
110
|
+
$effect(() => {
|
|
111
|
+
opts.viewport_width();
|
|
112
|
+
opts.column_widths();
|
|
113
|
+
measure();
|
|
114
|
+
});
|
|
43
115
|
let row_num_width = $derived.by(() => {
|
|
44
116
|
if (!opts.show_row_numbers())
|
|
45
117
|
return 0;
|
|
@@ -53,10 +125,11 @@ export function create_column_measurement(opts) {
|
|
|
53
125
|
if (col_widths[index] !== undefined) {
|
|
54
126
|
return `width: ${col_widths[index]}px; flex: 0 0 ${col_widths[index]}px;`;
|
|
55
127
|
}
|
|
56
|
-
const
|
|
57
|
-
if (
|
|
58
|
-
return `width: ${
|
|
59
|
-
|
|
128
|
+
const resolved = resolve_user_width(opts.column_widths()[index], opts.viewport_width());
|
|
129
|
+
if (resolved != null) {
|
|
130
|
+
return `width: ${resolved}px; flex: 0 0 ${resolved}px;`;
|
|
131
|
+
}
|
|
132
|
+
return "width: 150px; flex: 0 0 150px;";
|
|
60
133
|
}
|
|
61
134
|
return {
|
|
62
135
|
get col_widths() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradio/dataframe",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.3",
|
|
4
4
|
"description": "Gradio UI packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "",
|
|
@@ -15,15 +15,15 @@
|
|
|
15
15
|
"dequal": "^2.0.3",
|
|
16
16
|
"@tanstack/table-core": "^8.21.3",
|
|
17
17
|
"@tanstack/virtual-core": "^3.13.6",
|
|
18
|
-
"@gradio/atoms": "^0.
|
|
19
|
-
"@gradio/checkbox": "^0.
|
|
20
|
-
"@gradio/client": "^2.2.
|
|
21
|
-
"@gradio/icons": "^0.15.1",
|
|
18
|
+
"@gradio/atoms": "^0.24.0",
|
|
19
|
+
"@gradio/checkbox": "^0.7.0",
|
|
20
|
+
"@gradio/client": "^2.2.1",
|
|
22
21
|
"@gradio/button": "^0.6.6",
|
|
23
|
-
"@gradio/markdown-code": "^0.
|
|
24
|
-
"@gradio/statustracker": "^0.14.
|
|
25
|
-
"@gradio/
|
|
26
|
-
"@gradio/
|
|
22
|
+
"@gradio/markdown-code": "^0.8.0",
|
|
23
|
+
"@gradio/statustracker": "^0.14.1",
|
|
24
|
+
"@gradio/utils": "^0.12.2",
|
|
25
|
+
"@gradio/upload": "^0.17.10",
|
|
26
|
+
"@gradio/icons": "^0.15.1"
|
|
27
27
|
},
|
|
28
28
|
"exports": {
|
|
29
29
|
".": {
|
package/shared/DataCell.svelte
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
show_menu_button = false,
|
|
21
21
|
show_selection_buttons = false,
|
|
22
22
|
is_first_column = false,
|
|
23
|
+
is_solo = false,
|
|
23
24
|
latex_delimiters,
|
|
24
25
|
line_breaks = true,
|
|
25
26
|
editable = true,
|
|
@@ -50,6 +51,7 @@
|
|
|
50
51
|
show_menu_button?: boolean;
|
|
51
52
|
show_selection_buttons?: boolean;
|
|
52
53
|
is_first_column?: boolean;
|
|
54
|
+
is_solo?: boolean;
|
|
53
55
|
latex_delimiters: { left: string; right: string; display: boolean }[];
|
|
54
56
|
line_breaks?: boolean;
|
|
55
57
|
editable?: boolean;
|
|
@@ -71,21 +73,38 @@
|
|
|
71
73
|
} = $props();
|
|
72
74
|
|
|
73
75
|
let is_selected = $derived(selection_classes !== "");
|
|
76
|
+
|
|
77
|
+
// lock the cell-wrap's height to its pre-selection value so the
|
|
78
|
+
// row doesn't shift when the span goes position: absolute.
|
|
79
|
+
let wrap_el: HTMLDivElement | undefined = $state();
|
|
80
|
+
let locked_height = $state("");
|
|
81
|
+
|
|
82
|
+
// pre is weird but runs _before_ DOM updates
|
|
83
|
+
$effect.pre(() => {
|
|
84
|
+
if (is_solo && wrap_el) {
|
|
85
|
+
locked_height = `height: ${wrap_el.offsetHeight}px;`;
|
|
86
|
+
} else {
|
|
87
|
+
locked_height = "";
|
|
88
|
+
}
|
|
89
|
+
});
|
|
74
90
|
</script>
|
|
75
91
|
|
|
76
92
|
<div
|
|
77
93
|
class="body-cell {selection_classes}"
|
|
78
94
|
class:flash={is_flash}
|
|
79
95
|
class:first-column={is_first_column}
|
|
96
|
+
class:static={is_static}
|
|
97
|
+
class:cell-solo={is_solo}
|
|
80
98
|
data-row={row_idx}
|
|
81
99
|
data-col={col_idx}
|
|
82
100
|
data-testid={`cell-${row_idx}-${col_idx}`}
|
|
101
|
+
tabindex={is_static ? -1 : undefined}
|
|
83
102
|
{onmousedown}
|
|
84
103
|
{ondblclick}
|
|
85
104
|
{oncontextmenu}
|
|
86
105
|
style="{col_style} {cell_style}"
|
|
87
106
|
>
|
|
88
|
-
<div class="cell-wrap">
|
|
107
|
+
<div class="cell-wrap" bind:this={wrap_el} style={locked_height}>
|
|
89
108
|
<EditableCell
|
|
90
109
|
{value}
|
|
91
110
|
{display_value}
|
|
@@ -105,6 +124,7 @@
|
|
|
105
124
|
{on_select_row}
|
|
106
125
|
{is_dragging}
|
|
107
126
|
{wrap_text}
|
|
127
|
+
expanded={is_solo}
|
|
108
128
|
/>
|
|
109
129
|
{#if show_menu_button}
|
|
110
130
|
<CellMenuButton on_click={on_menu_click} />
|
|
@@ -120,8 +140,14 @@
|
|
|
120
140
|
inset 1px 0 0 var(--border-color-primary),
|
|
121
141
|
inset 0 0 0 1px var(--ring-color);
|
|
122
142
|
padding: 0;
|
|
123
|
-
overflow:
|
|
143
|
+
overflow: hidden;
|
|
124
144
|
box-sizing: border-box;
|
|
145
|
+
user-select: none;
|
|
146
|
+
min-width: 0;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.body-cell.static {
|
|
150
|
+
user-select: text;
|
|
125
151
|
}
|
|
126
152
|
|
|
127
153
|
.body-cell.first-column {
|
|
@@ -145,6 +171,65 @@
|
|
|
145
171
|
position: relative;
|
|
146
172
|
}
|
|
147
173
|
|
|
174
|
+
.body-cell.cell-solo {
|
|
175
|
+
z-index: 10;
|
|
176
|
+
overflow: visible;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.body-cell.cell-solo .cell-wrap {
|
|
180
|
+
overflow: visible;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.body-cell.cell-solo :global(.cell-wrap > span) {
|
|
184
|
+
position: absolute;
|
|
185
|
+
top: 0;
|
|
186
|
+
left: 0;
|
|
187
|
+
width: 100%;
|
|
188
|
+
min-height: 100%;
|
|
189
|
+
padding: var(--size-2);
|
|
190
|
+
box-sizing: border-box;
|
|
191
|
+
white-space: normal;
|
|
192
|
+
overflow: visible;
|
|
193
|
+
text-overflow: clip;
|
|
194
|
+
overflow-wrap: break-word;
|
|
195
|
+
word-break: break-word;
|
|
196
|
+
background: var(--background-fill-primary);
|
|
197
|
+
box-shadow:
|
|
198
|
+
inset 0 2px 0 0 var(--color-accent),
|
|
199
|
+
inset 0 -2px 0 0 var(--color-accent),
|
|
200
|
+
inset 2px 0 0 0 var(--color-accent),
|
|
201
|
+
inset -2px 0 0 0 var(--color-accent),
|
|
202
|
+
0 6px 12px -4px rgba(0, 0, 0, 0.22);
|
|
203
|
+
z-index: 1;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.body-cell.cell-solo :global(.cell-wrap > textarea) {
|
|
207
|
+
position: absolute;
|
|
208
|
+
top: 0;
|
|
209
|
+
left: 0;
|
|
210
|
+
width: 100%;
|
|
211
|
+
min-height: 100%;
|
|
212
|
+
padding: var(--size-2);
|
|
213
|
+
padding-left: var(--size-2);
|
|
214
|
+
margin: 0;
|
|
215
|
+
box-sizing: border-box;
|
|
216
|
+
transform: none;
|
|
217
|
+
background: var(--background-fill-primary);
|
|
218
|
+
box-shadow:
|
|
219
|
+
inset 0 2px 0 0 var(--color-accent),
|
|
220
|
+
inset 0 -2px 0 0 var(--color-accent),
|
|
221
|
+
inset 2px 0 0 0 var(--color-accent),
|
|
222
|
+
inset -2px 0 0 0 var(--color-accent),
|
|
223
|
+
0 6px 12px -4px rgba(0, 0, 0, 0.22);
|
|
224
|
+
z-index: 2;
|
|
225
|
+
field-sizing: content;
|
|
226
|
+
height: auto;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.body-cell.cell-solo :global(.selection-button) {
|
|
230
|
+
z-index: 3;
|
|
231
|
+
}
|
|
232
|
+
|
|
148
233
|
.body-cell.cell-selected.no-top {
|
|
149
234
|
--sel-top: inset 0 0 0 0 transparent;
|
|
150
235
|
}
|
|
@@ -182,7 +267,7 @@
|
|
|
182
267
|
padding: var(--size-2);
|
|
183
268
|
box-sizing: border-box;
|
|
184
269
|
gap: var(--size-1);
|
|
185
|
-
overflow:
|
|
270
|
+
overflow: hidden;
|
|
186
271
|
min-width: 0;
|
|
187
272
|
height: 100%;
|
|
188
273
|
}
|
|
@@ -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>
|
package/shared/HeaderCell.svelte
CHANGED
|
@@ -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>
|