/* Copyright 2026 Marimo. All rights reserved. */ "use no memo"; import { useDebounce } from "@uidotdev/usehooks"; import { ChartSplineIcon, PanelRightIcon, SearchIcon, XIcon, } from "lucide-react"; import React, { useEffect, useState } from "react"; import useEvent from "react-use-event-hook"; import { cn } from "@/utils/cn"; import { PANEL_TYPES, type PanelType, } from "../editor/chrome/panels/context-aware-panel/context-aware-panel"; import { Spinner } from "../icons/spinner"; import { Button } from "../ui/button"; import { type ExportActionProps, ExportMenu } from "./export-actions"; const NOOP_ON_SEARCH = () => { /** no-op*/ }; interface TableTopBarProps extends Partial { enableSearch: boolean; searchQuery?: string; onSearchQueryChange?: (query: string) => void; reloading?: boolean; showChartBuilder?: boolean; isChartBuilderOpen?: boolean; toggleDisplayHeader?: () => void; showTableExplorer?: boolean; togglePanel?: (panelType: PanelType) => void; isAnyPanelOpen?: boolean; } export const TableTopBar: React.FC = ({ enableSearch, searchQuery, onSearchQueryChange, reloading, showChartBuilder, isChartBuilderOpen, toggleDisplayHeader, showTableExplorer, togglePanel, isAnyPanelOpen, downloadAs, }) => { const [internalValue, setInternalValue] = useState(searchQuery || ""); const debouncedSearch = useDebounce(internalValue, 500); const onSearch = useEvent(onSearchQueryChange ?? NOOP_ON_SEARCH); const inputRef = React.useRef(null); useEffect(() => { onSearch(debouncedSearch); }, [debouncedSearch, onSearch]); const hasAnyAction = (enableSearch && onSearchQueryChange) || showChartBuilder || showTableExplorer || downloadAs; if (!hasAnyAction) { return null; } return (
{onSearchQueryChange && enableSearch && (
{ if (e.key === "Escape") { setInternalValue(""); inputRef.current?.blur(); } }} onChange={(e) => setInternalValue(e.target.value)} placeholder="Search..." /> {reloading && } {internalValue && ( )}
)}
{showChartBuilder && ( )} {showTableExplorer && togglePanel && ( )} {downloadAs && }
); };