mirror of
https://github.com/gradio-app/gradio.git
synced 2025-02-11 11:19:58 +08:00
Expand and collapse dataframe cells (#10463)
* - truncate long cell values - add expand and collapse logic * add changeset * tweak * add max_chars and single click expanding * - fix test - add story * Update gradio/components/dataframe.py Co-authored-by: Abubakar Abid <abubakar@huggingface.co> --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co>
This commit is contained in:
parent
ff5f976bbb
commit
ed7a0919ab
6
.changeset/soft-insects-greet.md
Normal file
6
.changeset/soft-insects-greet.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@gradio/dataframe": minor
|
||||
"gradio": minor
|
||||
---
|
||||
|
||||
feat:Expand and collapse dataframe cells
|
@ -99,6 +99,7 @@ class Dataframe(Component):
|
||||
show_fullscreen_button: bool = False,
|
||||
show_copy_button: bool = False,
|
||||
show_row_numbers: bool = False,
|
||||
max_chars: int | None = None,
|
||||
):
|
||||
"""
|
||||
Parameters:
|
||||
@ -129,6 +130,7 @@ class Dataframe(Component):
|
||||
show_fullscreen_button: If True, will show a button to view the values in the table in fullscreen mode.
|
||||
show_copy_button: If True, will show a button to copy the table data to the clipboard.
|
||||
show_row_numbers: If True, will display row numbers in a separate column.
|
||||
max_chars: Maximum number of characters to display in each cell before truncating (single-clicking a cell value will still reveal the full content). If None, no truncation is applied.
|
||||
"""
|
||||
self.wrap = wrap
|
||||
self.row_count = self.__process_counts(row_count)
|
||||
@ -165,6 +167,7 @@ class Dataframe(Component):
|
||||
self.show_fullscreen_button = show_fullscreen_button
|
||||
self.show_copy_button = show_copy_button
|
||||
self.show_row_numbers = show_row_numbers
|
||||
self.max_chars = max_chars
|
||||
super().__init__(
|
||||
label=label,
|
||||
every=every,
|
||||
|
@ -606,6 +606,7 @@ class Numpy(components.Dataframe):
|
||||
column_widths: list[str | int] | None = None,
|
||||
show_row_numbers: bool = False,
|
||||
show_fullscreen_button: bool = False,
|
||||
max_chars: int | None = None,
|
||||
show_copy_button: bool = False,
|
||||
):
|
||||
super().__init__(
|
||||
@ -634,6 +635,7 @@ class Numpy(components.Dataframe):
|
||||
min_width=min_width,
|
||||
show_row_numbers=show_row_numbers,
|
||||
show_fullscreen_button=show_fullscreen_button,
|
||||
max_chars=max_chars,
|
||||
show_copy_button=show_copy_button,
|
||||
)
|
||||
|
||||
@ -679,6 +681,7 @@ class Matrix(components.Dataframe):
|
||||
column_widths: list[str | int] | None = None,
|
||||
show_row_numbers: bool = False,
|
||||
show_fullscreen_button: bool = True,
|
||||
max_chars: int | None = None,
|
||||
show_copy_button: bool = False,
|
||||
):
|
||||
super().__init__(
|
||||
@ -707,6 +710,7 @@ class Matrix(components.Dataframe):
|
||||
min_width=min_width,
|
||||
show_row_numbers=show_row_numbers,
|
||||
show_fullscreen_button=show_fullscreen_button,
|
||||
max_chars=max_chars,
|
||||
show_copy_button=show_copy_button,
|
||||
)
|
||||
|
||||
@ -752,6 +756,7 @@ class List(components.Dataframe):
|
||||
column_widths: list[str | int] | None = None,
|
||||
show_row_numbers: bool = False,
|
||||
show_fullscreen_button: bool = True,
|
||||
max_chars: int | None = None,
|
||||
show_copy_button: bool = False,
|
||||
):
|
||||
super().__init__(
|
||||
@ -780,6 +785,7 @@ class List(components.Dataframe):
|
||||
min_width=min_width,
|
||||
show_row_numbers=show_row_numbers,
|
||||
show_fullscreen_button=show_fullscreen_button,
|
||||
max_chars=max_chars,
|
||||
show_copy_button=show_copy_button,
|
||||
)
|
||||
|
||||
|
@ -299,6 +299,34 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<Story
|
||||
name="Dataframe with truncated text"
|
||||
args={{
|
||||
values: [
|
||||
[
|
||||
"This is a very long text that should be truncated",
|
||||
"Short text",
|
||||
"Another very long text that needs truncation"
|
||||
],
|
||||
[
|
||||
"Short",
|
||||
"This text is also quite long and should be truncated as well",
|
||||
"Medium length text here"
|
||||
],
|
||||
[
|
||||
"Medium text",
|
||||
"Brief",
|
||||
"This is the longest text in the entire table and it should definitely be truncated"
|
||||
]
|
||||
],
|
||||
headers: ["Column A", "Column B", "Column C"],
|
||||
label: "Truncated Text Example",
|
||||
max_chars: 20,
|
||||
col_count: [3, "dynamic"],
|
||||
row_count: [3, "dynamic"]
|
||||
}}
|
||||
/>
|
||||
|
||||
<Story
|
||||
name="Dataframe with multiline headers"
|
||||
args={{
|
||||
|
@ -49,6 +49,7 @@
|
||||
export let loading_status: LoadingStatus;
|
||||
export let interactive: boolean;
|
||||
export let show_fullscreen_button = false;
|
||||
export let max_chars: number | undefined = undefined;
|
||||
export let show_copy_button = false;
|
||||
|
||||
$: _headers = [...(value.headers || headers)];
|
||||
@ -106,6 +107,7 @@
|
||||
stream_handler={(...args) => gradio.client.stream(...args)}
|
||||
bind:value_is_output
|
||||
{show_fullscreen_button}
|
||||
{max_chars}
|
||||
{show_copy_button}
|
||||
/>
|
||||
</Block>
|
||||
|
@ -23,12 +23,27 @@
|
||||
export let line_breaks = true;
|
||||
export let editable = true;
|
||||
export let root: string;
|
||||
export let max_chars: number | null = null;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
let is_expanded = false;
|
||||
|
||||
export let el: HTMLInputElement | null;
|
||||
$: _value = value;
|
||||
|
||||
function truncate_text(
|
||||
text: string | number,
|
||||
max_length: number | null = null
|
||||
): string {
|
||||
const str = String(text);
|
||||
if (!max_length || str.length <= max_length) return str;
|
||||
return str.slice(0, max_length) + "...";
|
||||
}
|
||||
|
||||
$: display_text = is_expanded
|
||||
? value
|
||||
: truncate_text(display_value || value, max_chars);
|
||||
|
||||
function use_focus(node: HTMLInputElement): any {
|
||||
if (clear_on_focus) {
|
||||
_value = "";
|
||||
@ -52,11 +67,21 @@
|
||||
|
||||
function handle_keydown(event: KeyboardEvent): void {
|
||||
if (event.key === "Enter") {
|
||||
value = _value;
|
||||
dispatch("blur");
|
||||
if (edit) {
|
||||
value = _value;
|
||||
dispatch("blur");
|
||||
} else if (!header) {
|
||||
is_expanded = !is_expanded;
|
||||
}
|
||||
}
|
||||
dispatch("keydown", event);
|
||||
}
|
||||
|
||||
function handle_click(): void {
|
||||
if (!edit && !header) {
|
||||
is_expanded = !is_expanded;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if edit}
|
||||
@ -76,28 +101,31 @@
|
||||
{/if}
|
||||
|
||||
<span
|
||||
on:dblclick
|
||||
tabindex="-1"
|
||||
on:click={handle_click}
|
||||
on:keydown={handle_keydown}
|
||||
tabindex="0"
|
||||
role="button"
|
||||
class:edit
|
||||
class:expanded={is_expanded}
|
||||
class:multiline={header}
|
||||
on:focus|preventDefault
|
||||
style={styling}
|
||||
class="table-cell-text"
|
||||
data-editable={editable}
|
||||
placeholder=" "
|
||||
>
|
||||
{#if datatype === "html"}
|
||||
{@html value}
|
||||
{@html display_text}
|
||||
{:else if datatype === "markdown"}
|
||||
<MarkdownCode
|
||||
message={value.toLocaleString()}
|
||||
message={display_text.toLocaleString()}
|
||||
{latex_delimiters}
|
||||
{line_breaks}
|
||||
chatbot={false}
|
||||
{root}
|
||||
/>
|
||||
{:else}
|
||||
{editable ? value : display_value || value}
|
||||
{editable ? display_text : display_value || display_text}
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
@ -118,6 +146,8 @@
|
||||
|
||||
span {
|
||||
flex: 1 1 0%;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
outline: none;
|
||||
padding: var(--size-2);
|
||||
-webkit-user-select: text;
|
||||
@ -125,6 +155,19 @@
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
cursor: text;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
input:where(:not(.header), [data-editable="true"]) {
|
||||
width: calc(100% - var(--size-10));
|
||||
}
|
||||
|
||||
span.expanded {
|
||||
height: auto;
|
||||
min-height: 100%;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
@ -135,6 +178,8 @@
|
||||
.header {
|
||||
transform: translateX(0);
|
||||
font-weight: var(--weight-bold);
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.edit {
|
||||
|
@ -57,6 +57,7 @@
|
||||
export let show_fullscreen_button = false;
|
||||
export let show_copy_button = false;
|
||||
export let value_is_output = false;
|
||||
export let max_chars: number | undefined = undefined;
|
||||
|
||||
let selected_cells: CellCoordinate[] = [];
|
||||
$: selected_cells = [...selected_cells];
|
||||
@ -912,6 +913,7 @@
|
||||
<div class="cell-wrap">
|
||||
<div class="header-content">
|
||||
<EditableCell
|
||||
{max_chars}
|
||||
bind:value={_headers[i].value}
|
||||
bind:el={els[id].input}
|
||||
{latex_delimiters}
|
||||
@ -1012,6 +1014,7 @@
|
||||
}}
|
||||
{clear_on_focus}
|
||||
{root}
|
||||
{max_chars}
|
||||
/>
|
||||
{#if editable && should_show_cell_menu([index, j], selected_cells, editable)}
|
||||
<button
|
||||
@ -1216,11 +1219,11 @@
|
||||
|
||||
.cell-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
outline: none;
|
||||
height: var(--size-full);
|
||||
min-height: var(--size-9);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
@ -1254,10 +1257,10 @@
|
||||
padding: 0;
|
||||
margin-right: var(--spacing-sm);
|
||||
z-index: var(--layer-1);
|
||||
}
|
||||
|
||||
.cell-menu-button:hover {
|
||||
background-color: var(--color-bg-hover);
|
||||
position: absolute;
|
||||
right: var(--size-1);
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.cell-selected .cell-menu-button {
|
||||
|
@ -57,6 +57,7 @@ class TestDataframe:
|
||||
"column_widths": [],
|
||||
"show_fullscreen_button": False,
|
||||
"show_copy_button": False,
|
||||
"max_chars": None,
|
||||
}
|
||||
dataframe_input = gr.Dataframe()
|
||||
output = dataframe_input.preprocess(DataframeData(**x_data))
|
||||
@ -103,6 +104,7 @@ class TestDataframe:
|
||||
"line_breaks": True,
|
||||
"column_widths": [],
|
||||
"show_fullscreen_button": False,
|
||||
"max_chars": None,
|
||||
"show_copy_button": False,
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user