CoolFace
Datasetpublic

gradio/frontend

sourceHugging Faceupdated 10h agoView on Hugging Face
1likes413kdownloads
TableHeader.svelte345 linesDownload Raw Back to shared
1<script lang="ts">2	import EditableCell from "./EditableCell.svelte";3	import CellMenuButton from "./CellMenuButton.svelte";4	import type { I18nFormatter } from "js/core/src/gradio_helper";5	import { get_sort_status } from "./utils/sort_utils";6	import Padlock from "./icons/Padlock.svelte";7	import SortArrowUp from "./icons/SortArrowUp.svelte";8	import SortArrowDown from "./icons/SortArrowDown.svelte";9	import type { SortDirection } from "./context/dataframe_context";10	import CellMenuIcons from "./CellMenuIcons.svelte";11	import type { FilterDatatype } from "./context/dataframe_context";12	import type { Datatype } from "./utils/utils";13	import { BaseCheckbox } from "@gradio/checkbox";14	export let value: string;15	export let i: number;16	export let datatype: Datatype = "str";17	export let actual_pinned_columns: number;18	export let header_edit: number | false;19	export let selected_header: number | false;20	export let headers: string[];21	export let get_cell_width: (index: number) => string;22	export let handle_header_click: (event: MouseEvent, col: number) => void;23	export let toggle_header_menu: (event: MouseEvent, col: number) => void;24	export let end_header_edit: (event: CustomEvent<KeyboardEvent>) => void;25	export let sort_columns: { col: number; direction: SortDirection }[] = [];26	export let filter_columns: {27		col: number;28		datatype: FilterDatatype;29		filter: string;30		value: string;31	}[] = [];32 33	export let latex_delimiters: {34		left: string;35		right: string;36		display: boolean;37	}[];38	export let line_breaks: boolean;39	export let max_chars: number | undefined;40	export let editable: boolean;41	export let i18n: I18nFormatter;42	export let el: HTMLTextAreaElement | null;43	export let is_static: boolean;44	export let col_count: [number, "fixed" | "dynamic"];45	export let data: any[] = [];46	export let on_select_all:47		| ((col: number, checked: boolean) => void)48		| undefined = undefined;49 50	$: can_add_columns = col_count && col_count[1] === "dynamic";51	$: is_bool_column = datatype === "bool";52 53	$: select_all_state = (() => {54		if (!is_bool_column || data.length === 0) return "unchecked";55		const true_count = data.filter(56			(row) => row[i]?.value === true || row[i]?.value === "true"57		).length;58		if (true_count === 0) return "unchecked";59		if (true_count === data.length) return "checked";60		return "indeterminate";61	})();62 63	$: sort_index = sort_columns.findIndex((item) => item.col === i);64	$: filter_index = filter_columns.findIndex((item) => item.col === i);65	$: sort_priority = sort_index !== -1 ? sort_index + 1 : null;66	$: current_direction =67		sort_index !== -1 ? sort_columns[sort_index].direction : null;68 69	function get_header_position(col_index: number): string {70		if (col_index >= actual_pinned_columns) {71			return "auto";72		}73 74		if (col_index === 0) {75			return "0";76		}77 78		const previous_widths = Array(col_index)79			.fill(0)80			.map((_, idx) => {81				return get_cell_width(idx);82			})83			.join(" + ");84 85		return `calc(${previous_widths})`;86	}87</script>88 89<th90	class:pinned-column={i < actual_pinned_columns}91	class:last-pinned={i === actual_pinned_columns - 1}92	class:focus={header_edit === i || selected_header === i}93	class:sorted={sort_index !== -1}94	class:filtered={filter_index !== -1}95	aria-sort={get_sort_status(value, sort_columns, headers) === "none"96		? "none"97		: get_sort_status(value, sort_columns, headers) === "asc"98			? "ascending"99			: "descending"}100	style="width: {get_cell_width(i)}; left: {get_header_position(i)};"101	on:click={(event) => handle_header_click(event, i)}102	on:mousedown={(event) => {103		event.preventDefault();104		event.stopPropagation();105	}}106	title={value}107>108	<div class="cell-wrap">109		<div class="header-content">110			{#if is_bool_column && editable && on_select_all}111				<div112					class="select-all-checkbox"113					role="button"114					tabindex="0"115					on:click|stopPropagation116					on:keydown|stopPropagation={(e) => {117						if (e.key === "Enter" || e.key === " ") {118							e.preventDefault();119						}120					}}121					on:mousedown|stopPropagation122				>123					<BaseCheckbox124						value={select_all_state === "checked"}125						indeterminate={select_all_state === "indeterminate"}126						label=""127						interactive={true}128						on:select={() => {129							if (on_select_all) {130								const new_value = select_all_state !== "checked";131								on_select_all(i, new_value);132							}133						}}134					/>135				</div>136			{/if}137			<button138				class="header-button"139				on:click={(event) => handle_header_click(event, i)}140				on:mousedown={(event) => {141					event.preventDefault();142					event.stopPropagation();143				}}144				title={value}145			>146				<EditableCell147					{max_chars}148					bind:value149					bind:el150					{latex_delimiters}151					{line_breaks}152					edit={header_edit === i}153					on:keydown={(event) => {154						if (155							event.detail.key === "Enter" ||156							event.detail.key === "Escape" ||157							event.detail.key === "Tab"158						) {159							end_header_edit(event);160						}161					}}162					header163					{editable}164					{is_static}165					{i18n}166					coords={[i, 0]}167				/>168				{#if sort_index !== -1}169					<div class="sort-indicators">170						<span class="sort-arrow">171							{#if current_direction === "asc"}172								<SortArrowUp size={12} />173							{:else}174								<SortArrowDown size={12} />175							{/if}176						</span>177						{#if sort_columns.length > 1}178							<span class="sort-priority">179								{sort_priority}180							</span>181						{/if}182					</div>183				{/if}184				{#if filter_index !== -1}185					<div class="filter-indicators">186						<span class="filter-icon">187							<CellMenuIcons icon="filter" />188						</span>189					</div>190				{/if}191			</button>192			{#if is_static}193				<Padlock />194			{/if}195		</div>196		{#if can_add_columns}197			<CellMenuButton on_click={(event) => toggle_header_menu(event, i)} />198		{/if}199	</div>200</th>201 202<style>203	th {204		--ring-color: transparent;205		position: relative;206		outline: none;207		box-shadow: inset 0 0 0 1px var(--ring-color);208		padding: 0;209		background: var(--table-even-background-fill);210		border-right-width: 0px;211		border-left-width: 1px;212		border-style: solid;213		border-color: var(--border-color-primary);214	}215 216	th:first-child {217		border-top-left-radius: var(--table-radius);218		border-bottom-left-radius: var(--table-radius);219		border-left-width: 0px;220	}221 222	th:last-child {223		border-top-right-radius: var(--table-radius);224		border-bottom-right-radius: var(--table-radius);225	}226 227	th.focus {228		--ring-color: var(--color-accent);229		box-shadow: inset 0 0 0 2px var(--ring-color);230		z-index: 4;231	}232 233	th.focus :global(.cell-menu-button) {234		display: flex;235	}236 237	th:hover :global(.cell-menu-button) {238		display: flex;239	}240 241	.cell-wrap {242		display: flex;243		align-items: center;244		justify-content: flex-start;245		outline: none;246		min-height: var(--size-9);247		position: relative;248		height: 100%;249		padding: var(--size-2);250		box-sizing: border-box;251		margin: 0;252		gap: var(--size-1);253		overflow: visible;254		min-width: 0;255		border-radius: var(--table-radius);256	}257 258	.header-content {259		display: flex;260		align-items: center;261		overflow: hidden;262		flex-grow: 1;263		min-width: 0;264		white-space: normal;265		overflow-wrap: break-word;266		word-break: normal;267		height: 100%;268		gap: var(--size-1);269	}270 271	.header-button {272		display: flex;273		text-align: left;274		width: 100%;275		overflow: hidden;276		text-overflow: ellipsis;277		display: flex;278		align-items: center;279		position: relative;280	}281 282	.sort-indicators {283		display: flex;284		align-items: center;285		margin-left: var(--size-1);286		gap: var(--size-1);287	}288 289	.sort-arrow {290		display: flex;291		align-items: center;292		justify-content: center;293		color: var(--body-text-color);294	}295 296	.sort-priority {297		display: flex;298		align-items: center;299		justify-content: center;300		font-size: var(--size-2);301		background-color: var(--button-secondary-background-fill);302		color: var(--body-text-color);303		border-radius: var(--radius-sm);304		width: var(--size-2-5);305		height: var(--size-2-5);306		padding: var(--size-1-5);307	}308 309	.filter-indicators {310		display: flex;311		align-items: center;312		margin-left: var(--size-1);313		gap: var(--size-1);314	}315 316	.filter-icon {317		display: flex;318		align-items: center;319		justify-content: center;320		color: var(--body-text-color);321	}322 323	.pinned-column {324		position: sticky;325		z-index: 5;326		border-right: none;327	}328 329	.select-all-checkbox {330		display: flex;331		align-items: center;332		justify-content: center;333		margin-right: var(--size-1);334		flex-shrink: 0;335	}336 337	.select-all-checkbox :global(label) {338		margin: 0;339	}340 341	.select-all-checkbox :global(span) {342		display: none;343	}344</style>345