adf0d17497
publish / version_or_publish (push) Has been cancelled
storybook-build / changes (push) Has been cancelled
storybook-build / :storybook-build (push) Has been cancelled
Sync Gradio Skills to Hugging Face / sync-skills (push) Has been cancelled
functional / changes (push) Has been cancelled
functional / build-frontend (push) Has been cancelled
functional / functional-test-SSR=false (push) Has been cancelled
functional / functional-reload (push) Has been cancelled
js / changes (push) Has been cancelled
js / js-test (push) Has been cancelled
docs-build / changes (push) Has been cancelled
docs-build / docs-build (push) Has been cancelled
docs-build / website-build (push) Has been cancelled
functional / functional-test-SSR=true (push) Has been cancelled
hygiene / hygiene-test (push) Has been cancelled
python / changes (push) Has been cancelled
python / build (push) Has been cancelled
python / test-ubuntu-latest-flaky (push) Has been cancelled
python / test-ubuntu-latest-not-flaky (push) Has been cancelled
python / test-windows-latest-flaky (push) Has been cancelled
python / test-windows-latest-not-flaky (push) Has been cancelled
281 lines
6.3 KiB
Svelte
281 lines
6.3 KiB
Svelte
<script lang="ts">
|
|
import EditableCell from "./EditableCell.svelte";
|
|
import CellMenuButton from "./CellMenuButton.svelte";
|
|
import Padlock from "./icons/Padlock.svelte";
|
|
import FilterIcon from "./icons/FilterIcon.svelte";
|
|
import SortButtonUp from "./icons/SortButtonUp.svelte";
|
|
import SortButtonDown from "./icons/SortButtonDown.svelte";
|
|
import { BaseCheckbox } from "@gradio/checkbox";
|
|
import type { I18nFormatter } from "js/core/src/gradio_helper";
|
|
import type { SortDirection } from "./types";
|
|
|
|
let {
|
|
value,
|
|
col_idx,
|
|
is_editing = false,
|
|
is_selected = false,
|
|
is_static = false,
|
|
is_bool = false,
|
|
select_all_state = "unchecked",
|
|
sort_direction = null,
|
|
sort_priority = null,
|
|
multi_sort = false,
|
|
is_filtered = false,
|
|
show_menu_button = false,
|
|
is_first_column = false,
|
|
latex_delimiters,
|
|
line_breaks = true,
|
|
editable = true,
|
|
max_chars = undefined,
|
|
i18n,
|
|
wrap_text = false,
|
|
onclick,
|
|
on_menu_click,
|
|
on_end_edit,
|
|
on_select_all
|
|
}: {
|
|
value: string;
|
|
col_idx: number;
|
|
is_editing?: boolean;
|
|
is_selected?: boolean;
|
|
is_static?: boolean;
|
|
is_bool?: boolean;
|
|
select_all_state?: "checked" | "unchecked" | "indeterminate";
|
|
sort_direction?: SortDirection | null;
|
|
sort_priority?: number | null;
|
|
multi_sort?: boolean;
|
|
is_filtered?: boolean;
|
|
show_menu_button?: boolean;
|
|
is_first_column?: boolean;
|
|
latex_delimiters: { left: string; right: string; display: boolean }[];
|
|
line_breaks?: boolean;
|
|
editable?: boolean;
|
|
max_chars?: number | undefined;
|
|
i18n: I18nFormatter;
|
|
wrap_text?: boolean;
|
|
onclick: (event: MouseEvent, col: number) => void;
|
|
on_menu_click: (event: MouseEvent, col: number) => void;
|
|
on_end_edit: (key: string) => void;
|
|
on_select_all?: (col: number, checked: boolean) => void;
|
|
} = $props();
|
|
|
|
let show_select_all = $derived(
|
|
is_bool && editable && !is_static && !!on_select_all
|
|
);
|
|
</script>
|
|
|
|
<th
|
|
class="header-cell"
|
|
class:focus={is_editing || is_selected}
|
|
class:sorted={sort_direction !== null}
|
|
class:filtered={is_filtered}
|
|
class:first-column={is_first_column}
|
|
data-heading={col_idx}
|
|
onclick={(e) => onclick(e, col_idx)}
|
|
onmousedown={(e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}}
|
|
title={value}
|
|
>
|
|
<div class="cell-wrap">
|
|
<div class="header-content">
|
|
{#if show_select_all}
|
|
<div
|
|
class="select-all-checkbox"
|
|
role="button"
|
|
tabindex="-1"
|
|
onclick={(e) => e.stopPropagation()}
|
|
onmousedown={(e) => e.stopPropagation()}
|
|
onkeydown={(e) => e.stopPropagation()}
|
|
>
|
|
<BaseCheckbox
|
|
value={select_all_state === "checked"}
|
|
indeterminate={select_all_state === "indeterminate"}
|
|
label={`Toggle all: ${value}`}
|
|
interactive={true}
|
|
on_select={() =>
|
|
on_select_all?.(col_idx, select_all_state !== "checked")}
|
|
/>
|
|
</div>
|
|
{/if}
|
|
<EditableCell
|
|
{value}
|
|
{latex_delimiters}
|
|
{line_breaks}
|
|
edit={is_editing}
|
|
onkeydown={(event) => {
|
|
if (["Enter", "Escape", "Tab"].includes(event.key)) {
|
|
on_end_edit(event.key);
|
|
}
|
|
}}
|
|
header
|
|
{editable}
|
|
{is_static}
|
|
{i18n}
|
|
{max_chars}
|
|
{wrap_text}
|
|
coords={[col_idx, 0]}
|
|
pad_left={show_select_all ? true : false}
|
|
/>
|
|
</div>
|
|
{#if sort_direction || is_filtered || is_static}
|
|
<span class="header-icons">
|
|
{#if is_filtered}
|
|
<span class="filter-indicator" aria-label="Filtered">
|
|
<FilterIcon />
|
|
</span>
|
|
{/if}
|
|
{#if sort_direction}
|
|
<span
|
|
class="sort-indicator"
|
|
aria-label="Sorted {sort_direction}ending"
|
|
>
|
|
{#if sort_direction === "asc"}
|
|
<SortButtonUp size={13} />
|
|
{:else}
|
|
<SortButtonDown size={13} />
|
|
{/if}
|
|
{#if multi_sort && sort_priority != null}
|
|
<span class="sort-priority">{sort_priority}</span>
|
|
{/if}
|
|
</span>
|
|
{/if}
|
|
|
|
{#if is_static}
|
|
<Padlock size={11} />
|
|
{/if}
|
|
</span>
|
|
{/if}
|
|
{#if show_menu_button}
|
|
<CellMenuButton on_click={(e) => on_menu_click(e, col_idx)} />
|
|
{/if}
|
|
</div>
|
|
</th>
|
|
|
|
<style>
|
|
.header-cell {
|
|
--ring-color: transparent;
|
|
position: relative;
|
|
outline: none;
|
|
box-shadow:
|
|
inset 1px 0 0 var(--border-color-primary),
|
|
inset 0 0 0 1px var(--ring-color);
|
|
padding: 0;
|
|
background: var(--table-even-background-fill) !important;
|
|
font-weight: var(--weight-bold, 700);
|
|
outline: none;
|
|
box-shadow:
|
|
inset 1px 0 0 var(--border-color-primary),
|
|
inset 0 0 0 1px var(--ring-color);
|
|
padding: 0;
|
|
overflow: visible;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.header-cell.first-column {
|
|
box-shadow: inset 0 0 0 1px var(--ring-color);
|
|
}
|
|
|
|
.header-cell:hover :global(.cell-menu-button),
|
|
.header-cell.focus :global(.cell-menu-button) {
|
|
display: flex;
|
|
}
|
|
|
|
.header-cell.focus {
|
|
--ring-color: var(--color-accent);
|
|
--sel-top: inset 0 2px 0 0 var(--ring-color);
|
|
--sel-bottom: inset 0 -2px 0 0 var(--ring-color);
|
|
--sel-left: inset 2px 0 0 0 var(--ring-color);
|
|
--sel-right: inset -2px 0 0 0 var(--ring-color);
|
|
box-shadow:
|
|
var(--sel-top), var(--sel-bottom), var(--sel-left), var(--sel-right);
|
|
z-index: 2;
|
|
position: relative;
|
|
}
|
|
|
|
.header-cell.focus.first-column {
|
|
box-shadow: inset 0 0 0 2px var(--ring-color);
|
|
}
|
|
|
|
.header-content {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--size-3);
|
|
overflow: hidden;
|
|
min-width: 0;
|
|
}
|
|
|
|
.header-icons {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 2px;
|
|
flex-shrink: 0;
|
|
margin-left: auto;
|
|
opacity: 0.6;
|
|
}
|
|
|
|
.sort-indicator {
|
|
display: flex;
|
|
align-items: center;
|
|
position: relative;
|
|
margin-left: -5px;
|
|
}
|
|
|
|
.sort-priority {
|
|
font-size: 8px;
|
|
background: var(--button-secondary-background-fill);
|
|
border-radius: var(--radius-full);
|
|
width: 12px;
|
|
height: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
line-height: 1;
|
|
}
|
|
|
|
.filter-indicator {
|
|
display: flex;
|
|
align-items: center;
|
|
width: 16px;
|
|
height: 16px;
|
|
margin-top: 3px;
|
|
}
|
|
|
|
.filter-indicator :global(svg) {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.cell-wrap {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-start;
|
|
outline: none;
|
|
min-height: var(--size-9);
|
|
position: relative;
|
|
height: 100%;
|
|
padding: var(--size-2);
|
|
box-sizing: border-box;
|
|
gap: var(--size-1);
|
|
overflow: visible;
|
|
min-width: 0;
|
|
}
|
|
|
|
.select-all-checkbox {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-shrink: 0;
|
|
width: var(--size-4);
|
|
}
|
|
|
|
.select-all-checkbox :global(label) {
|
|
margin: 0;
|
|
}
|
|
|
|
.select-all-checkbox :global(span) {
|
|
display: none;
|
|
}
|
|
</style>
|