Spaces:
Running
Running
| <script lang="ts"> | |
| import Dataframe from "@gradio/dataframe"; | |
| import { onMount } from "svelte"; | |
| import ConfigPanel from "./lib/ConfigPanel.svelte"; | |
| import SyntaxHighlighter from "./lib/SyntaxHighlighter.svelte"; | |
| import { sampleDatasets } from "./lib/sampleData"; | |
| // Configuration state | |
| let selectedDataset = "basic"; | |
| let value = { | |
| data: sampleDatasets.basic.data, | |
| headers: sampleDatasets.basic.headers, | |
| metadata: null | |
| }; | |
| let datatype: string[] = sampleDatasets.basic.datatypes; | |
| let editable = sampleDatasets.basic.config.editable; | |
| let show_row_numbers = sampleDatasets.basic.config.show_row_numbers; | |
| let show_search: "none" | "search" | "filter" = sampleDatasets.basic.config.show_search; | |
| let show_copy_button = sampleDatasets.basic.config.show_copy_button; | |
| let show_fullscreen_button = sampleDatasets.basic.config.show_fullscreen_button; | |
| let show_label = sampleDatasets.basic.config.show_label; | |
| let label = sampleDatasets.basic.config.label; | |
| let max_height = sampleDatasets.basic.config.max_height; | |
| let line_breaks = sampleDatasets.basic.config.line_breaks; | |
| let wrap = sampleDatasets.basic.config.wrap; | |
| let column_widths: string[] = []; | |
| let max_chars: number | undefined = sampleDatasets.basic.config.max_chars; | |
| // Theme state | |
| let currentTheme = "default"; | |
| // Active view state | |
| let activeView = "canvas"; // "canvas", "docs", "events", "source" | |
| // Mobile responsive state | |
| let showLeftPanel = false; | |
| let showRightPanel = true; // Show controls by default | |
| // Resizable controls panel | |
| let controlsHeight = 220; // Default height | |
| let isDragging = false; | |
| let dragStartY = 0; | |
| let dragStartHeight = 0; | |
| // Event handlers | |
| function handleChange(e: CustomEvent) { | |
| console.log("Data changed:", e.detail); | |
| value = e.detail; | |
| } | |
| function handleSelect(e: CustomEvent) { | |
| console.log("Cell selected:", e.detail); | |
| } | |
| function handleInput(e: CustomEvent) { | |
| console.log("Input event:", e.detail); | |
| } | |
| function handleDatasetChange(e: CustomEvent) { | |
| const dataset = e.detail.dataset; | |
| selectedDataset = dataset; | |
| const data = sampleDatasets[dataset as keyof typeof sampleDatasets]; | |
| value = { | |
| data: data.data, | |
| headers: data.headers, | |
| metadata: null | |
| }; | |
| datatype = data.datatypes; | |
| } | |
| function handleThemeChange(e: CustomEvent) { | |
| const theme = e.detail.theme; | |
| currentTheme = theme; | |
| const body = document.body; | |
| body.className = body.className.replace(/\b(dark|purple-theme|green-theme|orange-theme)\b/g, ''); | |
| if (theme !== 'default') { | |
| body.classList.add(theme); | |
| } | |
| } | |
| function switchDataset(dataset: string) { | |
| selectedDataset = dataset; | |
| const data = sampleDatasets[dataset as keyof typeof sampleDatasets]; | |
| value = { | |
| data: data.data, | |
| headers: data.headers, | |
| metadata: null | |
| }; | |
| datatype = data.datatypes; | |
| // Apply configuration from the dataset | |
| const config = data.config; | |
| editable = config.editable; | |
| show_row_numbers = config.show_row_numbers; | |
| show_search = config.show_search; | |
| show_copy_button = config.show_copy_button; | |
| show_fullscreen_button = config.show_fullscreen_button; | |
| show_label = config.show_label; | |
| label = config.label; | |
| max_height = config.max_height; | |
| line_breaks = config.line_breaks; | |
| wrap = config.wrap; | |
| max_chars = config.max_chars; | |
| // Switch to canvas view to show the selected example | |
| activeView = 'canvas'; | |
| } | |
| function applyTheme(theme: string) { | |
| currentTheme = theme; | |
| const body = document.body; | |
| body.className = body.className.replace(/\b(dark|purple-theme|green-theme|orange-theme)\b/g, ''); | |
| if (theme !== 'default') { | |
| body.classList.add(theme); | |
| } | |
| } | |
| function setActiveView(view: string) { | |
| activeView = view; | |
| } | |
| function getExampleIcon(key: string): string { | |
| const icons: Record<string, string> = { | |
| basic: 'π', | |
| compact: 'π', | |
| filterable: 'π', | |
| readonly: 'π', | |
| wrapped: 'π', | |
| large: 'π', | |
| mixed: 'π¨', | |
| minimal: 'β‘' | |
| }; | |
| return icons[key] || 'π'; | |
| } | |
| function getExampleTitle(key: string): string { | |
| const titles: Record<string, string> = { | |
| basic: 'Basic Example', | |
| compact: 'Compact View', | |
| filterable: 'Filter & Search', | |
| readonly: 'Read-Only', | |
| wrapped: 'Text Wrapping', | |
| large: 'Large Dataset', | |
| mixed: 'Rich Content', | |
| minimal: 'Minimal UI' | |
| }; | |
| return titles[key] || key.charAt(0).toUpperCase() + key.slice(1); | |
| } | |
| function getExampleDescription(key: string): string { | |
| const descriptions: Record<string, string> = { | |
| basic: 'Standard configuration with all features', | |
| compact: 'Minimal UI, no controls', | |
| filterable: 'Advanced filtering capabilities', | |
| readonly: 'Non-editable data display', | |
| wrapped: 'Long text with wrapping', | |
| large: 'Performance with 50 rows', | |
| mixed: 'HTML & Markdown support', | |
| minimal: 'Bare minimum interface' | |
| }; | |
| return descriptions[key] || 'Example configuration'; | |
| } | |
| function handleAddColumn() { | |
| const newHeaders = [...value.headers, `Column ${value.headers.length + 1}`]; | |
| const newData = value.data.map((row: any) => [...row, ""]); | |
| value = { | |
| ...value, | |
| headers: newHeaders, | |
| data: newData | |
| }; | |
| datatype = [...datatype, "str"]; | |
| } | |
| function handleAddRow() { | |
| const newRow = Array(value.headers.length).fill(""); | |
| value = { | |
| ...value, | |
| data: [...value.data, newRow] | |
| }; | |
| } | |
| // Resizable controls panel handlers | |
| function handleDragStart(e: MouseEvent) { | |
| isDragging = true; | |
| dragStartY = e.clientY; | |
| dragStartHeight = controlsHeight; | |
| document.body.classList.add('dragging'); | |
| document.addEventListener('mousemove', handleDragMove); | |
| document.addEventListener('mouseup', handleDragEnd); | |
| e.preventDefault(); | |
| } | |
| function handleDragMove(e: MouseEvent) { | |
| if (!isDragging) return; | |
| const deltaY = dragStartY - e.clientY; // Inverted because we want up movement to increase height | |
| const newHeight = Math.max(180, Math.min(500, dragStartHeight + deltaY)); // Min 180px, max 500px | |
| controlsHeight = newHeight; | |
| } | |
| function handleDragEnd() { | |
| isDragging = false; | |
| document.body.classList.remove('dragging'); | |
| document.removeEventListener('mousemove', handleDragMove); | |
| document.removeEventListener('mouseup', handleDragEnd); | |
| } | |
| onMount(() => { | |
| if (currentTheme !== 'default') { | |
| document.body.classList.add(currentTheme); | |
| } | |
| }); | |
| </script> | |
| <!-- Storybook-style layout --> | |
| <div class="min-h-screen bg-[#f6f9fc] flex flex-col"> | |
| <!-- Storybook Header --> | |
| <header class="h-16 bg-white border-b-2 border-[#d1d5db] flex items-center px-4 md:px-6 relative z-20"> | |
| <!-- Mobile Menu Buttons --> | |
| <div class="flex items-center space-x-2 md:hidden"> | |
| <button | |
| on:click={() => currentTheme === 'dark' ? applyTheme('default') : applyTheme('dark')} | |
| class="p-2 text-[#73828c] hover:text-[#2e3438] hover:bg-[#f6f9fc] rounded-lg transition-all duration-200" | |
| aria-label="Toggle dark mode" | |
| title="Toggle dark/light mode" | |
| > | |
| {#if currentTheme === 'dark'} | |
| <span class="text-lg">βοΈ</span> | |
| {:else} | |
| <span class="text-lg">π</span> | |
| {/if} | |
| </button> | |
| <button | |
| on:click={() => showLeftPanel = !showLeftPanel} | |
| class="p-2 text-[#73828c] hover:text-[#2e3438] hover:bg-[#f6f9fc] rounded-lg transition-all duration-200" | |
| aria-label="Toggle navigation menu" | |
| > | |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path> | |
| </svg> | |
| </button> | |
| <button | |
| on:click={() => showRightPanel = !showRightPanel} | |
| class="p-2 text-[#73828c] hover:text-[#2e3438] hover:bg-[#f6f9fc] rounded-lg transition-all duration-200" | |
| aria-label="Toggle controls panel" | |
| > | |
| <svg class="w-5 h-5" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| <path d="M10.0503 10.6066L2.97923 17.6777C2.19818 18.4587 2.19818 19.725 2.97923 20.5061V20.5061C3.76027 21.2871 5.0266 21.2871 5.80765 20.5061L12.8787 13.435" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path> | |
| <path d="M10.0502 10.6066C9.20638 8.45358 9.37134 5.6286 11.1109 3.88909C12.8504 2.14957 16.0606 1.76777 17.8284 2.82843L14.7877 5.8691L14.5051 8.98014L17.6161 8.69753L20.6568 5.65685C21.7175 7.42462 21.3357 10.6349 19.5961 12.3744C17.8566 14.1139 15.0316 14.2789 12.8786 13.435" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path> | |
| </svg> | |
| </button> | |
| </div> | |
| <div class="flex items-center space-x-3 md:space-x-4 flex-1 md:flex-initial justify-center md:justify-start"> | |
| <!-- Gradio Logo --> | |
| <div class="w-8 h-8 md:w-10 md:h-10 flex items-center justify-center"> | |
| <img src="./gradio-logo.svg" alt="Gradio Logo" class="w-full h-full object-contain" /> | |
| </div> | |
| <div class="flex flex-col"> | |
| <h1 class="text-sm md:text-base font-bold text-[#2e3438] leading-tight tracking-tight"> | |
| @gradio/dataframe demo | |
| </h1> | |
| </div> | |
| </div> | |
| <div class="hidden md:flex ml-auto items-center space-x-4"> | |
| <button | |
| on:click={() => currentTheme === 'dark' ? applyTheme('default') : applyTheme('dark')} | |
| class="px-3 py-2 !mr-2 text-sm font-medium text-[#73828c] rounded-lg flex items-center" | |
| aria-label="Toggle dark mode" | |
| title="Toggle dark/light mode" | |
| > | |
| {#if currentTheme === 'dark'} | |
| <span class="mr-2">βοΈ</span> | |
| {:else} | |
| <span class="mr-2">π</span> | |
| {/if} | |
| Toggle Theme | |
| </button> | |
| <button | |
| on:click={() => showRightPanel = !showRightPanel} | |
| class="px-4 py-2 !mr-2 text-sm font-medium text-[#73828c] hover:text-[#2e3438] hover:bg-[#f6f9fc] rounded-lg transition-all duration-200 flex items-center border border-[#e0e0e0]" | |
| aria-label="Toggle controls panel" | |
| > | |
| <span class="mr-2">π οΈ</span> | |
| {showRightPanel ? 'Hide' : 'Show'} Controls | |
| </button> | |
| <button | |
| on:click={() => setActiveView('docs')} | |
| class="px-4 py-2 text-sm font-medium text-[#73828c] hover:text-[#2e3438] hover:bg-[#f6f9fc] rounded-lg transition-all duration-200 flex items-center" | |
| > | |
| <span class="mr-2">π</span> | |
| Docs | |
| </button> | |
| <a | |
| href="https://www.npmjs.com/package/@gradio/dataframe" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| class="px-4 py-2 text-sm font-semibold text-white rounded-lg transition-all duration-200 flex items-center no-underline" | |
| > | |
| <span class="mr-2">π¦</span> | |
| npm | |
| </a> | |
| </div> | |
| </header> | |
| <div class="flex flex-1 overflow-hidden relative"> | |
| <!-- Mobile Overlay --> | |
| {#if showLeftPanel || showRightPanel} | |
| <div | |
| class="fixed inset-0 bg-black bg-opacity-50 z-10 md:hidden" | |
| role="button" | |
| tabindex="0" | |
| on:click={() => { showLeftPanel = false; showRightPanel = false; }} | |
| on:keydown={(e) => { if (e.key === 'Escape') { showLeftPanel = false; showRightPanel = false; } }} | |
| ></div> | |
| {/if} | |
| <!-- Left Panel: Examples & Documentation --> | |
| <div class=" | |
| {showLeftPanel ? 'translate-x-0' : '-translate-x-full'} | |
| md:translate-x-0 | |
| fixed md:static | |
| left-0 top-16 bottom-0 | |
| w-64 md:w-[200px] lg:w-[220px] xl:w-[240px] | |
| bg-white border-r-1 border-[#d1d5db] [border-right-width:1px!important] | |
| overflow-y-auto | |
| z-20 | |
| transition-transform duration-300 ease-in-out | |
| "> | |
| <!-- Documentation Content --> | |
| <div class="p-4 space-y-4"> | |
| <div> | |
| <h3 class="text-xs font-semibold text-[#2e3438] mb-2">@gradio/dataframe</h3> | |
| <p class="text-[10px] text-[#73828c] leading-relaxed"> | |
| A standalone dataframe component from Gradio that provides interactive table functionality with editing, searching, and data manipulation capabilities. | |
| </p> | |
| </div> | |
| </div> | |
| <!-- Documentation Navigation --> | |
| <div class="p-4 border-b border-[#e0e0e0]"> | |
| <h2 class="text-[8px] font-bold text-[#2e3438] uppercase tracking-wider mb-3">Navigation</h2> | |
| <div class="flex flex-col space-y-2"> | |
| <button | |
| on:click={() => setActiveView('canvas')} | |
| class="nav-button {activeView === 'canvas' ? 'nav-button-active' : 'nav-button-inactive'}" | |
| > | |
| <div class="flex items-center justify-center mr-3"> | |
| <span class="text-xs">π―</span> | |
| </div> | |
| Canvas | |
| </button> | |
| <button | |
| on:click={() => setActiveView('docs')} | |
| class="nav-button {activeView === 'docs' ? 'nav-button-active' : 'nav-button-inactive'}" | |
| > | |
| <div class="flex items-center justify-center mr-3"> | |
| <span class="text-xs">π</span> | |
| </div> | |
| Documentation | |
| </button> | |
| <button | |
| on:click={() => setActiveView('events')} | |
| class="nav-button {activeView === 'events' ? 'nav-button-active' : 'nav-button-inactive'}" | |
| > | |
| <div class="flex items-center justify-center mr-3"> | |
| <span class="text-xs">π</span> | |
| </div> | |
| Events | |
| </button> | |
| <button | |
| on:click={() => setActiveView('source')} | |
| class="nav-button {activeView === 'source' ? 'nav-button-active' : 'nav-button-inactive'}" | |
| > | |
| <div class="flex items-center justify-center mr-3"> | |
| <span class="text-xs">π»</span> | |
| </div> | |
| Source Code | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Examples Navigation --> | |
| <div class="p-4 border-b border-[#e0e0e0]"> | |
| <h2 class="text-[8px] font-bold text-[#2e3438] uppercase tracking-wider mb-3">Examples</h2> | |
| <!-- Example Cards --> | |
| <div class="space-y-2"> | |
| {#each Object.entries(sampleDatasets) as [key, dataset]} | |
| <button | |
| on:click={() => switchDataset(key)} | |
| class="w-full group" | |
| > | |
| <div class="example-card {selectedDataset === key ? 'example-card-active' : 'example-card-inactive'}"> | |
| <div class="flex items-center justify-between p-2"> | |
| <div class="flex items-center"> | |
| <div class="example-icon {selectedDataset === key ? 'example-icon-active' : 'example-icon-inactive'}"> | |
| <span class="text-xs">{getExampleIcon(key)}</span> | |
| </div> | |
| <div class="text-left"> | |
| <h4 class="text-[10px] font-semibold {selectedDataset === key ? 'text-[#1e293b]' : 'text-[#374151]'} group-hover:text-[#1e293b] transition-colors duration-200">{getExampleTitle(key)}</h4> | |
| <p class="text-[8px] {selectedDataset === key ? 'text-[#64748b]' : 'text-[#9ca3af]'} mt-0.5">{getExampleDescription(key)}</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </button> | |
| {/each} | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Main Content Area --> | |
| <div class="flex-1 bg-[#f6f9fc] overflow-y-auto border-l border-r border-[#e0e0e0] md:border-l-0" style="padding-bottom: {activeView === 'canvas' ? controlsHeight + 'px' : '16px'}"> | |
| <!-- Canvas Area --> | |
| {#if activeView === 'canvas'} | |
| <div class="flex-1 bg-[#f6f9fc] p-2 sm:p-4 md:p-4 lg:p-6 xl:p-8 overflow-auto"> | |
| <div class="main-container"> | |
| <div class="content-card"> | |
| <div class="border border-[#e2e8f0] rounded-lg md:rounded-xl p-4 md:p-8 bg-[#f8fafc] overflow-x-auto"> | |
| <Dataframe | |
| bind:value | |
| datatype={datatype as any} | |
| {editable} | |
| {show_row_numbers} | |
| {show_search} | |
| {show_copy_button} | |
| {show_fullscreen_button} | |
| {show_label} | |
| {label} | |
| {max_height} | |
| {line_breaks} | |
| {wrap} | |
| {column_widths} | |
| {max_chars} | |
| on:change={handleChange} | |
| on:select={handleSelect} | |
| on:input={handleInput} | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| {:else if activeView === 'docs'} | |
| <!-- Documentation Page --> | |
| <div class="page-wrapper"> | |
| <div class="main-container"> | |
| <div class="content-card"> | |
| <div class="mb-8 md:mb-12"> | |
| <h1 class="page-title">@gradio/dataframe</h1> | |
| <p class="description-text"> | |
| A standalone dataframe component from Gradio that provides interactive table functionality with editing, searching, and data manipulation capabilities. | |
| </p> | |
| </div> | |
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-12 mb-12"> | |
| <div> | |
| <h2 class="section-title">Installation</h2> | |
| <div class="bg-[#f8fafc] border border-[#e2e8f0] rounded-xl p-6 mb-8"> | |
| <code class="text-sm text-[#2e3438] font-mono font-semibold">npm install @gradio/dataframe</code> | |
| </div> | |
| </div> | |
| <div> | |
| <h2 class="section-title">Key Features</h2> | |
| <ul class="space-y-4"> | |
| <li class="flex items-start"> | |
| <span class="text-[#10b981] mr-4 mt-1 text-lg">β</span> | |
| <span class="feature-text">Interactive editing and data manipulation</span> | |
| </li> | |
| <li class="flex items-start"> | |
| <span class="text-[#10b981] mr-4 mt-1 text-lg">β</span> | |
| <span class="feature-text">Search and filter capabilities</span> | |
| </li> | |
| <li class="flex items-start"> | |
| <span class="text-[#10b981] mr-4 mt-1 text-lg">β</span> | |
| <span class="feature-text">Customizable appearance and behavior</span> | |
| </li> | |
| <li class="flex items-start"> | |
| <span class="text-[#10b981] mr-4 mt-1 text-lg">β</span> | |
| <span class="feature-text">Support for multiple data types</span> | |
| </li> | |
| <li class="flex items-start"> | |
| <span class="text-[#10b981] mr-4 mt-1 text-lg">β</span> | |
| <span class="feature-text">Copy to clipboard functionality</span> | |
| </li> | |
| <li class="flex items-start"> | |
| <span class="text-[#10b981] mr-4 mt-1 text-lg">β</span> | |
| <span class="feature-text">Fullscreen mode support</span> | |
| </li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div class="mb-12"> | |
| <h3 class="subsection-title">Quick Start</h3> | |
| <SyntaxHighlighter | |
| language="typescript" | |
| code={`<script> | |
| import Dataframe from "@gradio/dataframe"; | |
| let value = { | |
| data: [["Alice", 25], ["Bob", 30]], | |
| headers: ["Name", "Age"], | |
| }; | |
| </script> | |
| <Dataframe bind:value />`} | |
| /> | |
| </div> | |
| <div class="mb-12"> | |
| <h2 class="text-lg font-bold text-[#2e3438] mb-4">API Reference</h2> | |
| <div class="overflow-x-auto border border-[#e2e8f0] rounded-xl"> | |
| <table class="w-full"> | |
| <thead class="bg-[#f8fafc]"> | |
| <tr> | |
| <th class="px-6 py-4 text-left font-bold text-[#2e3438] border-b border-[#e2e8f0] text-sm">Prop</th> | |
| <th class="px-6 py-4 text-left font-bold text-[#2e3438] border-b border-[#e2e8f0] text-sm">Type</th> | |
| <th class="px-6 py-4 text-left font-bold text-[#2e3438] border-b border-[#e2e8f0] text-sm">Default</th> | |
| <th class="px-6 py-4 text-left font-bold text-[#2e3438] border-b border-[#e2e8f0] text-sm">Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">value</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">DataFrame | Array | List</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Data to display. Supports pandas, numpy, polars, and list of lists</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">headers</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">string[]</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">List of column header names</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">datatype</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">string | string[]</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">"str"</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Data types: "str", "number", "bool", "date", "markdown", "html", "image", "auto"</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">interactive</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">boolean</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Whether users can edit the dataframe (inferred if not provided)</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">label</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">string</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Label text that appears above the component</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">show_label</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">boolean</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Whether to display the label</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">max_height</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">number | string</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">500</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Maximum height in pixels or CSS units</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">show_row_numbers</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">boolean</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">false</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Display row numbers in a separate column</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">show_search</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">"none" | "search" | "filter"</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">"none"</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Show search input and filter functionality</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">show_copy_button</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">boolean</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">false</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Show button to copy table data to clipboard</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">show_fullscreen_button</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">boolean</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">false</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Show button to view table in fullscreen mode</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">wrap</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">boolean</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">false</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Enable text wrapping in table cells</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">line_breaks</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">boolean</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">true</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Enable GitHub-flavored Markdown line breaks (for markdown columns)</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">column_widths</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">(string | number)[]</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Width of each column in pixels ("100px") or percentage ("10%")</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">max_chars</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">number</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Maximum characters to display per cell before truncating</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">row_count</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">number | [number, "fixed" | "dynamic"]</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">[1, "dynamic"]</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Limit number of rows and whether users can add/delete rows</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">col_count</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">number | [number, "fixed" | "dynamic"]</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Limit number of columns and whether users can add/delete columns</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">pinned_columns</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">number</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Number of columns to pin from the left</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0]"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">static_columns</code></td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">number[]</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] font-medium">null</td> | |
| <td class="px-6 py-4 border-b border-[#e2e8f0] text-[#64748b] leading-relaxed">Column indices that should not be editable</td> | |
| </tr> | |
| <tr class="hover:bg-[#f8fafc] transition-colors duration-150"> | |
| <td class="px-6 py-4"><code class="text-sm bg-[#e2e8f0] px-3 py-1.5 rounded-md font-mono font-semibold text-[#1e293b]">type</code></td> | |
| <td class="px-6 py-4 text-[#64748b] font-medium">"pandas" | "numpy" | "array" | "polars"</td> | |
| <td class="px-6 py-4 text-[#64748b] font-medium">"pandas"</td> | |
| <td class="px-6 py-4 text-[#64748b] leading-relaxed">Type of value returned by the component</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| {:else if activeView === 'events'} | |
| <!-- Events Page --> | |
| <div class="page-wrapper"> | |
| <div class="main-container"> | |
| <div class="content-card"> | |
| <div class="mb-8 md:mb-12"> | |
| <h1 class="page-title">Events</h1> | |
| <p class="description-text"> | |
| The dataframe component fires several events that you can listen to for user interactions and data changes. | |
| </p> | |
| </div> | |
| <div class="space-y-10"> | |
| <div class="event-section"> | |
| <div class="flex items-start mb-6"> | |
| <code class="bg-[#F87701] text-white px-4 py-2 rounded-lg text-[#2e3438] mr-6 font-mono font-bold text-sm border shadow-sm">change</code> | |
| <div class="flex-1"> | |
| <h3 class="subsection-title">Data Change Event</h3> | |
| <p class="text-sm text-[#64748b] mb-4 leading-relaxed font-medium">Fired when the table data is modified by the user.</p> | |
| <SyntaxHighlighter | |
| language="typescript" | |
| code={`<Dataframe | |
| bind:value | |
| on:change={(e) => { | |
| console.log("Data changed:", e.detail); | |
| }} | |
| />`} | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="event-section"> | |
| <div class="flex items-start mb-6"> | |
| <code class="bg-[#10b981] text-white px-4 py-2 rounded-lg text-[#2e3438] mr-6 font-mono font-bold text-sm border shadow-sm">select</code> | |
| <div class="flex-1"> | |
| <h3 class="subsection-title">Cell Selection Event</h3> | |
| <p class="text-[#64748b] mb-6 leading-relaxed font-medium">Fired when a cell is selected or focused.</p> | |
| <SyntaxHighlighter | |
| language="typescript" | |
| code={`<Dataframe | |
| bind:value | |
| on:select={(e) => { | |
| console.log("Cell selected:", e.detail); | |
| // e.detail contains: { row: number, col: number } | |
| }} | |
| />`} | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="event-section"> | |
| <div class="flex items-start mb-6"> | |
| <code class="bg-[#f59e0b] text-white px-4 py-2 rounded-lg text-[#2e3438] mr-6 font-mono font-bold text-sm border shadow-sm">input</code> | |
| <div class="flex-1"> | |
| <h3 class="subsection-title">User Input Event</h3> | |
| <p class="text-[#64748b] mb-6 leading-relaxed font-medium">Fired during user input, useful for real-time validation.</p> | |
| <SyntaxHighlighter | |
| language="typescript" | |
| code={`<Dataframe | |
| bind:value | |
| on:input={(e) => { | |
| console.log("User input:", e.detail); | |
| // Real-time validation logic here | |
| }} | |
| />`} | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mt-12 p-8 bg-gradient-to-r from-[#f8fafc] to-[#e0f2fe] border border-[#e2e8f0] rounded-xl"> | |
| <h3 class="text-2xl font-bold text-[#2e3438] mb-4">Event Data Structure</h3> | |
| <p class="text-[#64748b] mb-6 leading-relaxed font-medium">All events provide data through the <code class="bg-white px-3 py-1.5 rounded-md border font-mono text-sm text-[#1e293b] font-semibold">e.detail</code> property:</p> | |
| <SyntaxHighlighter | |
| language="typescript" | |
| code={`// Change event detail | |
| { | |
| data: (string | number)[][], | |
| headers: string[], | |
| metadata: any | |
| } | |
| // Select event detail | |
| { | |
| row: number, | |
| col: number, | |
| value: string | number | |
| }`} | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| {:else if activeView === 'source'} | |
| <!-- Source Code Page --> | |
| <div class="page-wrapper overflow-y-scroll"> | |
| <div class="main-container"> | |
| <div class="content-card"> | |
| <div class="mb-8 md:mb-12"> | |
| <h1 class="page-title">Source Code</h1> | |
| <p class="description-text"> | |
| Complete example showing how to implement the dataframe component with all features. | |
| </p> | |
| </div> | |
| <div class="mb-10"> | |
| <h2 class="text-lg font-bold text-[#2e3438] mb-4">Current Configuration</h2> | |
| <SyntaxHighlighter | |
| language="typescript" | |
| code={`<script lang="ts"> | |
| import Dataframe from "@gradio/dataframe"; | |
| let value = ` + JSON.stringify({ | |
| data: value.data.slice(0, 3), | |
| headers: value.headers, | |
| metadata: null | |
| }, null, 2) + `; | |
| let datatype = ` + JSON.stringify(datatype) + `; | |
| function handleChange(e: any) { | |
| console.log("Data changed:", e.detail); | |
| } | |
| function handleSelect(e: any) { | |
| console.log("Cell selected:", e.detail); | |
| } | |
| function handleInput(e: any) { | |
| console.log("Input event:", e.detail); | |
| } | |
| </script> | |
| <Dataframe | |
| bind:value | |
| datatype={datatype} | |
| editable={` + editable + `} | |
| show_row_numbers={` + show_row_numbers + `} | |
| show_search="` + show_search + `" | |
| show_copy_button={` + show_copy_button + `} | |
| show_fullscreen_button={` + show_fullscreen_button + `} | |
| show_label={` + show_label + `} | |
| label="` + label + `" | |
| max_height={` + max_height + `} | |
| line_breaks={` + line_breaks + `} | |
| wrap={` + wrap + `}` + (max_chars ? ` | |
| max_chars={` + max_chars + `}` : '') + ` | |
| on:change={handleChange} | |
| on:select={handleSelect} | |
| on:input={handleInput} | |
| />`} | |
| /> | |
| </div> | |
| <div class="mb-10"> | |
| <h2 class="text-lg font-bold text-[#2e3438] mb-4">TypeScript Definitions</h2> | |
| <SyntaxHighlighter | |
| language="typescript" | |
| code={`interface DataframeValue { | |
| data: (string | number)[][]; | |
| headers: string[]; | |
| metadata: any; | |
| } | |
| interface DataframeProps { | |
| value: DataframeValue; | |
| datatype?: string[]; | |
| editable?: boolean; | |
| show_row_numbers?: boolean; | |
| show_search?: "none" | "search" | "filter"; | |
| show_copy_button?: boolean; | |
| show_fullscreen_button?: boolean; | |
| show_label?: boolean; | |
| label?: string; | |
| max_height?: number; | |
| line_breaks?: boolean; | |
| wrap?: boolean; | |
| max_chars?: number; | |
| column_widths?: string[]; | |
| }`} | |
| /> | |
| </div> | |
| <div> | |
| <h2 class="text-lg font-bold text-[#2e3438] mb-4">Installation</h2> | |
| <div class="bg-[#f8fafc] border border-[#e2e8f0] rounded-xl p-8"> | |
| <h3 class="text-lg font-semibold text-[#2e3438] mb-4">Package.json</h3> | |
| <SyntaxHighlighter | |
| language="json" | |
| code={`{ | |
| "dependencies": { | |
| "@gradio/dataframe": "^latest" | |
| } | |
| }`} | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| {/if} | |
| <!-- Bottom Controls Panel (Horizontal) --> | |
| <div class=" | |
| {showRightPanel && activeView === 'canvas' ? 'translate-y-0' : 'translate-y-full'} | |
| fixed | |
| left-0 md:left-[200px] lg:left-[220px] xl:left-[240px] | |
| right-0 bottom-0 | |
| bg-white border-t border-[#d1d5db] | |
| z-20 | |
| transition-transform duration-300 ease-in-out | |
| " style="height: {controlsHeight}px"> | |
| <!-- Drag handle for resizing --> | |
| <div | |
| class="flex justify-center border-b border-[#e0e0e0] cursor-ns-resize hover:bg-gray-50 transition-colors duration-200 {isDragging ? 'bg-gray-100' : ''}" | |
| on:mousedown={handleDragStart} | |
| role="slider" | |
| tabindex="0" | |
| aria-label="Resize controls panel" | |
| aria-valuenow={controlsHeight} | |
| aria-valuemin="120" | |
| aria-valuemax="400" | |
| title="Drag to resize controls panel" | |
| > | |
| </div> | |
| <!-- Mobile bottom sheet handle --> | |
| <div class="md:hidden flex justify-center py-2 border-b border-[#e0e0e0]"> | |
| <div class="w-10 h-1 bg-[#d1d5db] rounded-full"></div> | |
| </div> | |
| <ConfigPanel | |
| bind:selectedDataset | |
| bind:currentTheme | |
| bind:editable | |
| bind:show_row_numbers | |
| bind:show_search | |
| bind:show_copy_button | |
| bind:show_fullscreen_button | |
| bind:show_label | |
| bind:label | |
| bind:max_height | |
| bind:line_breaks | |
| bind:wrap | |
| bind:max_chars | |
| on:datasetChange={handleDatasetChange} | |
| on:themeChange={handleThemeChange} | |
| on:addColumn={handleAddColumn} | |
| on:addRow={handleAddRow} | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| </div> |