@parqui/react 1.3.0 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/Parkui.tsx","../src/hooks/useContainerSize.ts","../src/hooks/useParquetData.ts","../src/hooks/useSourceLoader.ts","../src/source.ts","../src/hooks/useChunkLoader.ts","../src/hooks/useVirtualScroll.ts","../src/hooks/useColumnManager.ts","../src/hooks/useKeyboardNavigation.ts","../src/hooks/useSearch.ts","../src/components/Toolbar.tsx","../src/components/Icons.tsx","../src/components/PipelineChip.tsx","../src/utils/formatting.ts","../src/styles.ts","../src/components/DataGrid.tsx","../src/components/ColumnHeader.tsx","../src/components/ParquiLogo.tsx","../src/components/VirtualRow.tsx","../src/components/GroupHeaderRow.tsx","../src/components/ColumnContextMenu.tsx","../src/FileDropZone.tsx"],"sourcesContent":["export { Parkui } from \"./Parkui.js\";\nexport type { ParkuiProps } from \"./Parkui.js\";\nexport type { ParquetInputSource } from \"./source.js\";\n\nexport { FileDropZone } from \"./FileDropZone.js\";\nexport type { FileDropZoneProps } from \"./FileDropZone.js\";\n\nexport { ParquiLogo } from \"./components/ParquiLogo.js\";\nexport type { ParquiLogoProps } from \"./components/ParquiLogo.js\";\n\n// Hooks (for advanced usage / custom wrappers)\nexport { useContainerSize } from \"./hooks/useContainerSize.js\";\nexport { useParquetData } from \"./hooks/useParquetData.js\";\nexport { useVirtualScroll, ROW_HEIGHT, HEADER_HEIGHT } from \"./hooks/useVirtualScroll.js\";\nexport { useColumnManager } from \"./hooks/useColumnManager.js\";\nexport { useKeyboardNavigation } from \"./hooks/useKeyboardNavigation.js\";\nexport { useSearch } from \"./hooks/useSearch.js\";\nexport { useSourceLoader } from \"./hooks/useSourceLoader.js\";\nexport { useChunkLoader } from \"./hooks/useChunkLoader.js\";\n\nexport type {\n ParquetColumn,\n ParquetMetadata,\n ParquetRow,\n ParquetData,\n ParquetSource,\n ReadOptions,\n} from \"@parqui/core\";\n","import {\n useState,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n} from \"react\";\nimport { useContainerSize } from \"./hooks/useContainerSize.js\";\nimport { useParquetData } from \"./hooks/useParquetData.js\";\nimport { useVirtualScroll } from \"./hooks/useVirtualScroll.js\";\nimport { useColumnManager } from \"./hooks/useColumnManager.js\";\nimport { useKeyboardNavigation } from \"./hooks/useKeyboardNavigation.js\";\nimport { useSearch } from \"./hooks/useSearch.js\";\nimport { Toolbar } from \"./components/Toolbar.js\";\nimport { DataGrid } from \"./components/DataGrid.js\";\nimport { ColumnContextMenu } from \"./components/ColumnContextMenu.js\";\nimport { FileDropZone } from \"./FileDropZone.js\";\nimport type { ParquetMetadata, ParquetSource } from \"@parqui/core\";\nimport { sourceToDisplayName, type ParquetInputSource } from \"./source.js\";\nimport { s, PARKUI_CSS } from \"./styles.js\";\n\n// ── Props ──\n\nexport interface ParkuiProps {\n source?: ParquetInputSource;\n columns?: string[];\n onMetadataLoad?: (metadata: ParquetMetadata) => void;\n allowOpen?: boolean;\n onRequestOpen?: () => Promise<{ source: ParquetSource; name: string } | null>;\n showToolbar?: boolean;\n className?: string;\n style?: React.CSSProperties;\n}\n\n// ── Context menu state ──\n\ninterface ContextMenuState {\n column: string;\n x: number;\n y: number;\n}\n\n// ── Main Component ──\n\nexport function Parkui({\n source,\n columns,\n onMetadataLoad,\n allowOpen = true,\n onRequestOpen,\n showToolbar = true,\n className,\n style,\n}: ParkuiProps) {\n // ── File management ──\n const [currentSource, setCurrentSource] = useState<ParquetInputSource | undefined>(source);\n const [fileName, setFileName] = useState<string>(\n source ? sourceToDisplayName(source) : \"\",\n );\n\n useEffect(() => {\n setCurrentSource(source);\n setFileName(source ? sourceToDisplayName(source) : \"\");\n }, [source]);\n\n const hasSource = !!currentSource;\n const search = useSearch();\n\n const handleFileSelect = useCallback((newFile: File) => {\n search.resetSearch();\n setCurrentSource(newFile);\n setFileName(newFile.name);\n }, [search]);\n\n const handleClose = useCallback(() => {\n setCurrentSource(undefined);\n setFileName(\"\");\n search.resetSearch();\n }, [search]);\n\n const handleCustomOpen = useCallback(async () => {\n if (!onRequestOpen) return;\n const result = await onRequestOpen();\n if (result) {\n search.resetSearch();\n setCurrentSource(result.source);\n setFileName(result.name);\n }\n }, [onRequestOpen, search]);\n\n // ── Data hooks ──\n const { containerRef, size } = useContainerSize();\n const pq = useParquetData(currentSource, columns, search.debouncedSearch);\n\n // Notify parent when metadata loads\n const onMetadataLoadRef = useRef(onMetadataLoad);\n onMetadataLoadRef.current = onMetadataLoad;\n useEffect(() => {\n if (pq.metadata) onMetadataLoadRef.current?.(pq.metadata);\n }, [pq.metadata]);\n\n const columnNames = useMemo(() => {\n if (columns) return columns;\n return pq.metadata?.columns.map((c) => c.name) ?? [];\n }, [columns, pq.metadata]);\n\n const colManager = useColumnManager(columnNames);\n\n // ── Context menu ──\n const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);\n\n // ── Grouped mode ──\n const isGrouped = pq.pipeline.groups.length > 0 && pq.groups.length > 0;\n\n // ── Scroll row count (groups flatten into flat items) ──\n const scrollRowCount = useMemo(() => {\n if (!isGrouped) return pq.filteredRowCount;\n let count = 0;\n for (const g of pq.groups) {\n count += 1; // header\n if (g.expanded) count += g.rowIndices.length;\n }\n return count;\n }, [isGrouped, pq.groups, pq.filteredRowCount]);\n\n const vScroll = useVirtualScroll(size.height, scrollRowCount, pq.metadata);\n\n // ── Keyboard navigation ──\n const isNavigable = useMemo(() => {\n if (!isGrouped) return undefined;\n // In grouped mode, build flat items to determine which rows are navigable\n return (flatIdx: number) => {\n let pos = 0;\n for (const g of pq.groups) {\n if (pos === flatIdx) return false; // header\n pos++;\n if (g.expanded) {\n const end = pos + g.rowIndices.length;\n if (flatIdx < end) return true; // it's a row\n pos = end;\n }\n }\n return false;\n };\n }, [isGrouped, pq.groups]);\n\n // Column layout ref for horizontal auto-scroll\n const colLayoutRef = useRef<{ rowNumWidth: number; widths: number[] }>({\n rowNumWidth: 50,\n widths: [],\n });\n\n const scrollToCell = useCallback(\n (row: number, col: number) => {\n vScroll.scrollToRow(row);\n const el = vScroll.scrollEl.current;\n if (!el) return;\n const { rowNumWidth, widths } = colLayoutRef.current;\n let colLeft = rowNumWidth;\n for (let i = 0; i < col; i++) colLeft += widths[i] ?? 0;\n const colRight = colLeft + (widths[col] ?? 0);\n const viewLeft = el.scrollLeft;\n const viewRight = viewLeft + el.clientWidth;\n\n if (colRight > viewRight) {\n el.scrollLeft = colRight - el.clientWidth;\n } else if (colLeft < viewLeft) {\n el.scrollLeft = col === 0 ? 0 : colLeft;\n }\n },\n [vScroll.scrollToRow],\n );\n\n const keyboard = useKeyboardNavigation(scrollToCell, isNavigable);\n\n // ── Keyboard handler ──\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n keyboard.handleKeyDown(e, scrollRowCount, colManager.visibleColumns.length);\n },\n [keyboard, scrollRowCount, colManager.visibleColumns.length],\n );\n\n // ── Sort click ──\n const handleSortClick = useCallback(\n (column: string, multi: boolean) => pq.toggleSort(column, multi),\n [pq.toggleSort],\n );\n\n // ── Context menu handlers ──\n const handleContextMenu = useCallback(\n (column: string, x: number, y: number) => setContextMenu({ column, x, y }),\n [],\n );\n const handleCloseContextMenu = useCallback(() => setContextMenu(null), []);\n\n // ── Chip remove handlers ──\n const handleRemoveSort = useCallback(\n (column: string) => pq.setSort(pq.pipeline.sorts.filter((sort) => sort.column !== column)),\n [pq.setSort, pq.pipeline.sorts],\n );\n const handleRemoveFilter = useCallback(\n (column: string) => pq.removeFilter(column),\n [pq.removeFilter],\n );\n const handleRemoveGroup = useCallback(\n (column: string) => pq.toggleGroup(column),\n [pq.toggleGroup],\n );\n\n const isColumnGrouped = useCallback(\n (column: string) => pq.pipeline.groups.some((g) => g.column === column),\n [pq.pipeline.groups],\n );\n\n // ── Layout computations ──\n const visibleCols = colManager.visibleColumns;\n const rowNumWidth = Math.max(50, String(pq.filteredRowCount).length * 9 + 24);\n\n colLayoutRef.current = {\n rowNumWidth,\n widths: visibleCols.map((c) => c.width),\n };\n\n // ── Drop zone props ──\n const dropZoneProps = onRequestOpen\n ? { onFileSelect: handleFileSelect, onCustomOpen: handleCustomOpen }\n : { onFileSelect: handleFileSelect };\n\n // ── Render flags ──\n const showDropZone = allowOpen && !hasSource;\n const showGrid = hasSource && !pq.loading && !pq.error;\n\n return (\n <div className={className} style={{ ...s.root, ...style }}>\n <style>{PARKUI_CSS}</style>\n\n {/* Toolbar */}\n {showToolbar && (\n <Toolbar\n allowOpen={allowOpen}\n hasSource={hasSource}\n fileName={fileName}\n pipeline={pq.pipeline}\n searchText={search.searchText}\n onSearchChange={search.handleSearchChange}\n onClearSearch={search.clearSearch}\n onRequestOpen={onRequestOpen ? handleCustomOpen : undefined}\n onFileSelect={handleFileSelect}\n onClose={handleClose}\n onRemoveSort={handleRemoveSort}\n onRemoveFilter={handleRemoveFilter}\n onRemoveGroup={handleRemoveGroup}\n />\n )}\n\n {/* Content area */}\n <div\n ref={containerRef}\n style={s.content}\n tabIndex={showGrid ? 0 : undefined}\n onKeyDown={showGrid ? handleKeyDown : undefined}\n role={showGrid ? \"grid\" : undefined}\n aria-rowcount={showGrid ? pq.filteredRowCount : undefined}\n aria-colcount={showGrid ? visibleCols.length : undefined}\n >\n {hasSource && pq.loading && (\n <div style={s.placeholder}>Loading...</div>\n )}\n\n {hasSource && pq.error && (\n <div style={s.error}>{pq.error}</div>\n )}\n\n {showDropZone && (\n <div style={s.dropZoneWrapper}>\n <FileDropZone {...dropZoneProps} />\n </div>\n )}\n\n {!hasSource && !allowOpen && (\n <div style={s.placeholder}>No parquet source provided</div>\n )}\n\n {showGrid && (\n <DataGrid\n vScroll={vScroll}\n scrollRowCount={scrollRowCount}\n visibleColumns={visibleCols}\n totalColWidth={colManager.totalWidth}\n rowNumWidth={rowNumWidth}\n getRow={pq.getRow}\n ensureRange={pq.ensureRange}\n ensureIndices={pq.ensureIndices}\n renderTick={pq.renderTick}\n groups={pq.groups}\n isGrouped={isGrouped}\n computing={pq.computing}\n toggleGroupExpanded={pq.toggleGroupExpanded}\n dragState={colManager.dragState}\n resizeState={colManager.resizeState}\n onDragStart={colManager.startDrag}\n onDragOver={colManager.updateDragOver}\n onDragOverEnd={colManager.updateDragOverEnd}\n onDragEnd={colManager.endDrag}\n onResizeStart={colManager.startResize}\n onUpdateResize={colManager.updateResize}\n onEndResize={colManager.endResize}\n getSortDirection={pq.getSortDirection}\n getSortPriority={pq.getSortPriority}\n getFilter={pq.getFilter}\n isColumnGrouped={isColumnGrouped}\n onSortClick={handleSortClick}\n onContextMenu={handleContextMenu}\n keyboard={keyboard}\n searchText={search.debouncedSearch}\n />\n )}\n </div>\n\n {/* Context menu */}\n {contextMenu && (\n <ColumnContextMenu\n column={contextMenu.column}\n x={contextMenu.x}\n y={contextMenu.y}\n sortDirection={pq.getSortDirection(contextMenu.column)}\n sortPriority={pq.getSortPriority(contextMenu.column)}\n activeFilter={pq.getFilter(contextMenu.column)}\n isGrouped={pq.pipeline.groups.some((g) => g.column === contextMenu.column)}\n onClose={handleCloseContextMenu}\n onSortAsc={() => {\n pq.setSort([\n ...pq.pipeline.sorts.filter((sort) => sort.column !== contextMenu.column),\n { column: contextMenu.column, direction: \"asc\" },\n ]);\n }}\n onSortDesc={() => {\n pq.setSort([\n ...pq.pipeline.sorts.filter((sort) => sort.column !== contextMenu.column),\n { column: contextMenu.column, direction: \"desc\" },\n ]);\n }}\n onSortClear={() => {\n pq.setSort(pq.pipeline.sorts.filter((sort) => sort.column !== contextMenu.column));\n }}\n onFilterSet={(filter) => pq.setFilter(filter)}\n onFilterClear={() => pq.removeFilter(contextMenu.column)}\n onGroupToggle={() => pq.toggleGroup(contextMenu.column)}\n loadUniqueValues={() => pq.getUniqueValues(contextMenu.column)}\n />\n )}\n </div>\n );\n}\n","import { useState, useEffect, useRef, useCallback, type RefObject } from \"react\";\n\nexport interface ContainerSize {\n width: number;\n height: number;\n}\n\n/**\n * Observes the size of a container element via ResizeObserver.\n * Returns a ref to attach to the element and the current size.\n */\nexport function useContainerSize(): {\n containerRef: RefObject<HTMLDivElement | null>;\n size: ContainerSize;\n} {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [size, setSize] = useState<ContainerSize>({ width: 0, height: 0 });\n const rafRef = useRef<number>(0);\n\n const handleResize = useCallback((entries: ResizeObserverEntry[]) => {\n // Use rAF to batch size updates and avoid layout thrashing\n cancelAnimationFrame(rafRef.current);\n rafRef.current = requestAnimationFrame(() => {\n const entry = entries[0];\n if (entry) {\n const { width, height } = entry.contentRect;\n setSize((prev) => {\n // Only update if dimensions actually changed (avoid re-renders)\n if (\n Math.abs(prev.width - width) < 1 &&\n Math.abs(prev.height - height) < 1\n ) {\n return prev;\n }\n return { width, height };\n });\n }\n });\n }, []);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const observer = new ResizeObserver(handleResize);\n observer.observe(el);\n\n return () => {\n cancelAnimationFrame(rafRef.current);\n observer.disconnect();\n };\n }, [handleResize]);\n\n return { containerRef, size };\n}\n","import { useState, useCallback, useRef, useEffect } from \"react\";\nimport {\n readColumnValues,\n buildFilterIndex,\n buildGroups,\n collectUniqueValues,\n createEmptyPipeline,\n compareValues,\n asyncSort,\n yieldToUI,\n type ParquetMetadata,\n type ParquetRow,\n type ParquetSource,\n type SortDef,\n type SortDirection,\n type FilterDef,\n type GroupDef,\n type GroupNode,\n type PipelineState,\n} from \"@parqui/core\";\nimport { useSourceLoader } from \"./useSourceLoader.js\";\nimport { useChunkLoader } from \"./useChunkLoader.js\";\nimport type { ParquetInputSource } from \"../source.js\";\n\n// ── Public interface ──\n\nexport interface UseParquetDataReturn {\n metadata: ParquetMetadata | null;\n loading: boolean;\n error: string | null;\n totalRows: number;\n\n pipeline: PipelineState;\n computing: boolean;\n filteredRowCount: number;\n groups: GroupNode[];\n\n getRow: (displayIndex: number) => ParquetRow | undefined;\n ensureRange: (start: number, end: number) => void;\n ensureIndices: (displayIndices: number[]) => void;\n renderTick: number;\n\n // Sort\n toggleSort: (column: string, multi?: boolean) => void;\n setSort: (sorts: SortDef[]) => void;\n clearSort: () => void;\n getSortDirection: (column: string) => SortDirection | null;\n getSortPriority: (column: string) => number | null;\n\n // Filter\n setFilter: (filter: FilterDef) => void;\n removeFilter: (column: string) => void;\n clearFilters: () => void;\n getFilter: (column: string) => FilterDef | undefined;\n getUniqueValues: (column: string) => Promise<unknown[]>;\n\n // Group\n setGroups: (groups: GroupDef[]) => void;\n toggleGroup: (column: string) => void;\n clearGroups: () => void;\n toggleGroupExpanded: (index: number) => void;\n\n resetAll: () => void;\n}\n\n// ── Hook ──\n\nexport function useParquetData(\n inputSource?: ParquetInputSource,\n columns?: string[],\n searchText?: string,\n): UseParquetDataReturn {\n // ── Layer 1: Source loading ──\n const { state: sourceState, sourceRef, metadataRef, mountedRef } = useSourceLoader(inputSource);\n\n // ── Layer 2: Pipeline state ──\n const [pipeline, setPipeline] = useState<PipelineState>(createEmptyPipeline);\n const [computing, setComputing] = useState(false);\n const [mapping, setMapping] = useState<number[] | null>(null);\n const [groups, setGroups] = useState<GroupNode[]>([]);\n\n const mappingRef = useRef<number[] | null>(null);\n const genRef = useRef(0);\n\n // Column value cache (survives pipeline recomputes, cleared on source change)\n const columnCacheRef = useRef<Map<string, unknown[]>>(new Map());\n const uniqueCacheRef = useRef<Map<string, unknown[]>>(new Map());\n\n const filteredRowCount = mapping ? mapping.length : sourceState.totalRows;\n\n // ── Layer 3: Chunk loading ──\n const chunks = useChunkLoader(\n sourceRef, metadataRef, mountedRef, mappingRef, genRef,\n columns, computing,\n );\n\n // ── Reset pipeline when source changes ──\n useEffect(() => {\n columnCacheRef.current.clear();\n uniqueCacheRef.current.clear();\n chunks.clearCaches();\n mappingRef.current = null;\n genRef.current++;\n setPipeline(createEmptyPipeline());\n setMapping(null);\n setGroups([]);\n setComputing(false);\n }, [inputSource]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // ── Pipeline compute ──\n\n useEffect(() => {\n const source = sourceRef.current;\n const metadata = metadataRef.current;\n const totalRows = metadata?.rowCount ?? 0;\n\n if (!source || !metadata || totalRows === 0) {\n if (mappingRef.current !== null) {\n genRef.current++;\n }\n mappingRef.current = null;\n setMapping(null);\n setGroups([]);\n setComputing(false);\n return;\n }\n\n // Capture narrowed values for async closure\n const narrowedSource: import(\"@parqui/core\").ParquetSource = source;\n const allColumnNames = metadata.columns.map((c) => c.name);\n const { sorts, filters, groups: groupDefs } = pipeline;\n const needle = searchText?.trim().toLowerCase() ?? \"\";\n\n // Fast path: no transforms → identity\n if (sorts.length === 0 && filters.length === 0 && groupDefs.length === 0 && !needle) {\n const hadMapping = mappingRef.current !== null;\n mappingRef.current = null;\n setMapping(null);\n setGroups([]);\n setComputing(false);\n if (hadMapping) {\n // Only invalidate in-flight loads when transitioning FROM a pipeline\n // back to identity. On initial load (hadMapping=false) there are no\n // stale reads to discard, and incrementing gen here would race with\n // child-component effects that already captured the current gen.\n genRef.current++;\n chunks.clearCaches();\n }\n return;\n }\n\n // Async compute\n const gen = ++genRef.current;\n const isStale = () => gen !== genRef.current;\n\n chunks.clearCaches();\n setComputing(true);\n\n async function compute() {\n try {\n // 1. Read needed columns\n const neededCols = new Set<string>();\n for (const s of sorts) neededCols.add(s.column);\n for (const f of filters) neededCols.add(f.column);\n for (const g of groupDefs) neededCols.add(g.column);\n // Full-text search needs all columns\n if (needle) {\n for (const c of allColumnNames) neededCols.add(c);\n }\n\n const toRead = [...neededCols].filter(\n (c) => !columnCacheRef.current.has(c),\n );\n if (toRead.length > 0) {\n const newCols = await readColumnValues(narrowedSource, toRead, isStale);\n if (isStale()) return;\n for (const [key, vals] of newCols) {\n columnCacheRef.current.set(key, vals);\n }\n }\n\n if (isStale()) return;\n await yieldToUI();\n\n // 2. Filter\n let indices = buildFilterIndex(totalRows, filters, columnCacheRef.current);\n if (indices === null) {\n indices = Array.from({ length: totalRows }, (_, i) => i);\n }\n\n // 2b. Full-text search filter\n if (needle) {\n indices = indices.filter((rowIdx) => {\n for (const colName of allColumnNames) {\n const col = columnCacheRef.current.get(colName);\n if (!col) continue;\n const val = col[rowIdx];\n if (val === null || val === undefined) continue;\n const str = typeof val === \"object\" ? JSON.stringify(val) : String(val);\n if (str.toLowerCase().includes(needle)) return true;\n }\n return false;\n });\n }\n\n if (isStale()) return;\n await yieldToUI();\n\n // 3. Sort\n if (sorts.length > 0) {\n const colValues = columnCacheRef.current;\n const compareFn = (a: number, b: number) => {\n for (const sort of sorts) {\n const col = colValues.get(sort.column);\n if (!col) continue;\n const va = col[a];\n const vb = col[b];\n const cmp = compareValues(va, vb);\n if (cmp !== 0) return sort.direction === \"asc\" ? cmp : -cmp;\n }\n return a - b;\n };\n\n if (indices.length > 100_000) {\n indices = await asyncSort(indices, compareFn, isStale);\n } else {\n indices.sort(compareFn);\n }\n }\n\n if (isStale()) return;\n\n // 4. Group\n let groupNodes: GroupNode[] = [];\n if (groupDefs.length > 0) {\n groupNodes = buildGroups(indices, groupDefs, columnCacheRef.current);\n }\n\n // 5. Apply\n mappingRef.current = indices;\n setMapping(indices);\n setGroups(groupNodes);\n } catch {\n // Keep previous state on error\n } finally {\n if (!isStale()) setComputing(false);\n }\n }\n\n compute();\n }, [sourceState.source, sourceState.metadata, sourceState.totalRows, pipeline, searchText]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // ── Sort actions ──\n\n const toggleSort = useCallback((column: string, multi = false) => {\n setPipeline((prev) => {\n const existing = prev.sorts.find((s) => s.column === column);\n let newSorts: SortDef[];\n if (!existing) {\n newSorts = multi ? [...prev.sorts, { column, direction: \"asc\" }] : [{ column, direction: \"asc\" }];\n } else if (existing.direction === \"asc\") {\n newSorts = multi\n ? prev.sorts.map((s) =>\n s.column === column ? { ...s, direction: \"desc\" as const } : s,\n )\n : [{ column, direction: \"desc\" }];\n } else {\n newSorts = multi ? prev.sorts.filter((s) => s.column !== column) : [];\n }\n return { ...prev, sorts: newSorts };\n });\n }, []);\n\n const setSort = useCallback((sorts: SortDef[]) => {\n setPipeline((prev) => ({ ...prev, sorts }));\n }, []);\n\n const clearSort = useCallback(() => {\n setPipeline((prev) => ({ ...prev, sorts: [] }));\n }, []);\n\n const getSortDirection = useCallback(\n (column: string): SortDirection | null =>\n pipeline.sorts.find((s) => s.column === column)?.direction ?? null,\n [pipeline.sorts],\n );\n\n const getSortPriority = useCallback(\n (column: string): number | null => {\n const idx = pipeline.sorts.findIndex((s) => s.column === column);\n return idx >= 0 ? idx + 1 : null;\n },\n [pipeline.sorts],\n );\n\n // ── Filter actions ──\n\n const setFilter = useCallback((filter: FilterDef) => {\n setPipeline((prev) => ({\n ...prev,\n filters: [\n ...prev.filters.filter((f) => f.column !== filter.column),\n filter,\n ],\n }));\n }, []);\n\n const removeFilter = useCallback((column: string) => {\n setPipeline((prev) => ({\n ...prev,\n filters: prev.filters.filter((f) => f.column !== column),\n }));\n }, []);\n\n const clearFilters = useCallback(() => {\n setPipeline((prev) => ({ ...prev, filters: [] }));\n }, []);\n\n const getFilter = useCallback(\n (column: string): FilterDef | undefined =>\n pipeline.filters.find((f) => f.column === column),\n [pipeline.filters],\n );\n\n const getUniqueValues = useCallback(\n async (column: string): Promise<unknown[]> => {\n if (uniqueCacheRef.current.has(column)) {\n return uniqueCacheRef.current.get(column)!;\n }\n const source = sourceRef.current;\n if (!source) return [];\n\n let values = columnCacheRef.current.get(column);\n if (!values) {\n const cols = await readColumnValues(source, [column]);\n values = cols.get(column) ?? [];\n columnCacheRef.current.set(column, values);\n }\n\n const unique = collectUniqueValues(values, 500);\n uniqueCacheRef.current.set(column, unique);\n return unique;\n },\n [], // eslint-disable-line react-hooks/exhaustive-deps\n );\n\n // ── Group actions ──\n\n const setGroupDefs = useCallback((groupDefs: GroupDef[]) => {\n setPipeline((prev) => ({ ...prev, groups: groupDefs }));\n }, []);\n\n const toggleGroup = useCallback((column: string) => {\n setPipeline((prev) => {\n const exists = prev.groups.some((g) => g.column === column);\n const newGroups = exists\n ? prev.groups.filter((g) => g.column !== column)\n : [...prev.groups, { column }];\n return { ...prev, groups: newGroups };\n });\n }, []);\n\n const clearGroups = useCallback(() => {\n setPipeline((prev) => ({ ...prev, groups: [] }));\n }, []);\n\n const toggleGroupExpanded = useCallback((groupIndex: number) => {\n setGroups((prev) =>\n prev.map((g, i) =>\n i === groupIndex ? { ...g, expanded: !g.expanded } : g,\n ),\n );\n }, []);\n\n // ── Reset ──\n\n const resetAll = useCallback(() => {\n setPipeline(createEmptyPipeline());\n mappingRef.current = null;\n genRef.current++;\n chunks.clearCaches();\n setMapping(null);\n setGroups([]);\n setComputing(false);\n columnCacheRef.current.clear();\n uniqueCacheRef.current.clear();\n }, [chunks]);\n\n return {\n metadata: sourceState.metadata,\n loading: sourceState.loading,\n error: sourceState.error,\n totalRows: sourceState.totalRows,\n pipeline,\n computing,\n filteredRowCount,\n groups,\n getRow: chunks.getRow,\n ensureRange: chunks.ensureRange,\n ensureIndices: chunks.ensureIndices,\n renderTick: chunks.renderTick,\n toggleSort,\n setSort,\n clearSort,\n getSortDirection,\n getSortPriority,\n setFilter,\n removeFilter,\n clearFilters,\n getFilter,\n getUniqueValues,\n setGroups: setGroupDefs,\n toggleGroup,\n clearGroups,\n toggleGroupExpanded,\n resetAll,\n };\n}\n","import { useState, useEffect, useRef } from \"react\";\nimport {\n readParquetMetadata,\n sourceFromFile,\n sourceFromBuffer,\n sourceFromUrl,\n type ParquetMetadata,\n type ParquetSource,\n} from \"@parqui/core\";\nimport {\n resolveSourceInput,\n type ParquetInputSource,\n} from \"../source.js\";\n\nexport interface SourceState {\n metadata: ParquetMetadata | null;\n source: ParquetSource | null;\n loading: boolean;\n error: string | null;\n totalRows: number;\n}\n\nconst EMPTY_STATE: SourceState = {\n metadata: null,\n source: null,\n loading: false,\n error: null,\n totalRows: 0,\n};\n\n/**\n * Resolves a ParquetInputSource into a ParquetSource and reads its metadata.\n * Handles File, ArrayBuffer, URL, and raw ParquetSource inputs.\n *\n * Returns stable refs for the source and metadata alongside React state.\n */\nexport function useSourceLoader(inputSource?: ParquetInputSource) {\n const [state, setState] = useState<SourceState>(EMPTY_STATE);\n\n // Refs for synchronous access (no re-render needed)\n const sourceRef = useRef<ParquetSource | null>(null);\n const metadataRef = useRef<ParquetMetadata | null>(null);\n const mountedRef = useRef(true);\n\n useEffect(() => {\n mountedRef.current = true;\n sourceRef.current = null;\n metadataRef.current = null;\n setState({ ...EMPTY_STATE, loading: true });\n\n let cancelled = false;\n\n async function init() {\n try {\n let source: ParquetSource;\n const resolved = resolveSourceInput(inputSource);\n\n if (resolved.source) source = resolved.source;\n else if (resolved.data) source = sourceFromBuffer(resolved.data);\n else if (resolved.file) source = sourceFromFile(resolved.file);\n else if (resolved.url) source = await sourceFromUrl(resolved.url);\n else {\n setState(EMPTY_STATE);\n return;\n }\n\n if (cancelled) return;\n sourceRef.current = source;\n\n const metadata = await readParquetMetadata(source);\n if (cancelled) return;\n\n metadataRef.current = metadata;\n setState({\n metadata,\n source,\n loading: false,\n error: null,\n totalRows: metadata.rowCount,\n });\n } catch (err) {\n if (!cancelled) {\n setState({\n ...EMPTY_STATE,\n error: err instanceof Error ? err.message : \"Failed to load file\",\n });\n }\n }\n }\n\n init();\n\n return () => {\n cancelled = true;\n mountedRef.current = false;\n };\n }, [inputSource]);\n\n return { state, sourceRef, metadataRef, mountedRef };\n}\n","import type { ParquetSource } from \"@parqui/core\";\n\nexport type ParquetInputSource = File | ArrayBuffer | string | ParquetSource;\n\nexport interface ResolvedSourceInput {\n file?: File;\n data?: ArrayBuffer;\n url?: string;\n source?: ParquetSource;\n}\n\ntype SliceablePromise = Promise<ArrayBuffer> & {\n slice: (start: number, end?: number) => Promise<ArrayBuffer>;\n};\n\nfunction makeSliceablePromise(input: Promise<ArrayBuffer>): SliceablePromise {\n const promise = Promise.resolve(input) as SliceablePromise;\n promise.slice = (start: number, end?: number) =>\n promise.then((buffer) => buffer.slice(start, end));\n return promise;\n}\n\nconst sourceCache = new WeakMap<ParquetSource, ParquetSource>();\n\nfunction normalizeParquetSource(source: ParquetSource): ParquetSource {\n const cached = sourceCache.get(source);\n if (cached) return cached;\n\n const wrapped: ParquetSource = {\n byteLength: source.byteLength,\n slice(start: number, end?: number): Promise<ArrayBuffer> {\n return makeSliceablePromise(\n Promise.resolve(source.slice(start, end)),\n );\n },\n };\n\n sourceCache.set(source, wrapped);\n return wrapped;\n}\n\nexport function isFileSource(value: unknown): value is File {\n return typeof File !== \"undefined\" && value instanceof File;\n}\n\nexport function isArrayBufferSource(value: unknown): value is ArrayBuffer {\n return value instanceof ArrayBuffer;\n}\n\nexport function isParquetSource(value: unknown): value is ParquetSource {\n if (!value || typeof value !== \"object\") return false;\n const candidate = value as Partial<ParquetSource>;\n return typeof candidate.byteLength === \"number\" && typeof candidate.slice === \"function\";\n}\n\nexport function resolveSourceInput(\n source: ParquetInputSource | undefined,\n): ResolvedSourceInput {\n if (source === undefined) return {};\n if (isFileSource(source)) return { file: source };\n if (isArrayBufferSource(source)) return { data: source };\n if (typeof source === \"string\") return { url: source };\n if (isParquetSource(source)) return { source: normalizeParquetSource(source) };\n return {};\n}\n\nexport function sourceToDisplayName(source: ParquetInputSource): string {\n if (isFileSource(source)) return source.name;\n if (typeof source === \"string\") return urlToName(source);\n return \"\";\n}\n\nexport function sourceToDisplaySize(\n source: ParquetInputSource,\n): number | undefined {\n if (isFileSource(source)) return source.size;\n return undefined;\n}\n\nfunction urlToName(url: string): string {\n try {\n const pathname = new URL(url).pathname;\n return pathname.split(\"/\").pop() ?? url;\n } catch {\n return url;\n }\n}\n","import { useState, useCallback, useRef } from \"react\";\nimport {\n readParquetData,\n runWithConcurrency,\n type ParquetRow,\n type ParquetSource,\n type ParquetMetadata,\n} from \"@parqui/core\";\n\n// ── Constants ──\n\nconst CHUNK_SIZE = 500;\nconst MAX_DISPLAY_CHUNKS = 10;\nconst SOURCE_CACHE_MAX = 5_000;\nconst MAX_CONCURRENT_READS = 4;\nconst GAP_TOLERANCE = 200;\n\ninterface ChunkEntry {\n rows: ParquetRow[];\n loadedAt: number;\n}\n\nexport interface ChunkLoader {\n /** Get a row by display index. Returns undefined if not yet loaded. */\n getRow: (displayIndex: number) => ParquetRow | undefined;\n /** Ensure rows in [start, end) range are loaded. */\n ensureRange: (start: number, end: number) => void;\n /** Ensure specific display indices are loaded (for grouped view). */\n ensureIndices: (displayIndices: number[]) => void;\n /** Clear all caches. Call when pipeline changes. */\n clearCaches: () => void;\n /** Counter that increments when display data changes. */\n renderTick: number;\n}\n\n/**\n * Manages chunked, on-demand loading of parquet row data.\n *\n * Two modes:\n * 1. Sequential (no mapping): reads offset/limit directly.\n * 2. Mapped (filtered/sorted): uses mapping array to fetch source rows,\n * clustering nearby indices for efficient batch reads.\n *\n * @param sourceRef — ref to current ParquetSource\n * @param metadataRef — ref to current metadata\n * @param mountedRef — ref to mounted flag\n * @param mappingRef — ref to filtered+sorted row index array (null = identity)\n * @param genRef — ref to generation counter for staleness detection\n * @param columns — optional column filter\n * @param computing — whether pipeline is currently computing (blocks loading)\n */\nexport function useChunkLoader(\n sourceRef: React.RefObject<ParquetSource | null>,\n metadataRef: React.RefObject<ParquetMetadata | null>,\n mountedRef: React.RefObject<boolean>,\n mappingRef: React.RefObject<number[] | null>,\n genRef: React.RefObject<number>,\n columns?: string[],\n computing?: boolean,\n): ChunkLoader {\n const [renderTick, setRenderTick] = useState(0);\n\n const columnsRef = useRef<string[] | undefined>(columns);\n columnsRef.current = columns;\n\n // Display chunk cache: chunkIndex → rows\n const chunksRef = useRef<Map<number, ChunkEntry>>(new Map());\n const loadingChunksRef = useRef<Set<number>>(new Set());\n\n // Source row cache for mapped mode: sourceRowIndex → row\n const sourceRowCacheRef = useRef<Map<number, ParquetRow>>(new Map());\n\n const tick = useCallback(() => setRenderTick((v) => v + 1), []);\n\n const clearCaches = useCallback(() => {\n chunksRef.current.clear();\n loadingChunksRef.current.clear();\n sourceRowCacheRef.current.clear();\n tick();\n }, [tick]);\n\n // ── Fetch source rows by clustering nearby indices ──\n\n const fetchSourceRows = useCallback(\n async (neededIndices: number[], gen: number): Promise<void> => {\n if (!sourceRef.current || !metadataRef.current || neededIndices.length === 0) return;\n\n const totalRows = metadataRef.current.rowCount;\n const unique = [...new Set(neededIndices)].filter(\n (idx) => !sourceRowCacheRef.current.has(idx),\n );\n if (unique.length === 0) return;\n\n unique.sort((a, b) => a - b);\n\n // Cluster nearby indices\n const clusters: { start: number; end: number; needed: Set<number> }[] = [];\n let curStart = unique[0];\n let curEnd = unique[0] + 1;\n let curNeeded = new Set([unique[0]]);\n\n for (let i = 1; i < unique.length; i++) {\n if (unique[i] <= curEnd + GAP_TOLERANCE) {\n curEnd = unique[i] + 1;\n curNeeded.add(unique[i]);\n } else {\n clusters.push({ start: curStart, end: curEnd, needed: curNeeded });\n curStart = unique[i];\n curEnd = unique[i] + 1;\n curNeeded = new Set([unique[i]]);\n }\n }\n clusters.push({ start: curStart, end: curEnd, needed: curNeeded });\n\n await runWithConcurrency(clusters, MAX_CONCURRENT_READS, async (cluster) => {\n if (gen !== genRef.current) return;\n try {\n const readStart = Math.max(0, cluster.start);\n const readEnd = Math.min(cluster.end, totalRows);\n const result = await readParquetData(sourceRef.current!, {\n columns: columnsRef.current,\n offset: readStart,\n limit: readEnd - readStart,\n });\n if (!mountedRef.current || gen !== genRef.current) return;\n\n for (let i = 0; i < result.rows.length; i++) {\n const sourceIdx = readStart + i;\n if (cluster.needed.has(sourceIdx)) {\n sourceRowCacheRef.current.set(sourceIdx, result.rows[i]);\n }\n }\n } catch {\n // Will be retried on next ensureRange\n }\n });\n\n // Evict oldest if cache is too large\n const cache = sourceRowCacheRef.current;\n if (cache.size > SOURCE_CACHE_MAX) {\n const toDelete = cache.size - SOURCE_CACHE_MAX;\n let count = 0;\n for (const key of cache.keys()) {\n if (count >= toDelete) break;\n cache.delete(key);\n count++;\n }\n }\n },\n [sourceRef, metadataRef, mountedRef, genRef],\n );\n\n // ── Load a single display chunk ──\n\n const loadChunk = useCallback(\n async (chunkIndex: number) => {\n if (loadingChunksRef.current.has(chunkIndex)) return;\n if (chunksRef.current.has(chunkIndex)) return;\n if (!sourceRef.current) return;\n\n loadingChunksRef.current.add(chunkIndex);\n const gen = genRef.current;\n\n try {\n const curMapping = mappingRef.current;\n const displayStart = chunkIndex * CHUNK_SIZE;\n\n if (curMapping) {\n // Mapped mode: resolve source indices\n const displayEnd = Math.min(displayStart + CHUNK_SIZE, curMapping.length);\n const sourceIndices = curMapping.slice(displayStart, displayEnd);\n const uncached = sourceIndices.filter(\n (idx) => !sourceRowCacheRef.current.has(idx),\n );\n\n if (uncached.length > 0) {\n await fetchSourceRows(uncached, gen);\n if (!mountedRef.current || gen !== genRef.current) return;\n }\n\n const rows: ParquetRow[] = [];\n for (const sourceIdx of sourceIndices) {\n rows.push(sourceRowCacheRef.current.get(sourceIdx) ?? {});\n }\n\n if (mountedRef.current && gen === genRef.current) {\n chunksRef.current.set(chunkIndex, { rows, loadedAt: Date.now() });\n evictOldChunks(chunksRef.current);\n tick();\n }\n } else {\n // Sequential mode: direct offset/limit read\n const result = await readParquetData(sourceRef.current!, {\n columns: columnsRef.current,\n offset: displayStart,\n limit: CHUNK_SIZE,\n });\n\n if (mountedRef.current && gen === genRef.current) {\n chunksRef.current.set(chunkIndex, { rows: result.rows, loadedAt: Date.now() });\n evictOldChunks(chunksRef.current);\n tick();\n }\n }\n } catch {\n // Will be retried on next ensureRange\n } finally {\n loadingChunksRef.current.delete(chunkIndex);\n }\n },\n [sourceRef, mappingRef, mountedRef, genRef, fetchSourceRows, tick],\n );\n\n // ── Public API ──\n\n const getRow = useCallback(\n (displayIndex: number): ParquetRow | undefined => {\n const chunkIndex = Math.floor(displayIndex / CHUNK_SIZE);\n const chunk = chunksRef.current.get(chunkIndex);\n if (!chunk) return undefined;\n return chunk.rows[displayIndex - chunkIndex * CHUNK_SIZE];\n },\n [],\n );\n\n const ensureRange = useCallback(\n (start: number, end: number) => {\n if (computing) return;\n const startChunk = Math.floor(start / CHUNK_SIZE);\n const endChunk = Math.floor(Math.max(0, end - 1) / CHUNK_SIZE);\n for (let i = startChunk; i <= endChunk; i++) {\n if (!chunksRef.current.has(i) && !loadingChunksRef.current.has(i)) {\n loadChunk(i);\n }\n }\n },\n [loadChunk, computing],\n );\n\n const ensureIndices = useCallback(\n (displayIndices: number[]) => {\n if (computing) return;\n const chunkSet = new Set<number>();\n for (const idx of displayIndices) {\n chunkSet.add(Math.floor(idx / CHUNK_SIZE));\n }\n for (const chunkIdx of chunkSet) {\n if (!chunksRef.current.has(chunkIdx) && !loadingChunksRef.current.has(chunkIdx)) {\n loadChunk(chunkIdx);\n }\n }\n },\n [loadChunk, computing],\n );\n\n return { getRow, ensureRange, ensureIndices, clearCaches, renderTick };\n}\n\n// ── Internal helpers ──\n\nfunction evictOldChunks(chunks: Map<number, ChunkEntry>) {\n if (chunks.size <= MAX_DISPLAY_CHUNKS) return;\n const entries = [...chunks.entries()].sort(\n (a, b) => a[1].loadedAt - b[1].loadedAt,\n );\n const toRemove = entries.length - MAX_DISPLAY_CHUNKS;\n for (let i = 0; i < toRemove; i++) {\n chunks.delete(entries[i][0]);\n }\n}\n","import { useState, useCallback, useRef, useEffect } from \"react\";\n\nexport const ROW_HEIGHT = 32;\nexport const HEADER_HEIGHT = 36;\nconst OVERSCAN = 10; // extra rows rendered above/below viewport\n\nconst MAX_SCROLL_HEIGHT = 1_500_000;\n\nexport interface VirtualScrollState {\n scrollTop: number;\n startIndex: number;\n endIndex: number;\n visibleCount: number;\n totalHeight: number;\n offsetY: number;\n}\n\nexport interface VirtualScroll extends VirtualScrollState {\n onScroll: (e: React.UIEvent<HTMLDivElement>) => void;\n scrollToRow: (rowIndex: number) => void;\n /** Callback ref — attach to the scroll container element. */\n scrollRef: (el: HTMLDivElement | null) => void;\n /** Read-only ref to the scroll container (for imperative access). */\n scrollEl: React.RefObject<HTMLDivElement | null>;\n}\n\n/**\n * Virtual scroll engine.\n *\n * Uses a callback ref to attach a ResizeObserver the moment the scroll\n * container mounts (not on first render — the element may not exist yet\n * if the component shows a loading state first).\n *\n * On resize, adjusts scrollTop to maintain the same first visible row.\n */\nexport function useVirtualScroll(\n containerHeight: number,\n totalRows: number,\n resetKey?: unknown,\n): VirtualScroll {\n const elRef = useRef<HTMLDivElement | null>(null);\n const roRef = useRef<ResizeObserver | null>(null);\n const [scrollTop, setScrollTop] = useState(0);\n const [measuredHeight, setMeasuredHeight] = useState(0);\n\n // Current scroll params — used by ResizeObserver to maintain rawStart\n const paramsRef = useRef({\n rawStart: 0,\n scaled: false,\n totalHeight: 0,\n totalRows: 0,\n });\n\n // Callback ref: sets up ResizeObserver when the element mounts,\n // cleans up when it unmounts. This works even if the element appears\n // after the first render (e.g. after loading finishes).\n const scrollRef = useCallback((el: HTMLDivElement | null) => {\n // Clean up previous observer\n if (roRef.current) {\n roRef.current.disconnect();\n roRef.current = null;\n }\n\n elRef.current = el;\n\n if (!el) return;\n\n // Initial measurement\n setMeasuredHeight(el.clientHeight);\n setScrollTop(el.scrollTop);\n\n roRef.current = new ResizeObserver(() => {\n const newClientHeight = el.clientHeight;\n const p = paramsRef.current;\n\n if (p.scaled && p.totalRows > 0) {\n const newBodyHeight = Math.max(1, newClientHeight - HEADER_HEIGHT);\n const newMaxScroll = Math.max(1, p.totalHeight - newBodyHeight);\n const newFullyVisible = Math.floor(newBodyHeight / ROW_HEIGHT);\n const newMaxFirstRow = Math.max(1, p.totalRows - newFullyVisible);\n const targetRaw = Math.min(p.rawStart, newMaxFirstRow);\n const newScrollTop = (targetRaw / newMaxFirstRow) * newMaxScroll;\n\n el.scrollTop = newScrollTop;\n setScrollTop(el.scrollTop);\n } else {\n setScrollTop(el.scrollTop);\n }\n\n setMeasuredHeight(newClientHeight);\n });\n\n roRef.current.observe(el);\n }, []);\n\n // Always prefer the live DOM height over React state to avoid stale values after resize.\n // `measuredHeight` state is only used to trigger re-renders via ResizeObserver;\n // the actual computation uses the real clientHeight from the DOM.\n const liveHeight = elRef.current?.clientHeight ?? 0;\n const effectiveHeight = liveHeight > 0 ? liveHeight : (measuredHeight > 0 ? measuredHeight : containerHeight);\n\n // Reset scroll only when the data source changes\n useEffect(() => {\n setScrollTop(0);\n if (elRef.current) {\n elRef.current.scrollTop = 0;\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resetKey]);\n\n const bodyHeight = Math.max(1, effectiveHeight - HEADER_HEIGHT);\n const visibleCount = Math.ceil(bodyHeight / ROW_HEIGHT);\n\n const naturalHeight = totalRows * ROW_HEIGHT;\n const scaled = naturalHeight > MAX_SCROLL_HEIGHT;\n const totalHeight = scaled ? MAX_SCROLL_HEIGHT : naturalHeight + ROW_HEIGHT;\n\n let startIndex: number;\n let endIndex: number;\n let offsetY: number;\n let rawStart: number;\n\n if (scaled) {\n const maxScroll = Math.max(1, totalHeight - bodyHeight);\n const scrollFraction = Math.min(1, Math.max(0, scrollTop / maxScroll));\n const fullyVisibleRows = Math.floor(bodyHeight / ROW_HEIGHT);\n const maxFirstRow = Math.max(0, totalRows - fullyVisibleRows);\n rawStart = Math.round(scrollFraction * maxFirstRow);\n startIndex = Math.max(0, rawStart - OVERSCAN);\n endIndex = Math.min(totalRows, rawStart + visibleCount + OVERSCAN);\n\n const overscanAbove = rawStart - startIndex;\n offsetY = scrollTop - overscanAbove * ROW_HEIGHT;\n } else {\n rawStart = Math.floor(scrollTop / ROW_HEIGHT);\n startIndex = Math.max(0, rawStart - OVERSCAN);\n endIndex = Math.min(totalRows, rawStart + visibleCount + OVERSCAN);\n offsetY = startIndex * ROW_HEIGHT;\n }\n\n // Keep params ref in sync for ResizeObserver\n paramsRef.current = { rawStart, scaled, totalHeight, totalRows };\n\n const onScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {\n const el = e.currentTarget;\n setScrollTop(el.scrollTop);\n setMeasuredHeight((prev) => {\n const h = el.clientHeight;\n return h === prev ? prev : h;\n });\n }, []);\n\n const scrollToRow = useCallback(\n (rowIndex: number) => {\n const el = elRef.current;\n if (!el) return;\n const idx = Math.max(0, Math.min(totalRows - 1, rowIndex));\n const actualBodyHeight = el.clientHeight - HEADER_HEIGHT;\n\n if (scaled) {\n const maxScroll = Math.max(1, totalHeight - actualBodyHeight);\n const fullyVisible = Math.floor(actualBodyHeight / ROW_HEIGHT);\n const maxFirstRow = Math.max(1, totalRows - fullyVisible);\n\n // Check visibility using the same Math.round as the render\n const frac = Math.min(1, Math.max(0, el.scrollTop / maxScroll));\n const renderRawStart = Math.round(frac * maxFirstRow);\n\n if (idx < renderRawStart) {\n el.scrollTop = (idx / maxFirstRow) * maxScroll;\n } else if (idx >= renderRawStart + fullyVisible) {\n el.scrollTop =\n ((idx - fullyVisible + 1) / maxFirstRow) * maxScroll;\n // Verify render's Math.round agrees; nudge if needed\n const checkFrac = Math.min(1, Math.max(0, el.scrollTop / maxScroll));\n const checkRaw = Math.round(checkFrac * maxFirstRow);\n if (idx >= checkRaw + fullyVisible) {\n el.scrollTop += 1;\n }\n }\n } else {\n const rowTop = idx * ROW_HEIGHT;\n const rowBottom = rowTop + ROW_HEIGHT;\n const viewTop = el.scrollTop;\n const viewBottom = viewTop + actualBodyHeight;\n\n if (rowTop < viewTop) {\n el.scrollTop = rowTop;\n } else if (rowBottom > viewBottom) {\n el.scrollTop = rowBottom - actualBodyHeight;\n }\n }\n\n // Sync state immediately\n setScrollTop(el.scrollTop);\n setMeasuredHeight(el.clientHeight);\n },\n [scaled, totalHeight, totalRows],\n );\n\n return {\n scrollTop,\n startIndex,\n endIndex,\n visibleCount,\n totalHeight,\n offsetY,\n onScroll,\n scrollToRow,\n scrollRef,\n scrollEl: elRef,\n };\n}\n","import { useState, useCallback, useRef } from \"react\";\n\nconst DEFAULT_COL_WIDTH = 150;\nconst MIN_COL_WIDTH = 50;\n\nexport interface ColumnDef {\n key: string;\n width: number;\n visible: boolean;\n}\n\nexport interface DragState {\n /** Column key being dragged */\n dragKey: string | null;\n /** Insert position index (the dragged column will be placed at this index) */\n insertIndex: number | null;\n}\n\nexport interface ResizeState {\n /** Column key being resized */\n columnKey: string | null;\n /** Starting mouse X */\n startX: number;\n /** Starting width */\n startWidth: number;\n}\n\nexport interface ColumnManager {\n columns: ColumnDef[];\n visibleColumns: ColumnDef[];\n totalWidth: number;\n /** Start dragging a column for reorder */\n startDrag: (key: string) => void;\n /** Update insert position based on mouse position over a column */\n updateDragOver: (overKey: string, mouseXInColumn: number, columnWidth: number) => void;\n /** Set insert position to after last column */\n updateDragOverEnd: () => void;\n /** Finish drag — apply the reorder */\n endDrag: () => void;\n dragState: DragState;\n /** Start resizing a column */\n startResize: (key: string, clientX: number) => void;\n /** Update resize (call on mousemove) */\n updateResize: (clientX: number) => void;\n /** End resize */\n endResize: () => void;\n resizeState: ResizeState;\n /** Toggle column visibility */\n toggleColumn: (key: string) => void;\n /** Show all columns */\n showAllColumns: () => void;\n /** Set column width explicitly */\n setColumnWidth: (key: string, width: number) => void;\n}\n\n/**\n * Manages column definitions: order, width, visibility, drag-and-drop, resize.\n */\nexport function useColumnManager(\n columnNames: string[],\n initialWidths?: Record<string, number>,\n): ColumnManager {\n const [columns, setColumns] = useState<ColumnDef[]>(() =>\n columnNames.map((key) => ({\n key,\n width: initialWidths?.[key] ?? DEFAULT_COL_WIDTH,\n visible: true,\n })),\n );\n\n // Track if columnNames changed (new file)\n const prevNamesRef = useRef<string[]>(columnNames);\n if (\n columnNames.length !== prevNamesRef.current.length ||\n columnNames.some((n, i) => n !== prevNamesRef.current[i])\n ) {\n prevNamesRef.current = columnNames;\n const newCols = columnNames.map((key) => ({\n key,\n width: initialWidths?.[key] ?? DEFAULT_COL_WIDTH,\n visible: true,\n }));\n setColumns(newCols);\n }\n\n const [dragState, setDragState] = useState<DragState>({\n dragKey: null,\n insertIndex: null,\n });\n\n // Use a ref to reliably read drag state in endDrag (avoids stale closure)\n const dragRef = useRef<DragState>(dragState);\n dragRef.current = dragState;\n\n const [resizeState, setResizeState] = useState<ResizeState>({\n columnKey: null,\n startX: 0,\n startWidth: 0,\n });\n\n const visibleColumns = columns.filter((c) => c.visible);\n const totalWidth = visibleColumns.reduce((sum, c) => sum + c.width, 0);\n\n // ── Drag & Drop reorder ──\n\n const startDrag = useCallback((key: string) => {\n setDragState({ dragKey: key, insertIndex: null });\n }, []);\n\n const updateDragOver = useCallback(\n (overKey: string, mouseXInColumn: number, columnWidth: number) => {\n setDragState((prev) => {\n if (!prev.dragKey || prev.dragKey === overKey) {\n return { ...prev, insertIndex: null };\n }\n\n // Find indices in the visible columns list\n const visibleCols = columns.filter((c) => c.visible);\n const overIdx = visibleCols.findIndex((c) => c.key === overKey);\n if (overIdx === -1) return prev;\n\n // If mouse is in the left half of the column → insert before it\n // If mouse is in the right half → insert after it\n const isLeftHalf = mouseXInColumn < columnWidth / 2;\n const insertIndex = isLeftHalf ? overIdx : overIdx + 1;\n\n return { ...prev, insertIndex };\n });\n },\n [columns],\n );\n\n const updateDragOverEnd = useCallback(() => {\n setDragState((prev) => {\n if (!prev.dragKey) return prev;\n const visibleCols = columns.filter((c) => c.visible);\n return { ...prev, insertIndex: visibleCols.length };\n });\n }, [columns]);\n\n const endDrag = useCallback(() => {\n const { dragKey, insertIndex } = dragRef.current;\n\n // Reset state first\n setDragState({ dragKey: null, insertIndex: null });\n\n if (!dragKey || insertIndex === null) return;\n\n setColumns((cols) => {\n const visibleCols = cols.filter((c) => c.visible);\n const fromIdx = visibleCols.findIndex((c) => c.key === dragKey);\n if (fromIdx === -1) return cols;\n\n // If dropping in the same position or the next one (no actual move), skip\n if (insertIndex === fromIdx || insertIndex === fromIdx + 1) return cols;\n\n // Work with the full column array but compute reorder from visible indices.\n // Map visible indices to full array indices.\n const visibleToFullIdx: number[] = [];\n cols.forEach((c, fullIdx) => {\n if (c.visible) visibleToFullIdx.push(fullIdx);\n });\n\n const fullFromIdx = visibleToFullIdx[fromIdx];\n const moved = cols[fullFromIdx];\n\n // Remove the dragged column\n const newCols = cols.filter((_, i) => i !== fullFromIdx);\n\n // Calculate insert position in the new (removed) array.\n // insertIndex is the target slot among visible columns.\n // We need to find where that maps in newCols.\n let targetFullIdx: number;\n if (insertIndex >= visibleCols.length) {\n // Insert after last visible column\n const lastVisibleFullIdx = visibleToFullIdx[visibleCols.length - 1];\n // After removal, adjust index\n targetFullIdx =\n lastVisibleFullIdx > fullFromIdx\n ? lastVisibleFullIdx // -1 for removal +1 for after = net 0\n : lastVisibleFullIdx + 1;\n } else {\n // Insert before the column currently at insertIndex\n const adjustedInsertIdx =\n insertIndex > fromIdx ? insertIndex - 1 : insertIndex;\n const remainingVisible = newCols.filter((c) => c.visible);\n const targetKey = remainingVisible[adjustedInsertIdx]?.key;\n targetFullIdx = targetKey\n ? newCols.findIndex((c) => c.key === targetKey)\n : newCols.length;\n }\n\n newCols.splice(targetFullIdx, 0, moved);\n return newCols;\n });\n }, []);\n\n // ── Resize ──\n\n const startResize = useCallback(\n (key: string, clientX: number) => {\n const col = columns.find((c) => c.key === key);\n if (col) {\n setResizeState({\n columnKey: key,\n startX: clientX,\n startWidth: col.width,\n });\n }\n },\n [columns],\n );\n\n const updateResize = useCallback(\n (clientX: number) => {\n if (!resizeState.columnKey) return;\n const delta = clientX - resizeState.startX;\n const newWidth = Math.max(MIN_COL_WIDTH, resizeState.startWidth + delta);\n setColumns((cols) =>\n cols.map((c) =>\n c.key === resizeState.columnKey ? { ...c, width: newWidth } : c,\n ),\n );\n },\n [resizeState],\n );\n\n const endResize = useCallback(() => {\n setResizeState({ columnKey: null, startX: 0, startWidth: 0 });\n }, []);\n\n // ── Visibility ──\n\n const toggleColumn = useCallback((key: string) => {\n setColumns((cols) =>\n cols.map((c) => (c.key === key ? { ...c, visible: !c.visible } : c)),\n );\n }, []);\n\n const showAllColumns = useCallback(() => {\n setColumns((cols) => cols.map((c) => ({ ...c, visible: true })));\n }, []);\n\n const setColumnWidth = useCallback((key: string, width: number) => {\n setColumns((cols) =>\n cols.map((c) =>\n c.key === key ? { ...c, width: Math.max(MIN_COL_WIDTH, width) } : c,\n ),\n );\n }, []);\n\n return {\n columns,\n visibleColumns,\n totalWidth,\n startDrag,\n updateDragOver,\n updateDragOverEnd,\n endDrag,\n dragState,\n startResize,\n updateResize,\n endResize,\n resizeState,\n toggleColumn,\n showAllColumns,\n setColumnWidth,\n };\n}\n","import { useState, useCallback } from \"react\";\n\nexport interface CellPosition {\n row: number;\n col: number;\n}\n\nexport interface KeyboardNavigation {\n activeCell: CellPosition | null;\n setActiveCell: (pos: CellPosition | null) => void;\n handleKeyDown: (\n e: React.KeyboardEvent,\n totalRows: number,\n totalCols: number,\n ) => void;\n handleCellClick: (row: number, col: number) => void;\n}\n\n/**\n * Manages active cell state and keyboard navigation (arrows, Tab, Home/End, PgUp/PgDn).\n *\n * @param onScrollToCell — called with (row, col) when the active cell changes\n * so the scroll container can bring it into view (both vertical and horizontal).\n * @param isNavigable — optional predicate. When provided, arrow/tab/page\n * movement skips rows where `isNavigable(row)` returns false (e.g. group\n * headers in a grouped view).\n */\nexport function useKeyboardNavigation(\n onScrollToCell?: (row: number, col: number) => void,\n isNavigable?: (row: number) => boolean,\n): KeyboardNavigation {\n const [activeCell, setActiveCell] = useState<CellPosition | null>(null);\n\n const moveTo = useCallback(\n (row: number, col: number, totalRows: number, totalCols: number) => {\n let r = Math.max(0, Math.min(totalRows - 1, row));\n const clampedCol = Math.max(0, Math.min(totalCols - 1, col));\n\n if (isNavigable) {\n // If we landed on a non-navigable row, advance in the direction of movement\n if (!isNavigable(r)) {\n const currentRow = activeCell?.row ?? 0;\n const direction = row >= currentRow ? 1 : -1;\n // Search in direction\n let candidate = r;\n while (candidate >= 0 && candidate < totalRows && !isNavigable(candidate)) {\n candidate += direction;\n }\n if (candidate >= 0 && candidate < totalRows) {\n r = candidate;\n } else {\n // Try opposite direction\n candidate = r;\n while (candidate >= 0 && candidate < totalRows && !isNavigable(candidate)) {\n candidate -= direction;\n }\n if (candidate >= 0 && candidate < totalRows) {\n r = candidate;\n } else {\n return; // no navigable row found\n }\n }\n }\n }\n\n setActiveCell({ row: r, col: clampedCol });\n onScrollToCell?.(r, clampedCol);\n },\n [onScrollToCell, isNavigable, activeCell?.row],\n );\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent, totalRows: number, totalCols: number) => {\n if (!activeCell) {\n // If no cell is active and user presses arrow, activate first cell\n if (\n [\"ArrowDown\", \"ArrowUp\", \"ArrowLeft\", \"ArrowRight\"].includes(e.key)\n ) {\n e.preventDefault();\n moveTo(0, 0, totalRows, totalCols);\n }\n return;\n }\n\n const { row, col } = activeCell;\n const PAGE_SIZE = 20;\n\n switch (e.key) {\n case \"ArrowDown\":\n e.preventDefault();\n moveTo(row + 1, col, totalRows, totalCols);\n break;\n case \"ArrowUp\":\n e.preventDefault();\n moveTo(row - 1, col, totalRows, totalCols);\n break;\n case \"ArrowRight\":\n e.preventDefault();\n moveTo(row, col + 1, totalRows, totalCols);\n break;\n case \"ArrowLeft\":\n e.preventDefault();\n moveTo(row, col - 1, totalRows, totalCols);\n break;\n case \"Tab\":\n e.preventDefault();\n if (e.shiftKey) {\n if (col > 0) {\n moveTo(row, col - 1, totalRows, totalCols);\n } else if (row > 0) {\n moveTo(row - 1, totalCols - 1, totalRows, totalCols);\n }\n } else {\n if (col < totalCols - 1) {\n moveTo(row, col + 1, totalRows, totalCols);\n } else if (row < totalRows - 1) {\n moveTo(row + 1, 0, totalRows, totalCols);\n }\n }\n break;\n case \"Home\":\n e.preventDefault();\n if (e.ctrlKey) {\n moveTo(0, 0, totalRows, totalCols);\n } else {\n moveTo(row, 0, totalRows, totalCols);\n }\n break;\n case \"End\":\n e.preventDefault();\n if (e.ctrlKey) {\n moveTo(totalRows - 1, totalCols - 1, totalRows, totalCols);\n } else {\n moveTo(row, totalCols - 1, totalRows, totalCols);\n }\n break;\n case \"PageDown\":\n e.preventDefault();\n moveTo(row + PAGE_SIZE, col, totalRows, totalCols);\n break;\n case \"PageUp\":\n e.preventDefault();\n moveTo(row - PAGE_SIZE, col, totalRows, totalCols);\n break;\n case \"Escape\":\n e.preventDefault();\n setActiveCell(null);\n break;\n }\n },\n [activeCell, moveTo],\n );\n\n const handleCellClick = useCallback((row: number, col: number) => {\n setActiveCell({ row, col });\n }, []);\n\n return {\n activeCell,\n setActiveCell,\n handleKeyDown,\n handleCellClick,\n };\n}\n","import { useState, useCallback, useEffect, useRef } from \"react\";\n\nconst SEARCH_DEBOUNCE_MS = 300;\n\nexport interface SearchState {\n /** Raw input text (updates immediately on keystroke). */\n searchText: string;\n /** Debounced search text (updates after delay). */\n debouncedSearch: string;\n /** Input change handler. */\n handleSearchChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n /** Clear search text and debounced value. */\n clearSearch: () => void;\n /** Reset search (e.g. when file changes). */\n resetSearch: () => void;\n}\n\n/**\n * Manages search input state with debouncing.\n * Search is used for highlighting matching cells — not for filtering rows.\n */\nexport function useSearch(): SearchState {\n const [searchText, setSearchText] = useState(\"\");\n const [debouncedSearch, setDebouncedSearch] = useState(\"\");\n const timerRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const val = e.target.value;\n setSearchText(val);\n if (timerRef.current) clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setDebouncedSearch(val), SEARCH_DEBOUNCE_MS);\n }, []);\n\n const clearSearch = useCallback(() => {\n setSearchText(\"\");\n setDebouncedSearch(\"\");\n if (timerRef.current) clearTimeout(timerRef.current);\n }, []);\n\n const resetSearch = useCallback(() => {\n setSearchText(\"\");\n setDebouncedSearch(\"\");\n if (timerRef.current) clearTimeout(timerRef.current);\n }, []);\n\n // Cleanup timer on unmount\n useEffect(() => () => {\n if (timerRef.current) clearTimeout(timerRef.current);\n }, []);\n\n return { searchText, debouncedSearch, handleSearchChange, clearSearch, resetSearch };\n}\n","import { useCallback, useRef } from \"react\";\nimport type { PipelineState } from \"@parqui/core\";\nimport { PipelineChip } from \"./PipelineChip.js\";\nimport { FolderOpenIcon, FileIcon, CloseIcon, SearchIcon } from \"./Icons.js\";\nimport { formatFilterValue } from \"../utils/formatting.js\";\nimport { s } from \"../styles.js\";\n\nexport interface ToolbarProps {\n allowOpen: boolean;\n hasSource: boolean;\n fileName: string;\n pipeline: PipelineState;\n\n // Search\n searchText: string;\n onSearchChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n onClearSearch: () => void;\n\n // File actions\n onRequestOpen?: () => void | Promise<void>;\n onFileSelect: (file: File) => void;\n onClose: () => void;\n\n // Pipeline chip actions\n onRemoveSort: (column: string) => void;\n onRemoveFilter: (column: string) => void;\n onRemoveGroup: (column: string) => void;\n}\n\nexport function Toolbar({\n allowOpen,\n hasSource,\n fileName,\n pipeline,\n searchText,\n onSearchChange,\n onClearSearch,\n onRequestOpen,\n onFileSelect,\n onClose,\n onRemoveSort,\n onRemoveFilter,\n onRemoveGroup,\n}: ToolbarProps) {\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const handleOpenClick = useCallback(() => {\n if (onRequestOpen) {\n void onRequestOpen();\n } else {\n fileInputRef.current?.click();\n }\n }, [onRequestOpen]);\n\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const f = e.target.files?.[0];\n if (f) onFileSelect(f);\n e.target.value = \"\";\n },\n [onFileSelect],\n );\n\n return (\n <div style={s.toolbar}>\n {/* Left zone: Open + filename/close + group/sort chips */}\n <div style={s.toolbarFileZone}>\n {allowOpen && (\n <>\n <button\n type=\"button\"\n onClick={handleOpenClick}\n className=\"parqui-toolbar-open\"\n style={s.openButton}\n title=\"Open file (Ctrl+O)\"\n aria-label=\"Open file\"\n >\n <FolderOpenIcon />\n <span>Open</span>\n </button>\n {!onRequestOpen && (\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".parquet\"\n style={{ display: \"none\" }}\n onChange={handleInputChange}\n />\n )}\n </>\n )}\n\n {hasSource && (\n <>\n {allowOpen && <div style={s.separator} />}\n <span style={s.fileIcon}>\n <FileIcon />\n </span>\n <span style={s.fileName}>{fileName}</span>\n {allowOpen && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"parqui-close-btn\"\n style={s.closeButton}\n title=\"Close file\"\n aria-label=\"Close file\"\n >\n <CloseIcon />\n </button>\n )}\n\n {/* Group & sort chips */}\n {(pipeline.groups.length > 0 || pipeline.sorts.length > 0) && (\n <>\n <div style={s.separator} />\n <div style={s.chipsScroll} className=\"parqui-chips-scroll\">\n {pipeline.groups.map((g) => (\n <PipelineChip\n key={`group-${g.column}`}\n label={`\\u229e ${g.column}`}\n color=\"green\"\n onRemove={() => onRemoveGroup(g.column)}\n />\n ))}\n {pipeline.sorts.map((sort) => (\n <PipelineChip\n key={`sort-${sort.column}`}\n label={`${sort.column} ${sort.direction === \"asc\" ? \"\\u2191\" : \"\\u2193\"}`}\n color=\"blue\"\n onRemove={() => onRemoveSort(sort.column)}\n />\n ))}\n </div>\n </>\n )}\n </>\n )}\n </div>\n\n {/* Right zone: filter chips + search */}\n {hasSource && (\n <div style={s.toolbarPipeline}>\n {pipeline.filters.length > 0 && (\n <div style={{ ...s.chipsScroll, flex: \"none\" }} className=\"parqui-chips-scroll\">\n {pipeline.filters.map((f) => (\n <PipelineChip\n key={`filter-${f.column}`}\n label={`${f.column}: ${formatFilterValue(f.value)}`}\n color=\"amber\"\n onRemove={() => onRemoveFilter(f.column)}\n />\n ))}\n </div>\n )}\n <div style={s.searchWrapper}>\n <SearchIcon />\n <input\n type=\"text\"\n value={searchText}\n onChange={onSearchChange}\n placeholder=\"Search\"\n className=\"parqui-search-input\"\n style={s.searchInput}\n aria-label=\"Search cell values\"\n />\n {searchText && (\n <button\n type=\"button\"\n onClick={onClearSearch}\n style={s.searchClear}\n aria-label=\"Clear search\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </div>\n )}\n </div>\n );\n}\n","export function FolderOpenIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n\nexport function FileIcon() {\n return (\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n );\n}\n\nexport function CloseIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\nexport function SearchIcon() {\n return (\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" style={{ flexShrink: 0, color: \"#94a3b8\" }}>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n );\n}\n\nexport function ChipCloseIcon() {\n return (\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n","import { ChipCloseIcon } from \"./Icons.js\";\n\nconst chipColors = {\n blue: { bg: \"#eff6ff\", border: \"#bfdbfe\", text: \"#1e40af\" },\n amber: { bg: \"#fffbeb\", border: \"#fde68a\", text: \"#92400e\" },\n green: { bg: \"#ecfdf5\", border: \"#a7f3d0\", text: \"#065f46\" },\n} as const;\n\nexport function PipelineChip({\n label,\n color,\n onRemove,\n}: {\n label: string;\n color: \"blue\" | \"amber\" | \"green\";\n onRemove: () => void;\n}) {\n const c = chipColors[color];\n return (\n <span\n className=\"parqui-chip\"\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 4,\n padding: \"2px 4px 2px 8px\",\n fontSize: 11,\n fontWeight: 600,\n color: c.text,\n backgroundColor: c.bg,\n border: `1px solid ${c.border}`,\n borderRadius: 5,\n whiteSpace: \"nowrap\",\n cursor: \"default\",\n transition: \"background-color 0.15s, border-color 0.15s\",\n }}\n >\n <span style={{ overflow: \"hidden\", textOverflow: \"ellipsis\", maxWidth: 160 }}>\n {label}\n </span>\n <button\n type=\"button\"\n className=\"parqui-chip-remove\"\n onClick={onRemove}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 16,\n height: 16,\n border: \"none\",\n backgroundColor: \"transparent\",\n color: c.text,\n borderRadius: 3,\n cursor: \"pointer\",\n padding: 0,\n flexShrink: 0,\n transition: \"background-color 0.15s\",\n }}\n aria-label={`Remove ${label}`}\n >\n <ChipCloseIcon />\n </button>\n </span>\n );\n}\n","import type React from \"react\";\nimport { createElement } from \"react\";\n\n/** Format a cell value for display. */\nexport function formatCell(value: unknown): string {\n if (value === null || value === undefined) return \"\\u2205\";\n if (typeof value === \"object\") return JSON.stringify(value);\n return String(value);\n}\n\n/** Format a filter value for chip display. */\nexport function formatFilterValue(value: unknown): string {\n if (Array.isArray(value)) {\n if (value.length <= 3) return value.map(String).join(\", \");\n return `${value.slice(0, 3).map(String).join(\", \")} +${value.length - 3}`;\n }\n if (value === null || value === undefined) return \"\\u2205\";\n return String(value);\n}\n\n/**\n * Render a cell value with optional search term highlighting.\n * Returns a plain string when no match, or a React element with <mark> tags.\n */\nexport function highlightCell(value: unknown, searchText?: string): React.ReactNode {\n const text = formatCell(value);\n if (!searchText || !searchText.trim()) return text;\n\n const needle = searchText.trim().toLowerCase();\n const lowerText = text.toLowerCase();\n const idx = lowerText.indexOf(needle);\n if (idx === -1) return text;\n\n const parts: React.ReactNode[] = [];\n let cursor = 0;\n let pos = idx;\n let key = 0;\n while (pos !== -1) {\n if (pos > cursor) parts.push(text.slice(cursor, pos));\n parts.push(\n createElement(\"mark\", { key: key++, className: \"parqui-search-highlight\" }, text.slice(pos, pos + needle.length)),\n );\n cursor = pos + needle.length;\n pos = lowerText.indexOf(needle, cursor);\n }\n if (cursor < text.length) parts.push(text.slice(cursor));\n return createElement(\"span\", null, ...parts);\n}\n\n/** Check if any column value in a row matches the search needle. */\nexport function rowMatchesSearch(row: Record<string, unknown>, needle: string): boolean {\n for (const key in row) {\n const val = row[key];\n if (val === null || val === undefined) continue;\n const str = typeof val === \"object\" ? JSON.stringify(val) : String(val);\n if (str.toLowerCase().includes(needle)) return true;\n }\n return false;\n}\n","import type React from \"react\";\n\n/** Global CSS injected once into the document. */\nexport const PARKUI_CSS = `\n.parqui-toolbar-open:hover {\n background-color: #1e40af;\n border-color: #1e3a8a;\n}\n.parqui-toolbar-open:focus-visible {\n outline: 2px solid #93c5fd;\n outline-offset: 2px;\n}\n.parqui-toolbar-icon:hover {\n background-color: #eef3f9;\n color: #111827;\n border-color: #c7d1dd;\n}\n.parqui-toolbar-icon:focus-visible {\n outline: 2px solid #93c5fd;\n outline-offset: 1px;\n}\n.parqui-close-btn:hover {\n background-color: #fee2e2;\n color: #dc2626;\n}\n.parqui-chip:hover {\n background-color: #dbeafe;\n border-color: #93c5fd;\n}\n.parqui-chip-remove:hover {\n background-color: #bfdbfe;\n color: #1e40af;\n}\n.parqui-search-input:focus {\n border-color: #93c5fd;\n outline: none;\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.15);\n}\n.parqui-chips-scroll::-webkit-scrollbar {\n display: none;\n}\n@keyframes parqui-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n.parqui-grid-scrollbar::-webkit-scrollbar {\n width: 10px;\n height: 10px;\n}\n.parqui-grid-scrollbar::-webkit-scrollbar-track {\n background: #e9edf2;\n}\n.parqui-grid-scrollbar::-webkit-scrollbar-thumb {\n background: #b0bccb;\n border-radius: 999px;\n border: 2px solid #e9edf2;\n}\n.parqui-grid-scrollbar::-webkit-scrollbar-thumb:hover {\n background: #8ea0b6;\n}\n.parqui-grid-header-cell:hover {\n background: #edf2f7;\n color: #111827;\n}\n.parqui-grid-header-cell:hover .parqui-grid-header-label {\n color: #111827;\n}\n.parqui-grid-row:hover .parqui-grid-cell,\n.parqui-grid-row:hover .parqui-grid-row-num {\n background-color: #f0f4fa;\n}\n.parqui-grid-row .parqui-grid-cell {\n background-color: #ffffff;\n}\n.parqui-grid-row .parqui-grid-row-num {\n background-color: #f6f8fb;\n}\n.parqui-grid-row.parqui-grid-row-selected .parqui-grid-cell,\n.parqui-grid-row.parqui-grid-row-selected .parqui-grid-row-num {\n background-color: #e9f0fb;\n}\n.parqui-grid-group-header {\n background-color: #edf2f7;\n}\n.parqui-grid-group-header:hover {\n background-color: #e2ebf7;\n}\n.parqui-search-highlight {\n background-color: #fde68a;\n color: inherit;\n padding: 0;\n margin: 0;\n border-radius: 0;\n line-height: inherit;\n font-size: inherit;\n}\n`;\n\nexport const s: Record<string, React.CSSProperties> = {\n root: {\n fontFamily: \"'Plus Jakarta Sans', 'Inter', system-ui, sans-serif\",\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: \"#f3f5f8\",\n color: \"#1f2937\",\n overflow: \"hidden\",\n },\n toolbar: {\n display: \"flex\",\n alignItems: \"center\",\n padding: \"0 10px\",\n height: 40,\n userSelect: \"none\",\n flexShrink: 0,\n backgroundColor: \"#ffffff\",\n borderBottom: \"1px solid #d9e0ea\",\n gap: 0,\n },\n toolbarFileZone: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n flexShrink: 0,\n },\n toolbarPipeline: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n flex: 1,\n minWidth: 0,\n marginLeft: 12,\n justifyContent: \"flex-end\",\n },\n chipsScroll: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 5,\n flex: 1,\n minWidth: 0,\n overflowX: \"auto\",\n overflowY: \"hidden\",\n scrollbarWidth: \"none\",\n },\n searchWrapper: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"0 8px\",\n border: \"1px solid #d9e0ea\",\n borderRadius: 7,\n height: 28,\n backgroundColor: \"#f9fafb\",\n flexShrink: 0,\n minWidth: 160,\n maxWidth: 260,\n },\n searchInput: {\n border: \"none\",\n background: \"transparent\",\n outline: \"none\",\n fontSize: 12,\n color: \"#1f2937\",\n fontFamily: \"inherit\",\n width: \"100%\",\n padding: 0,\n },\n searchClear: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 16,\n height: 16,\n border: \"none\",\n backgroundColor: \"transparent\",\n color: \"#94a3b8\",\n cursor: \"pointer\",\n padding: 0,\n flexShrink: 0,\n borderRadius: 3,\n },\n openButton: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"0 12px\",\n fontSize: 12,\n fontWeight: 700,\n fontFamily: \"inherit\",\n color: \"#ffffff\",\n backgroundColor: \"#1d4ed8\",\n border: \"1px solid #1e40af\",\n borderRadius: 7,\n cursor: \"pointer\",\n whiteSpace: \"nowrap\",\n flexShrink: 0,\n height: 28,\n transition: \"background-color 0.15s, border-color 0.15s\",\n boxShadow: \"none\",\n },\n separator: {\n width: 1,\n height: 18,\n backgroundColor: \"#dce3ed\",\n margin: \"0 6px\",\n flexShrink: 0,\n },\n fileIcon: {\n flexShrink: 0,\n color: \"#64748b\",\n display: \"flex\",\n alignItems: \"center\",\n },\n fileName: {\n fontSize: 12,\n fontWeight: 600,\n color: \"#111827\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n maxWidth: 200,\n },\n closeButton: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 20,\n height: 20,\n border: \"none\",\n borderRadius: 4,\n backgroundColor: \"transparent\",\n color: \"#94a3b8\",\n cursor: \"pointer\",\n flexShrink: 0,\n padding: 0,\n transition: \"background-color 0.15s, color 0.15s\",\n marginLeft: 2,\n },\n content: {\n flex: 1,\n minHeight: 0,\n display: \"flex\",\n flexDirection: \"column\",\n fontSize: 13,\n outline: \"none\",\n position: \"relative\",\n },\n placeholder: {\n padding: 40,\n textAlign: \"center\",\n color: \"#6b7280\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flex: 1,\n },\n error: {\n padding: 20,\n color: \"#dc2626\",\n textAlign: \"center\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flex: 1,\n },\n dropZoneWrapper: {\n flex: 1,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n scrollContainer: {\n overflow: \"auto\",\n flex: 1,\n minHeight: 0,\n position: \"relative\",\n backgroundColor: \"#f7f9fc\",\n },\n headerRow: {\n display: \"flex\",\n position: \"sticky\",\n top: 0,\n zIndex: 2,\n backgroundColor: \"#ffffff\",\n boxShadow: \"0 1px 0 #d8e0ea\",\n },\n rowNumHeader: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"#f3f5f8\",\n borderBottom: \"1px solid #d9e0ea\",\n borderRight: \"1px solid #d9e0ea\",\n fontWeight: 600,\n fontSize: 12,\n color: \"#6b7280\",\n flexShrink: 0,\n boxSizing: \"border-box\",\n },\n groupHeader: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n padding: \"0 12px\",\n borderBottom: \"1px solid #d8e0ea\",\n cursor: \"pointer\",\n userSelect: \"none\",\n fontSize: 13,\n fontWeight: 600,\n boxSizing: \"border-box\",\n },\n groupChevron: {\n fontSize: 12,\n color: \"#4b5563\",\n width: 12,\n },\n groupLabel: {\n color: \"#1f2937\",\n },\n groupCount: {\n color: \"#6b7280\",\n fontSize: 12,\n },\n row: {\n display: \"flex\",\n borderBottom: \"1px solid #e5eaf1\",\n boxSizing: \"border-box\",\n backgroundColor: \"#ffffff\",\n },\n rowNum: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"flex-end\",\n padding: \"0 8px\",\n borderRight: \"1px solid #dfe6ef\",\n fontSize: 11,\n color: \"#6b7280\",\n flexShrink: 0,\n boxSizing: \"border-box\",\n userSelect: \"none\",\n },\n cell: {\n display: \"flex\",\n alignItems: \"center\",\n padding: \"0 12px\",\n borderRight: \"1px solid #e8edf3\",\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n textOverflow: \"ellipsis\",\n cursor: \"default\",\n flexShrink: 0,\n boxSizing: \"border-box\",\n color: \"#1f2937\",\n },\n cellActive: {\n outline: \"2px solid #2563eb\",\n outlineOffset: -2,\n backgroundColor: \"#e8f1ff\",\n zIndex: 1,\n },\n cellSkeleton: {\n width: \"60%\",\n height: 8,\n borderRadius: 3,\n background:\n \"linear-gradient(90deg, #e6ebf2 25%, #f1f4f8 50%, #e6ebf2 75%)\",\n backgroundSize: \"200% 100%\",\n animation: \"parqui-shimmer 1.5s ease-in-out infinite\",\n opacity: 0.7,\n },\n};\n","import { useEffect, useMemo, useCallback, useRef } from \"react\";\nimport type { GroupNode, ParquetRow } from \"@parqui/core\";\nimport type { ColumnDef, DragState, ResizeState } from \"../hooks/useColumnManager.js\";\nimport type { VirtualScroll } from \"../hooks/useVirtualScroll.js\";\nimport { HEADER_HEIGHT } from \"../hooks/useVirtualScroll.js\";\nimport type { CellPosition, KeyboardNavigation } from \"../hooks/useKeyboardNavigation.js\";\nimport { ColumnHeader, ColumnDropEndZone } from \"./ColumnHeader.js\";\nimport { ParquiLogo } from \"./ParquiLogo.js\";\nimport { VirtualRow } from \"./VirtualRow.js\";\nimport { GroupHeaderRow } from \"./GroupHeaderRow.js\";\nimport { s } from \"../styles.js\";\n\n// ── Flat list types for grouped view ──\n\ntype FlatItem =\n | { type: \"header\"; groupIndex: number }\n | { type: \"row\"; displayIndex: number };\n\nfunction buildFlatItems(groups: GroupNode[]): FlatItem[] {\n const items: FlatItem[] = [];\n for (let gi = 0; gi < groups.length; gi++) {\n items.push({ type: \"header\", groupIndex: gi });\n if (groups[gi].expanded) {\n for (const displayIdx of groups[gi].rowIndices) {\n items.push({ type: \"row\", displayIndex: displayIdx });\n }\n }\n }\n return items;\n}\n\n// ── Props ──\n\nexport interface DataGridProps {\n // Virtual scroll\n vScroll: VirtualScroll;\n scrollRowCount: number;\n\n // Columns\n visibleColumns: ColumnDef[];\n totalColWidth: number;\n rowNumWidth: number;\n\n // Data\n getRow: (displayIndex: number) => ParquetRow | undefined;\n ensureRange: (start: number, end: number) => void;\n ensureIndices: (displayIndices: number[]) => void;\n renderTick: number;\n\n // Pipeline\n groups: GroupNode[];\n isGrouped: boolean;\n computing: boolean;\n toggleGroupExpanded: (index: number) => void;\n\n // Column management\n dragState: DragState;\n resizeState: ResizeState;\n onDragStart: (key: string) => void;\n onDragOver: (overKey: string, mouseXInColumn: number, columnWidth: number) => void;\n onDragOverEnd: () => void;\n onDragEnd: () => void;\n onResizeStart: (key: string, clientX: number) => void;\n onUpdateResize: (clientX: number) => void;\n onEndResize: () => void;\n\n // Sort & filter display\n getSortDirection: (column: string) => import(\"@parqui/core\").SortDirection | null;\n getSortPriority: (column: string) => number | null;\n getFilter: (column: string) => import(\"@parqui/core\").FilterDef | undefined;\n isColumnGrouped: (column: string) => boolean;\n onSortClick: (column: string, multi: boolean) => void;\n onContextMenu: (column: string, x: number, y: number) => void;\n\n // Keyboard\n keyboard: KeyboardNavigation;\n\n // Search (highlighting only)\n searchText?: string;\n}\n\nexport function DataGrid({\n vScroll,\n scrollRowCount,\n visibleColumns,\n totalColWidth,\n rowNumWidth,\n getRow,\n ensureRange,\n ensureIndices,\n renderTick,\n groups,\n isGrouped,\n computing,\n toggleGroupExpanded,\n dragState,\n resizeState,\n onDragStart,\n onDragOver,\n onDragOverEnd,\n onDragEnd,\n onResizeStart,\n onUpdateResize,\n onEndResize,\n getSortDirection,\n getSortPriority,\n getFilter,\n isColumnGrouped,\n onSortClick,\n onContextMenu,\n keyboard,\n searchText,\n}: DataGridProps) {\n // ── Grouped view: flat item list ──\n const flatItems = useMemo(() => {\n if (!isGrouped) return null;\n return buildFlatItems(groups);\n }, [isGrouped, groups]);\n\n // ── Load visible rows ──\n useEffect(() => {\n if (scrollRowCount === 0 || computing) return;\n\n if (flatItems) {\n const displayIndices: number[] = [];\n for (let i = vScroll.startIndex; i < vScroll.endIndex && i < flatItems.length; i++) {\n const item = flatItems[i];\n if (item.type === \"row\") displayIndices.push(item.displayIndex);\n }\n if (displayIndices.length > 0) ensureIndices(displayIndices);\n } else {\n ensureRange(vScroll.startIndex, vScroll.endIndex);\n }\n }, [vScroll.startIndex, vScroll.endIndex, scrollRowCount, renderTick, flatItems, computing, ensureRange, ensureIndices]);\n\n // ── Global mousemove/mouseup for column resizing ──\n useEffect(() => {\n if (!resizeState.columnKey) return;\n const handleMouseMove = (e: MouseEvent) => onUpdateResize(e.clientX);\n const handleMouseUp = () => onEndResize();\n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseup\", handleMouseUp);\n return () => {\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [resizeState.columnKey, onUpdateResize, onEndResize]);\n\n const totalWidth = totalColWidth + rowNumWidth;\n\n return (\n <div\n ref={vScroll.scrollRef}\n onScroll={vScroll.onScroll}\n style={s.scrollContainer}\n className=\"parqui-grid-scrollbar\"\n >\n {/* Header row */}\n <div\n style={{\n ...s.headerRow,\n width: totalWidth,\n minWidth: \"100%\",\n }}\n >\n <div\n style={{\n ...s.rowNumHeader,\n width: rowNumWidth,\n minWidth: rowNumWidth,\n height: HEADER_HEIGHT,\n }}\n >\n <ParquiLogo size={18} color=\"#64748b\" />\n </div>\n {visibleColumns.map((col, idx) => (\n <ColumnHeader\n key={col.key}\n column={col}\n visibleIndex={idx}\n dragState={dragState}\n sortDirection={getSortDirection(col.key)}\n sortPriority={getSortPriority(col.key)}\n hasFilter={!!getFilter(col.key)}\n isGrouped={isColumnGrouped(col.key)}\n onDragStart={onDragStart}\n onDragOver={onDragOver}\n onDragEnd={onDragEnd}\n onResizeStart={onResizeStart}\n onSortClick={onSortClick}\n onContextMenu={onContextMenu}\n />\n ))}\n <ColumnDropEndZone\n dragState={dragState}\n totalColumns={visibleColumns.length}\n onDragOverEnd={onDragOverEnd}\n onDragEnd={onDragEnd}\n />\n </div>\n\n {/* Virtual body */}\n <div\n style={{\n height: vScroll.totalHeight,\n position: \"relative\",\n width: totalWidth,\n minWidth: \"100%\",\n }}\n >\n <div\n style={{\n position: \"absolute\",\n top: vScroll.offsetY,\n left: 0,\n right: 0,\n }}\n >\n {flatItems\n ? renderFlatItems(\n flatItems, groups, vScroll.startIndex, vScroll.endIndex,\n visibleColumns, getRow, rowNumWidth,\n keyboard.activeCell, keyboard.handleCellClick,\n toggleGroupExpanded, totalWidth, searchText,\n )\n : renderRows(\n vScroll.startIndex, vScroll.endIndex,\n visibleColumns, getRow, rowNumWidth,\n keyboard.activeCell, keyboard.handleCellClick,\n searchText,\n )\n }\n </div>\n </div>\n </div>\n );\n}\n\n// ── Row rendering (non-grouped) ──\n\nfunction renderRows(\n start: number,\n end: number,\n columns: ColumnDef[],\n getRow: (index: number) => Record<string, unknown> | undefined,\n rowNumWidth: number,\n activeCell: CellPosition | null,\n onCellClick: (row: number, col: number) => void,\n searchText?: string,\n) {\n const rows: React.ReactNode[] = [];\n for (let i = start; i < end; i++) {\n rows.push(\n <VirtualRow\n key={i}\n flatIndex={i}\n displayIndex={i}\n columns={columns}\n row={getRow(i)}\n rowNumWidth={rowNumWidth}\n isActiveRow={activeCell?.row === i}\n activeCol={activeCell?.row === i ? activeCell.col : -1}\n onCellClick={onCellClick}\n searchText={searchText}\n />,\n );\n }\n return rows;\n}\n\n// ── Row rendering (grouped — flat list) ──\n\nfunction renderFlatItems(\n flatItems: FlatItem[],\n groups: GroupNode[],\n start: number,\n end: number,\n columns: ColumnDef[],\n getRow: (index: number) => Record<string, unknown> | undefined,\n rowNumWidth: number,\n activeCell: CellPosition | null,\n onCellClick: (row: number, col: number) => void,\n onToggleGroup: (groupIndex: number) => void,\n totalWidth: number,\n searchText?: string,\n) {\n const items: React.ReactNode[] = [];\n for (let i = start; i < end && i < flatItems.length; i++) {\n const item = flatItems[i];\n if (item.type === \"header\") {\n const group = groups[item.groupIndex];\n items.push(\n <GroupHeaderRow\n key={`gh-${item.groupIndex}`}\n group={group}\n groupIndex={item.groupIndex}\n onToggle={onToggleGroup}\n totalWidth={totalWidth}\n />,\n );\n } else {\n items.push(\n <VirtualRow\n key={`r-${item.displayIndex}`}\n flatIndex={i}\n displayIndex={item.displayIndex}\n columns={columns}\n row={getRow(item.displayIndex)}\n rowNumWidth={rowNumWidth}\n isActiveRow={activeCell?.row === i}\n activeCol={activeCell?.row === i ? activeCell.col : -1}\n onCellClick={onCellClick}\n searchText={searchText}\n />,\n );\n }\n }\n return items;\n}\n","import { useCallback, useRef } from \"react\";\nimport type { ColumnDef, DragState } from \"../hooks/useColumnManager.js\";\nimport type { SortDirection } from \"@parqui/core\";\nimport { HEADER_HEIGHT } from \"../hooks/useVirtualScroll.js\";\n\ninterface ColumnHeaderProps {\n column: ColumnDef;\n /** Index of this column among visible columns */\n visibleIndex: number;\n dragState: DragState;\n /** Current sort direction */\n sortDirection: SortDirection | null;\n /** Sort priority (1-based) for multi-column sort, null if not sorted */\n sortPriority: number | null;\n /** Whether a filter is active on this column */\n hasFilter: boolean;\n /** Whether this column is grouped */\n isGrouped: boolean;\n onDragStart: (key: string) => void;\n onDragOver: (\n overKey: string,\n mouseXInColumn: number,\n columnWidth: number,\n ) => void;\n onDragEnd: () => void;\n onResizeStart: (key: string, clientX: number) => void;\n /** Left-click on header — toggle sort */\n onSortClick: (column: string, multi: boolean) => void;\n /** Right-click on header — open context menu */\n onContextMenu: (column: string, x: number, y: number) => void;\n}\n\nexport function ColumnHeader({\n column,\n visibleIndex,\n dragState,\n sortDirection,\n sortPriority,\n hasFilter,\n isGrouped,\n onDragStart,\n onDragOver,\n onDragEnd,\n onResizeStart,\n onSortClick,\n onContextMenu,\n}: ColumnHeaderProps) {\n const cellRef = useRef<HTMLDivElement>(null);\n\n const isDragging = dragState.dragKey === column.key;\n\n const showLeftIndicator =\n dragState.dragKey !== null &&\n dragState.dragKey !== column.key &&\n dragState.insertIndex === visibleIndex;\n\n const showRightIndicator =\n dragState.dragKey !== null &&\n dragState.dragKey !== column.key &&\n dragState.insertIndex === visibleIndex + 1;\n\n const handleDragStart = useCallback(\n (e: React.DragEvent) => {\n e.dataTransfer.effectAllowed = \"move\";\n e.dataTransfer.setData(\"text/plain\", column.key);\n onDragStart(column.key);\n },\n [column.key, onDragStart],\n );\n\n const handleDragOver = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = \"move\";\n const rect = cellRef.current?.getBoundingClientRect();\n if (rect) {\n const mouseXInColumn = e.clientX - rect.left;\n onDragOver(column.key, mouseXInColumn, rect.width);\n }\n },\n [column.key, onDragOver],\n );\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n onDragEnd();\n },\n [onDragEnd],\n );\n\n const handleNativeDragEnd = useCallback(() => {\n onDragEnd();\n }, [onDragEnd]);\n\n const handleResizeMouseDown = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onResizeStart(column.key, e.clientX);\n },\n [column.key, onResizeStart],\n );\n\n const handleClick = useCallback(\n (e: React.MouseEvent) => {\n // Don't trigger sort if user is resizing\n if ((e.target as HTMLElement).dataset.resize) return;\n onSortClick(column.key, e.ctrlKey || e.metaKey);\n },\n [column.key, onSortClick],\n );\n\n const handleContextMenu = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n onContextMenu(column.key, e.clientX, e.clientY);\n },\n [column.key, onContextMenu],\n );\n\n return (\n <div\n ref={cellRef}\n className=\"parqui-grid-header-cell\"\n draggable\n onDragStart={handleDragStart}\n onDragOver={handleDragOver}\n onDrop={handleDrop}\n onDragEnd={handleNativeDragEnd}\n onClick={handleClick}\n onContextMenu={handleContextMenu}\n style={{\n ...headerStyles.cell,\n width: column.width,\n minWidth: column.width,\n maxWidth: column.width,\n height: HEADER_HEIGHT,\n opacity: isDragging ? 0.4 : 1,\n }}\n title={column.key}\n >\n {/* Left insertion indicator */}\n {showLeftIndicator && <div style={headerStyles.indicatorLeft} />}\n {/* Right insertion indicator */}\n {showRightIndicator && <div style={headerStyles.indicatorRight} />}\n\n {/* Column label + indicators */}\n <span style={headerStyles.label} className=\"parqui-grid-header-label\">{column.key}</span>\n\n {/* Status indicators area */}\n <span style={headerStyles.indicators}>\n {/* Filter dot */}\n {hasFilter && <span style={headerStyles.filterDot} />}\n\n {/* Group icon */}\n {isGrouped && <span style={headerStyles.groupIcon}>▦</span>}\n\n {/* Sort arrow */}\n {sortDirection && (\n <span style={headerStyles.sortArrow}>\n {sortDirection === \"asc\" ? \"↑\" : \"↓\"}\n {sortPriority !== null && sortPriority > 1 && (\n <span style={headerStyles.sortPriority}>{sortPriority}</span>\n )}\n </span>\n )}\n </span>\n\n {/* Resize handle */}\n <div\n data-resize=\"true\"\n onMouseDown={handleResizeMouseDown}\n style={headerStyles.resizeHandle}\n role=\"separator\"\n aria-orientation=\"vertical\"\n />\n </div>\n );\n}\n\n/**\n * A trailing drop zone rendered after the last column header.\n */\nexport function ColumnDropEndZone({\n dragState,\n totalColumns,\n onDragOverEnd,\n onDragEnd,\n}: {\n dragState: DragState;\n totalColumns: number;\n onDragOverEnd: () => void;\n onDragEnd: () => void;\n}) {\n const showIndicator =\n dragState.dragKey !== null && dragState.insertIndex === totalColumns;\n\n const handleDragOver = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = \"move\";\n onDragOverEnd();\n },\n [onDragOverEnd],\n );\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n onDragEnd();\n },\n [onDragEnd],\n );\n\n if (!dragState.dragKey) return null;\n\n return (\n <div\n onDragOver={handleDragOver}\n onDrop={handleDrop}\n style={headerStyles.endZone}\n >\n {showIndicator && <div style={headerStyles.indicatorLeft} />}\n </div>\n );\n}\n\nconst headerStyles: Record<string, React.CSSProperties> = {\n cell: {\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\",\n padding: \"0 12px\",\n backgroundColor: \"#ffffff\",\n borderBottom: \"1px solid #d8e0ea\",\n borderRight: \"1px solid #d8e0ea\",\n fontWeight: 600,\n fontSize: 13,\n color: \"#334155\",\n cursor: \"pointer\",\n userSelect: \"none\",\n overflow: \"hidden\",\n flexShrink: 0,\n boxSizing: \"border-box\",\n gap: 4,\n },\n label: {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n flex: 1,\n color: \"#334155\",\n },\n indicators: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 4,\n flexShrink: 0,\n },\n sortArrow: {\n display: \"flex\",\n alignItems: \"center\",\n fontSize: 12,\n color: \"#2563eb\",\n fontWeight: 700,\n },\n sortPriority: {\n fontSize: 9,\n marginLeft: 1,\n },\n filterDot: {\n width: 5,\n height: 5,\n borderRadius: \"50%\",\n backgroundColor: \"#0ea5e9\",\n },\n groupIcon: {\n fontSize: 11,\n color: \"#2563eb\",\n },\n resizeHandle: {\n position: \"absolute\",\n right: 0,\n top: 0,\n bottom: 0,\n width: 6,\n cursor: \"col-resize\",\n zIndex: 2,\n backgroundColor: \"transparent\",\n },\n indicatorLeft: {\n position: \"absolute\",\n left: 0,\n top: 0,\n bottom: 0,\n width: 3,\n backgroundColor: \"#2563eb\",\n zIndex: 3,\n borderRadius: \"2px 0 0 2px\",\n },\n indicatorRight: {\n position: \"absolute\",\n right: 0,\n top: 0,\n bottom: 0,\n width: 3,\n backgroundColor: \"#2563eb\",\n zIndex: 3,\n borderRadius: \"0 2px 2px 0\",\n },\n endZone: {\n position: \"relative\",\n width: 32,\n minWidth: 32,\n flexShrink: 0,\n backgroundColor: \"#ffffff\",\n borderBottom: \"1px solid #d8e0ea\",\n },\n};\n","import { useId } from \"react\";\n\nexport interface ParquiLogoProps {\n size?: number;\n color?: string;\n style?: React.CSSProperties;\n}\n\nexport function ParquiLogo({\n size = 28,\n color = \"#50ABF1\",\n style,\n}: ParquiLogoProps) {\n const clipId = useId();\n const r = (size / 28) * 3;\n\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 28 28\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ flexShrink: 0, ...style }}\n >\n <defs>\n <clipPath id={clipId}>\n <rect width=\"28\" height=\"28\" rx={r} />\n </clipPath>\n </defs>\n <g clipPath={`url(#${clipId})`}>\n <g transform=\"rotate(45 14 14)\">\n <rect x=\"-20\" y=\"-5\" width=\"68\" height=\"10\" fill={color} />\n <rect x=\"-20\" y=\"9\" width=\"32\" height=\"10\" fill={color} />\n <rect x=\"16\" y=\"9\" width=\"32\" height=\"10\" fill={color} />\n <rect x=\"-20\" y=\"23\" width=\"68\" height=\"10\" fill={color} />\n </g>\n </g>\n </svg>\n );\n}\n\n","import type { ColumnDef } from \"../hooks/useColumnManager.js\";\nimport { ROW_HEIGHT } from \"../hooks/useVirtualScroll.js\";\nimport { highlightCell } from \"../utils/formatting.js\";\nimport { s } from \"../styles.js\";\n\ninterface VirtualRowProps {\n flatIndex: number;\n displayIndex: number;\n columns: ColumnDef[];\n row: Record<string, unknown> | undefined;\n rowNumWidth: number;\n isActiveRow: boolean;\n activeCol: number;\n onCellClick: (row: number, col: number) => void;\n searchText?: string;\n}\n\nexport function VirtualRow({\n flatIndex,\n displayIndex,\n columns,\n row,\n rowNumWidth,\n isActiveRow,\n activeCol,\n onCellClick,\n searchText,\n}: VirtualRowProps) {\n const isLoading = !row;\n\n return (\n <div\n className={`parqui-grid-row${isActiveRow ? \" parqui-grid-row-selected\" : \"\"}`}\n style={{ ...s.row, height: ROW_HEIGHT }}\n role=\"row\"\n aria-rowindex={displayIndex + 1}\n >\n <div\n className=\"parqui-grid-row-num\"\n style={{\n ...s.rowNum,\n width: rowNumWidth,\n minWidth: rowNumWidth,\n height: ROW_HEIGHT,\n }}\n >\n {displayIndex + 1}\n </div>\n {columns.map((col, colIdx) => {\n const isActive = isActiveRow && activeCol === colIdx;\n return (\n <div\n key={col.key}\n onClick={() => onCellClick(flatIndex, colIdx)}\n className=\"parqui-grid-cell\"\n style={{\n ...s.cell,\n width: col.width,\n minWidth: col.width,\n maxWidth: col.width,\n height: ROW_HEIGHT,\n ...(isActive ? s.cellActive : undefined),\n }}\n role=\"gridcell\"\n aria-colindex={colIdx + 1}\n aria-selected={isActive}\n >\n {isLoading ? (\n <div style={s.cellSkeleton} />\n ) : (\n highlightCell(row[col.key], searchText)\n )}\n </div>\n );\n })}\n </div>\n );\n}\n","import type { GroupNode } from \"@parqui/core\";\nimport { ROW_HEIGHT } from \"../hooks/useVirtualScroll.js\";\nimport { s } from \"../styles.js\";\n\nexport function GroupHeaderRow({\n group,\n groupIndex,\n onToggle,\n totalWidth,\n}: {\n group: GroupNode;\n groupIndex: number;\n onToggle: (index: number) => void;\n totalWidth: number;\n}) {\n return (\n <div\n className=\"parqui-grid-group-header\"\n style={{ ...s.groupHeader, height: ROW_HEIGHT, width: totalWidth }}\n onClick={() => onToggle(groupIndex)}\n role=\"row\"\n >\n <span style={s.groupChevron}>\n {group.expanded ? \"\\u25BE\" : \"\\u25B8\"}\n </span>\n <span style={s.groupLabel}>{group.label}</span>\n <span style={s.groupCount}>\n ({group.count.toLocaleString()})\n </span>\n </div>\n );\n}\n","import { useState, useEffect, useCallback, useRef } from \"react\";\nimport type { SortDirection, FilterDef } from \"@parqui/core\";\n\nexport interface ColumnContextMenuProps {\n /** Column name */\n column: string;\n /** Screen position */\n x: number;\n y: number;\n /** Current sort direction for this column */\n sortDirection: SortDirection | null;\n /** Current sort priority (1-based), or null */\n sortPriority: number | null;\n /** Current filter for this column */\n activeFilter: FilterDef | undefined;\n /** Whether this column is grouped */\n isGrouped: boolean;\n /** Callback to close the menu */\n onClose: () => void;\n /** Sort actions */\n onSortAsc: () => void;\n onSortDesc: () => void;\n onSortClear: () => void;\n /** Filter actions */\n onFilterSet: (filter: FilterDef) => void;\n onFilterClear: () => void;\n /** Group actions */\n onGroupToggle: () => void;\n /** Async loader for unique values */\n loadUniqueValues: () => Promise<unknown[]>;\n}\n\nexport function ColumnContextMenu({\n column,\n x,\n y,\n sortDirection,\n sortPriority,\n activeFilter,\n isGrouped,\n onClose,\n onSortAsc,\n onSortDesc,\n onSortClear,\n onFilterSet,\n onFilterClear,\n onGroupToggle,\n loadUniqueValues,\n}: ColumnContextMenuProps) {\n const [showFilterPanel, setShowFilterPanel] = useState(false);\n const [uniqueValues, setUniqueValues] = useState<unknown[] | null>(null);\n const [selectedValues, setSelectedValues] = useState<Set<string>>(new Set());\n const [filterSearch, setFilterSearch] = useState(\"\");\n const [loadingValues, setLoadingValues] = useState(false);\n const menuRef = useRef<HTMLDivElement>(null);\n\n // Close on click outside\n useEffect(() => {\n const handle = (e: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(e.target as Node)) {\n onClose();\n }\n };\n document.addEventListener(\"mousedown\", handle);\n return () => document.removeEventListener(\"mousedown\", handle);\n }, [onClose]);\n\n // Close on Escape\n useEffect(() => {\n const handle = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", handle);\n return () => document.removeEventListener(\"keydown\", handle);\n }, [onClose]);\n\n // Load unique values when filter panel opens\n useEffect(() => {\n if (showFilterPanel && uniqueValues === null && !loadingValues) {\n setLoadingValues(true);\n loadUniqueValues().then((values) => {\n setUniqueValues(values);\n // Pre-select all values if \"in\" filter is active\n if (activeFilter?.operator === \"in\" && Array.isArray(activeFilter.value)) {\n setSelectedValues(new Set(activeFilter.value.map(String)));\n } else {\n setSelectedValues(new Set(values.map((v) => String(v))));\n }\n setLoadingValues(false);\n });\n }\n }, [showFilterPanel, uniqueValues, loadingValues, loadUniqueValues, activeFilter]);\n\n const handleFilterApply = useCallback(() => {\n if (!uniqueValues) return;\n const allSelected = selectedValues.size === uniqueValues.length;\n if (allSelected) {\n onFilterClear();\n } else {\n onFilterSet({\n column,\n operator: \"in\",\n value: [...selectedValues],\n });\n }\n onClose();\n }, [column, selectedValues, uniqueValues, onFilterSet, onFilterClear, onClose]);\n\n const toggleValue = useCallback((val: string) => {\n setSelectedValues((prev) => {\n const next = new Set(prev);\n if (next.has(val)) next.delete(val);\n else next.add(val);\n return next;\n });\n }, []);\n\n const selectAll = useCallback(() => {\n if (uniqueValues) {\n setSelectedValues(new Set(uniqueValues.map((v) => String(v))));\n }\n }, [uniqueValues]);\n\n const selectNone = useCallback(() => {\n setSelectedValues(new Set());\n }, []);\n\n // Adjust position so menu doesn't go off screen\n const adjustedX = Math.min(x, window.innerWidth - 260);\n const adjustedY = Math.min(y, window.innerHeight - 400);\n\n const filteredUniqueValues = uniqueValues?.filter((v) =>\n filterSearch\n ? String(v).toLowerCase().includes(filterSearch.toLowerCase())\n : true,\n );\n\n return (\n <div\n ref={menuRef}\n style={{ ...menuStyles.overlay, left: adjustedX, top: adjustedY }}\n onContextMenu={(e) => e.preventDefault()}\n >\n <div style={menuStyles.container}>\n {/* ── Sort section ── */}\n <div style={menuStyles.sectionLabel}>Sort</div>\n <MenuItem\n active={sortDirection === \"asc\"}\n onClick={() => { onSortAsc(); onClose(); }}\n >\n <span style={menuStyles.itemIcon}>↑</span>\n Sort ascending\n {sortPriority && sortPriority > 0 && (\n <span style={menuStyles.badge}>{sortPriority}</span>\n )}\n </MenuItem>\n <MenuItem\n active={sortDirection === \"desc\"}\n onClick={() => { onSortDesc(); onClose(); }}\n >\n <span style={menuStyles.itemIcon}>↓</span>\n Sort descending\n </MenuItem>\n {sortDirection && (\n <MenuItem\n onClick={() => { onSortClear(); onClose(); }}\n >\n <span style={menuStyles.itemIcon}>✕</span>\n Clear sort\n </MenuItem>\n )}\n\n <div style={menuStyles.divider} />\n\n {/* ── Filter section ── */}\n <div style={menuStyles.sectionLabel}>Filter</div>\n <MenuItem\n active={showFilterPanel}\n onClick={() => setShowFilterPanel(!showFilterPanel)}\n >\n <span style={menuStyles.itemIcon}>⊞</span>\n Filter by values...\n {activeFilter && <span style={menuStyles.activeDot} />}\n </MenuItem>\n {activeFilter && (\n <MenuItem\n onClick={() => { onFilterClear(); onClose(); }}\n >\n <span style={menuStyles.itemIcon}>✕</span>\n Clear filter\n </MenuItem>\n )}\n\n {showFilterPanel && (\n <div style={menuStyles.filterPanel}>\n <input\n type=\"text\"\n placeholder=\"Search values...\"\n value={filterSearch}\n onChange={(e) => setFilterSearch(e.target.value)}\n style={menuStyles.filterSearch}\n autoFocus\n />\n <div style={menuStyles.filterActions}>\n <button style={menuStyles.linkButton} onClick={selectAll}>\n Select all\n </button>\n <button style={menuStyles.linkButton} onClick={selectNone}>\n Select none\n </button>\n </div>\n <div style={menuStyles.filterList}>\n {loadingValues ? (\n <div style={menuStyles.filterLoading}>Loading values...</div>\n ) : (\n filteredUniqueValues?.map((val) => {\n const key = String(val);\n return (\n <label key={key} style={menuStyles.filterItem}>\n <input\n type=\"checkbox\"\n checked={selectedValues.has(key)}\n onChange={() => toggleValue(key)}\n style={menuStyles.checkbox}\n />\n <span style={menuStyles.filterValue}>\n {val === null || val === undefined\n ? \"(null)\"\n : String(val)}\n </span>\n </label>\n );\n })\n )}\n </div>\n <button style={menuStyles.applyButton} onClick={handleFilterApply}>\n Apply filter\n </button>\n </div>\n )}\n\n <div style={menuStyles.divider} />\n\n {/* ── Group section ── */}\n <div style={menuStyles.sectionLabel}>Group</div>\n <MenuItem\n active={isGrouped}\n onClick={() => { onGroupToggle(); onClose(); }}\n >\n <span style={menuStyles.itemIcon}>{isGrouped ? \"▤\" : \"▦\"}</span>\n {isGrouped ? \"Remove grouping\" : \"Group by this column\"}\n </MenuItem>\n </div>\n </div>\n );\n}\n\nfunction MenuItem({\n active,\n onClick,\n children,\n}: {\n active?: boolean;\n onClick: () => void;\n children: React.ReactNode;\n}) {\n const [isHovered, setIsHovered] = useState(false);\n\n return (\n <button\n style={{\n ...menuStyles.item,\n ...(active ? menuStyles.itemActive : {}),\n ...(!active && isHovered ? menuStyles.itemHover : {}),\n }}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n onClick={onClick}\n >\n {children}\n </button>\n );\n}\n\nconst menuStyles: Record<string, React.CSSProperties> = {\n overlay: {\n position: \"fixed\",\n zIndex: 10000,\n },\n container: {\n backgroundColor: \"#ffffff\",\n border: \"1px solid #d7e0ea\",\n borderRadius: 10,\n boxShadow: \"0 14px 28px rgba(15, 23, 42, 0.14), 0 3px 10px rgba(15, 23, 42, 0.08)\",\n minWidth: 230,\n maxWidth: 320,\n padding: \"6px 0\",\n fontFamily: \"'Plus Jakarta Sans', 'Inter', system-ui, sans-serif\",\n fontSize: 13,\n color: \"#1f2937\",\n },\n sectionLabel: {\n padding: \"8px 12px 3px\",\n fontSize: 11,\n fontWeight: 700,\n color: \"#6b7280\",\n textTransform: \"uppercase\",\n letterSpacing: \"0.06em\",\n },\n item: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n width: \"100%\",\n padding: \"8px 12px\",\n border: \"none\",\n background: \"none\",\n textAlign: \"left\",\n fontSize: 13,\n color: \"#334155\",\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n borderRadius: 7,\n margin: \"1px 6px\",\n transition: \"background-color 120ms ease, color 120ms ease\",\n },\n itemHover: {\n backgroundColor: \"#eef3f9\",\n color: \"#111827\",\n },\n itemActive: {\n backgroundColor: \"#e8f1ff\",\n color: \"#1d4ed8\",\n },\n itemIcon: {\n width: 16,\n textAlign: \"center\",\n flexShrink: 0,\n fontSize: 13,\n color: \"#64748b\",\n },\n badge: {\n marginLeft: \"auto\",\n backgroundColor: \"#eaf0f7\",\n color: \"#475569\",\n fontSize: 10,\n fontWeight: 700,\n padding: \"2px 6px\",\n borderRadius: 4,\n },\n activeDot: {\n marginLeft: \"auto\",\n width: 7,\n height: 7,\n borderRadius: \"50%\",\n backgroundColor: \"#2563eb\",\n },\n divider: {\n height: 1,\n backgroundColor: \"#e6ebf2\",\n margin: \"6px 0\",\n },\n filterPanel: {\n padding: \"6px 12px 10px\",\n },\n filterSearch: {\n width: \"100%\",\n padding: \"7px 9px\",\n border: \"1px solid #d1dbe7\",\n borderRadius: 7,\n fontSize: 12,\n fontFamily: \"inherit\",\n outline: \"none\",\n boxSizing: \"border-box\",\n backgroundColor: \"#ffffff\",\n color: \"#1f2937\",\n },\n filterActions: {\n display: \"flex\",\n gap: 12,\n padding: \"6px 0\",\n },\n linkButton: {\n background: \"none\",\n border: \"none\",\n color: \"#1d4ed8\",\n fontSize: 11,\n cursor: \"pointer\",\n padding: 0,\n fontFamily: \"inherit\",\n fontWeight: 600,\n },\n filterList: {\n maxHeight: 200,\n overflowY: \"auto\",\n border: \"1px solid #d8e0ea\",\n borderRadius: 7,\n marginBottom: 6,\n backgroundColor: \"#ffffff\",\n },\n filterLoading: {\n padding: 12,\n textAlign: \"center\",\n color: \"#6b7280\",\n fontSize: 12,\n },\n filterItem: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"4px 8px\",\n cursor: \"pointer\",\n fontSize: 12,\n color: \"#334155\",\n },\n checkbox: {\n margin: 0,\n flexShrink: 0,\n accentColor: \"#2563eb\",\n },\n filterValue: {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n },\n applyButton: {\n width: \"100%\",\n padding: \"8px 12px\",\n backgroundColor: \"#1d4ed8\",\n color: \"white\",\n border: \"1px solid #1e40af\",\n borderRadius: 7,\n fontSize: 12,\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n boxShadow: \"none\",\n },\n};\n","import { useState, useCallback, useRef } from \"react\";\n\nexport interface FileDropZoneProps {\n /** Called when a file is selected (via drop or file picker) */\n onFileSelect: (file: File) => void;\n /**\n * Custom open handler (e.g. Tauri native dialog).\n * When provided, the \"Select file\" button calls this instead of the\n * browser file picker. Drag-and-drop still uses onFileSelect.\n */\n onCustomOpen?: () => void;\n /** Accepted file extensions (default: [\".parquet\"]) */\n accept?: string[];\n /** Compact mode — renders as a small inline drop area (for use alongside viewer) */\n compact?: boolean;\n /** Additional CSS class name */\n className?: string;\n /** Custom label text */\n label?: string;\n /** Custom button text */\n buttonLabel?: string;\n}\n\nexport function FileDropZone({\n onFileSelect,\n onCustomOpen,\n accept = [\".parquet\"],\n compact = false,\n className,\n label,\n buttonLabel,\n}: FileDropZoneProps) {\n const [isDragOver, setIsDragOver] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const acceptString = accept.join(\",\");\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(false);\n\n const droppedFile = e.dataTransfer.files[0];\n if (droppedFile && accept.some((ext) => droppedFile.name.endsWith(ext))) {\n onFileSelect(droppedFile);\n }\n },\n [onFileSelect, accept],\n );\n\n const handleDragOver = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(true);\n }, []);\n\n const handleDragLeave = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(false);\n }, []);\n\n const handleFileInput = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const selectedFile = e.target.files?.[0];\n if (selectedFile) {\n onFileSelect(selectedFile);\n }\n // Reset input so the same file can be re-selected\n if (inputRef.current) {\n inputRef.current.value = \"\";\n }\n },\n [onFileSelect],\n );\n\n const handleClick = useCallback(() => {\n if (onCustomOpen) {\n onCustomOpen();\n } else {\n inputRef.current?.click();\n }\n }, [onCustomOpen]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleClick();\n }\n },\n [handleClick],\n );\n\n if (compact) {\n return (\n <div\n className={className}\n role=\"button\"\n tabIndex={0}\n aria-label={label ?? \"Drop a file here or click to select\"}\n onDrop={handleDrop}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n style={{\n ...compactStyles.zone,\n ...(isDragOver ? compactStyles.zoneDragOver : {}),\n }}\n >\n <span style={compactStyles.icon}>+</span>\n <span style={compactStyles.text}>\n {buttonLabel ?? \"Open file\"}\n </span>\n <input\n ref={inputRef}\n type=\"file\"\n accept={acceptString}\n onChange={handleFileInput}\n style={{ display: \"none\" }}\n tabIndex={-1}\n aria-hidden=\"true\"\n />\n </div>\n );\n }\n\n return (\n <div\n className={className}\n role=\"button\"\n tabIndex={0}\n aria-label={label ?? \"Drop a parquet file here or click to select\"}\n onDrop={handleDrop}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n style={{\n ...fullStyles.zone,\n ...(isDragOver ? fullStyles.zoneDragOver : {}),\n }}\n >\n <div style={fullStyles.iconCircle}>\n <svg\n width=\"32\"\n height=\"32\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n </div>\n <div style={fullStyles.textGroup}>\n <p style={fullStyles.title}>\n {label ?? \"Open a Parquet file\"}\n </p>\n <p style={fullStyles.hint}>\n Drag & drop a .parquet file here, or click to browse\n </p>\n </div>\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n handleClick();\n }}\n style={fullStyles.button}\n >\n {buttonLabel ?? \"Choose file\"}\n </button>\n <p style={fullStyles.supportedLabel}>.parquet</p>\n <input\n ref={inputRef}\n type=\"file\"\n accept={acceptString}\n onChange={handleFileInput}\n style={{ display: \"none\" }}\n tabIndex={-1}\n aria-hidden=\"true\"\n />\n </div>\n );\n}\n\nconst fullStyles: Record<string, React.CSSProperties> = {\n zone: {\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 20,\n padding: \"56px 48px\",\n border: \"2px dashed #b9c6d7\",\n borderRadius: 14,\n cursor: \"pointer\",\n transition: \"all 0.2s ease\",\n backgroundColor: \"#ffffff\",\n fontFamily: \"'Plus Jakarta Sans', 'Inter', system-ui, sans-serif\",\n outline: \"none\",\n maxWidth: 420,\n width: \"100%\",\n },\n zoneDragOver: {\n borderColor: \"#2563eb\",\n backgroundColor: \"#f5f9ff\",\n transform: \"scale(1.01)\",\n },\n iconCircle: {\n width: 72,\n height: 72,\n borderRadius: \"50%\",\n backgroundColor: \"#edf2f7\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#64748b\",\n transition: \"background-color 0.2s, color 0.2s\",\n },\n textGroup: {\n textAlign: \"center\" as const,\n },\n title: {\n fontSize: 17,\n fontWeight: 700,\n color: \"#111827\",\n margin: 0,\n },\n hint: {\n fontSize: 13,\n color: \"#64748b\",\n margin: \"6px 0 0\",\n },\n button: {\n padding: \"10px 32px\",\n backgroundColor: \"#1d4ed8\",\n color: \"#ffffff\",\n border: \"1px solid #1e40af\",\n borderRadius: 8,\n fontSize: 14,\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"'Plus Jakarta Sans', 'Inter', system-ui, sans-serif\",\n transition: \"background-color 0.15s\",\n boxShadow: \"none\",\n },\n supportedLabel: {\n fontSize: 11,\n color: \"#94a3b8\",\n margin: 0,\n letterSpacing: \"0.03em\",\n },\n};\n\nconst compactStyles: Record<string, React.CSSProperties> = {\n zone: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n padding: \"6px 14px\",\n border: \"1px dashed #c2cfde\",\n borderRadius: 8,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n backgroundColor: \"#ffffff\",\n fontFamily: \"'Plus Jakarta Sans', 'Inter', system-ui, sans-serif\",\n fontSize: 13,\n color: \"#64748b\",\n whiteSpace: \"nowrap\",\n outline: \"none\",\n },\n zoneDragOver: {\n borderColor: \"#2563eb\",\n backgroundColor: \"#f5f9ff\",\n color: \"#1d4ed8\",\n },\n icon: {\n fontSize: 16,\n fontWeight: 700,\n lineHeight: 1,\n },\n text: {\n lineHeight: 1,\n },\n};\n"],"mappings":"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","names":["import_react","import_react","import_core","import_react","import_react","import_core","s","import_react","import_react","import_react","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","rowNumWidth"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/Parkui.tsx","../src/hooks/useContainerSize.ts","../src/hooks/useParquetData.ts","../src/hooks/useSourceLoader.ts","../src/source.ts","../src/hooks/useChunkLoader.ts","../src/hooks/useVirtualScroll.ts","../src/hooks/useColumnManager.ts","../src/hooks/useKeyboardNavigation.ts","../src/hooks/useSearch.ts","../src/components/Toolbar.tsx","../src/components/Icons.tsx","../src/components/PipelineChip.tsx","../src/utils/formatting.ts","../src/styles.ts","../src/components/DataGrid.tsx","../src/components/ColumnHeader.tsx","../src/components/ParquiLogo.tsx","../src/components/VirtualRow.tsx","../src/components/GroupHeaderRow.tsx","../src/components/ColumnContextMenu.tsx","../src/FileDropZone.tsx"],"sourcesContent":["export { Parkui } from \"./Parkui.js\";\nexport type { ParkuiProps } from \"./Parkui.js\";\nexport type { ParquetInputSource } from \"./source.js\";\n\nexport { FileDropZone } from \"./FileDropZone.js\";\nexport type { FileDropZoneProps } from \"./FileDropZone.js\";\n\nexport { ParquiLogo } from \"./components/ParquiLogo.js\";\nexport type { ParquiLogoProps } from \"./components/ParquiLogo.js\";\n\n// Hooks (for advanced usage / custom wrappers)\nexport { useContainerSize } from \"./hooks/useContainerSize.js\";\nexport { useParquetData } from \"./hooks/useParquetData.js\";\nexport { useVirtualScroll, ROW_HEIGHT, HEADER_HEIGHT } from \"./hooks/useVirtualScroll.js\";\nexport { useColumnManager } from \"./hooks/useColumnManager.js\";\nexport { useKeyboardNavigation } from \"./hooks/useKeyboardNavigation.js\";\nexport { useSearch } from \"./hooks/useSearch.js\";\nexport { useSourceLoader } from \"./hooks/useSourceLoader.js\";\nexport { useChunkLoader } from \"./hooks/useChunkLoader.js\";\n\nexport type {\n ParquetColumn,\n ParquetMetadata,\n ParquetRow,\n ParquetData,\n ParquetSource,\n ReadOptions,\n} from \"@parqui/core\";\n","import {\n useState,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n} from \"react\";\nimport { useContainerSize } from \"./hooks/useContainerSize.js\";\nimport { useParquetData } from \"./hooks/useParquetData.js\";\nimport { useVirtualScroll } from \"./hooks/useVirtualScroll.js\";\nimport { useColumnManager } from \"./hooks/useColumnManager.js\";\nimport { useKeyboardNavigation } from \"./hooks/useKeyboardNavigation.js\";\nimport { useSearch } from \"./hooks/useSearch.js\";\nimport { Toolbar } from \"./components/Toolbar.js\";\nimport { DataGrid } from \"./components/DataGrid.js\";\nimport { ColumnContextMenu } from \"./components/ColumnContextMenu.js\";\nimport { FileDropZone } from \"./FileDropZone.js\";\nimport type { ParquetMetadata, ParquetSource } from \"@parqui/core\";\nimport { sourceToDisplayName, type ParquetInputSource } from \"./source.js\";\nimport { s, PARKUI_CSS } from \"./styles.js\";\n\n// ── Props ──\n\nexport interface ParkuiProps {\n source?: ParquetInputSource;\n columns?: string[];\n onMetadataLoad?: (metadata: ParquetMetadata) => void;\n allowOpen?: boolean;\n onRequestOpen?: () => Promise<{ source: ParquetSource; name: string } | null>;\n showToolbar?: boolean;\n className?: string;\n style?: React.CSSProperties;\n}\n\n// ── Context menu state ──\n\ninterface ContextMenuState {\n column: string;\n x: number;\n y: number;\n}\n\n// ── Main Component ──\n\nexport function Parkui({\n source,\n columns,\n onMetadataLoad,\n allowOpen = true,\n onRequestOpen,\n showToolbar = true,\n className,\n style,\n}: ParkuiProps) {\n // ── File management ──\n const [currentSource, setCurrentSource] = useState<ParquetInputSource | undefined>(source);\n const [fileName, setFileName] = useState<string>(\n source ? sourceToDisplayName(source) : \"\",\n );\n\n useEffect(() => {\n setCurrentSource(source);\n setFileName(source ? sourceToDisplayName(source) : \"\");\n }, [source]);\n\n const hasSource = !!currentSource;\n const search = useSearch();\n\n const handleFileSelect = useCallback((newFile: File) => {\n search.resetSearch();\n setCurrentSource(newFile);\n setFileName(newFile.name);\n }, [search]);\n\n const handleClose = useCallback(() => {\n setCurrentSource(undefined);\n setFileName(\"\");\n search.resetSearch();\n }, [search]);\n\n const handleCustomOpen = useCallback(async () => {\n if (!onRequestOpen) return;\n const result = await onRequestOpen();\n if (result) {\n search.resetSearch();\n setCurrentSource(result.source);\n setFileName(result.name);\n }\n }, [onRequestOpen, search]);\n\n // ── Data hooks ──\n const { containerRef, size } = useContainerSize();\n const pq = useParquetData(currentSource, columns, search.debouncedSearch);\n\n // Notify parent when metadata loads\n const onMetadataLoadRef = useRef(onMetadataLoad);\n onMetadataLoadRef.current = onMetadataLoad;\n useEffect(() => {\n if (pq.metadata) onMetadataLoadRef.current?.(pq.metadata);\n }, [pq.metadata]);\n\n const columnNames = useMemo(() => {\n if (columns) return columns;\n return pq.metadata?.columns.map((c) => c.name) ?? [];\n }, [columns, pq.metadata]);\n\n const colManager = useColumnManager(columnNames);\n\n // ── Context menu ──\n const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);\n\n // ── Grouped mode ──\n const isGrouped = pq.pipeline.groups.length > 0 && pq.groups.length > 0;\n\n // ── Scroll row count (groups flatten into flat items) ──\n const scrollRowCount = useMemo(() => {\n if (!isGrouped) return pq.filteredRowCount;\n let count = 0;\n for (const g of pq.groups) {\n count += 1; // header\n if (g.expanded) count += g.rowIndices.length;\n }\n return count;\n }, [isGrouped, pq.groups, pq.filteredRowCount]);\n\n const vScroll = useVirtualScroll(size.height, scrollRowCount, pq.metadata);\n\n // ── Keyboard navigation ──\n const isNavigable = useMemo(() => {\n if (!isGrouped) return undefined;\n // In grouped mode, build flat items to determine which rows are navigable\n return (flatIdx: number) => {\n let pos = 0;\n for (const g of pq.groups) {\n if (pos === flatIdx) return false; // header\n pos++;\n if (g.expanded) {\n const end = pos + g.rowIndices.length;\n if (flatIdx < end) return true; // it's a row\n pos = end;\n }\n }\n return false;\n };\n }, [isGrouped, pq.groups]);\n\n // Column layout ref for horizontal auto-scroll\n const colLayoutRef = useRef<{ rowNumWidth: number; widths: number[] }>({\n rowNumWidth: 50,\n widths: [],\n });\n\n const scrollToCell = useCallback(\n (row: number, col: number) => {\n vScroll.scrollToRow(row);\n const el = vScroll.scrollEl.current;\n if (!el) return;\n const { rowNumWidth, widths } = colLayoutRef.current;\n let colLeft = rowNumWidth;\n for (let i = 0; i < col; i++) colLeft += widths[i] ?? 0;\n const colRight = colLeft + (widths[col] ?? 0);\n const viewLeft = el.scrollLeft;\n const viewRight = viewLeft + el.clientWidth;\n\n if (colRight > viewRight) {\n el.scrollLeft = colRight - el.clientWidth;\n } else if (colLeft < viewLeft) {\n el.scrollLeft = col === 0 ? 0 : colLeft;\n }\n },\n [vScroll.scrollToRow],\n );\n\n const keyboard = useKeyboardNavigation(scrollToCell, isNavigable);\n\n // ── Keyboard handler ──\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n keyboard.handleKeyDown(e, scrollRowCount, colManager.visibleColumns.length);\n },\n [keyboard, scrollRowCount, colManager.visibleColumns.length],\n );\n\n // ── Sort click ──\n const handleSortClick = useCallback(\n (column: string, multi: boolean) => pq.toggleSort(column, multi),\n [pq.toggleSort],\n );\n\n // ── Context menu handlers ──\n const handleContextMenu = useCallback(\n (column: string, x: number, y: number) => setContextMenu({ column, x, y }),\n [],\n );\n const handleCloseContextMenu = useCallback(() => setContextMenu(null), []);\n\n // ── Chip remove handlers ──\n const handleRemoveSort = useCallback(\n (column: string) => pq.setSort(pq.pipeline.sorts.filter((sort) => sort.column !== column)),\n [pq.setSort, pq.pipeline.sorts],\n );\n const handleRemoveFilter = useCallback(\n (column: string) => pq.removeFilter(column),\n [pq.removeFilter],\n );\n const handleRemoveGroup = useCallback(\n (column: string) => pq.toggleGroup(column),\n [pq.toggleGroup],\n );\n\n const isColumnGrouped = useCallback(\n (column: string) => pq.pipeline.groups.some((g) => g.column === column),\n [pq.pipeline.groups],\n );\n\n // ── Layout computations ──\n const visibleCols = colManager.visibleColumns;\n const rowNumWidth = Math.max(50, String(pq.filteredRowCount).length * 9 + 24);\n\n colLayoutRef.current = {\n rowNumWidth,\n widths: visibleCols.map((c) => c.width),\n };\n\n // ── Drop zone props ──\n const dropZoneProps = onRequestOpen\n ? { onFileSelect: handleFileSelect, onCustomOpen: handleCustomOpen }\n : { onFileSelect: handleFileSelect };\n\n // ── Render flags ──\n const showDropZone = allowOpen && !hasSource;\n const showGrid = hasSource && !pq.loading && !pq.error;\n\n return (\n <div className={className} style={{ ...s.root, ...style }}>\n <style>{PARKUI_CSS}</style>\n\n {/* Toolbar */}\n {showToolbar && (\n <Toolbar\n allowOpen={allowOpen}\n hasSource={hasSource}\n fileName={fileName}\n pipeline={pq.pipeline}\n searchText={search.searchText}\n onSearchChange={search.handleSearchChange}\n onClearSearch={search.clearSearch}\n onRequestOpen={onRequestOpen ? handleCustomOpen : undefined}\n onFileSelect={handleFileSelect}\n onClose={handleClose}\n onRemoveSort={handleRemoveSort}\n onRemoveFilter={handleRemoveFilter}\n onRemoveGroup={handleRemoveGroup}\n />\n )}\n\n {/* Content area */}\n <div\n ref={containerRef}\n style={s.content}\n tabIndex={showGrid ? 0 : undefined}\n onKeyDown={showGrid ? handleKeyDown : undefined}\n role={showGrid ? \"grid\" : undefined}\n aria-rowcount={showGrid ? pq.filteredRowCount : undefined}\n aria-colcount={showGrid ? visibleCols.length : undefined}\n >\n {hasSource && pq.loading && (\n <div style={s.placeholder}>Loading...</div>\n )}\n\n {hasSource && pq.error && (\n <div style={s.error}>{pq.error}</div>\n )}\n\n {showDropZone && (\n <div style={s.dropZoneWrapper}>\n <FileDropZone {...dropZoneProps} />\n </div>\n )}\n\n {!hasSource && !allowOpen && (\n <div style={s.placeholder}>No parquet source provided</div>\n )}\n\n {showGrid && (\n <DataGrid\n vScroll={vScroll}\n scrollRowCount={scrollRowCount}\n visibleColumns={visibleCols}\n totalColWidth={colManager.totalWidth}\n rowNumWidth={rowNumWidth}\n getRow={pq.getRow}\n ensureRange={pq.ensureRange}\n ensureIndices={pq.ensureIndices}\n renderTick={pq.renderTick}\n groups={pq.groups}\n isGrouped={isGrouped}\n computing={pq.computing}\n toggleGroupExpanded={pq.toggleGroupExpanded}\n dragState={colManager.dragState}\n resizeState={colManager.resizeState}\n onDragStart={colManager.startDrag}\n onDragOver={colManager.updateDragOver}\n onDragOverEnd={colManager.updateDragOverEnd}\n onDragEnd={colManager.endDrag}\n onResizeStart={colManager.startResize}\n onUpdateResize={colManager.updateResize}\n onEndResize={colManager.endResize}\n getSortDirection={pq.getSortDirection}\n getSortPriority={pq.getSortPriority}\n getFilter={pq.getFilter}\n isColumnGrouped={isColumnGrouped}\n onSortClick={handleSortClick}\n onContextMenu={handleContextMenu}\n keyboard={keyboard}\n searchText={search.debouncedSearch}\n />\n )}\n </div>\n\n {/* Context menu */}\n {contextMenu && (\n <ColumnContextMenu\n column={contextMenu.column}\n x={contextMenu.x}\n y={contextMenu.y}\n sortDirection={pq.getSortDirection(contextMenu.column)}\n sortPriority={pq.getSortPriority(contextMenu.column)}\n activeFilter={pq.getFilter(contextMenu.column)}\n isGrouped={pq.pipeline.groups.some((g) => g.column === contextMenu.column)}\n onClose={handleCloseContextMenu}\n onSortAsc={() => {\n pq.setSort([\n ...pq.pipeline.sorts.filter((sort) => sort.column !== contextMenu.column),\n { column: contextMenu.column, direction: \"asc\" },\n ]);\n }}\n onSortDesc={() => {\n pq.setSort([\n ...pq.pipeline.sorts.filter((sort) => sort.column !== contextMenu.column),\n { column: contextMenu.column, direction: \"desc\" },\n ]);\n }}\n onSortClear={() => {\n pq.setSort(pq.pipeline.sorts.filter((sort) => sort.column !== contextMenu.column));\n }}\n onFilterSet={(filter) => pq.setFilter(filter)}\n onFilterClear={() => pq.removeFilter(contextMenu.column)}\n onGroupToggle={() => pq.toggleGroup(contextMenu.column)}\n loadUniqueValues={() => pq.getUniqueValues(contextMenu.column)}\n />\n )}\n </div>\n );\n}\n","import { useState, useEffect, useRef, useCallback, type RefObject } from \"react\";\n\nexport interface ContainerSize {\n width: number;\n height: number;\n}\n\n/**\n * Observes the size of a container element via ResizeObserver.\n * Returns a ref to attach to the element and the current size.\n */\nexport function useContainerSize(): {\n containerRef: RefObject<HTMLDivElement | null>;\n size: ContainerSize;\n} {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [size, setSize] = useState<ContainerSize>({ width: 0, height: 0 });\n const rafRef = useRef<number>(0);\n\n const handleResize = useCallback((entries: ResizeObserverEntry[]) => {\n // Use rAF to batch size updates and avoid layout thrashing\n cancelAnimationFrame(rafRef.current);\n rafRef.current = requestAnimationFrame(() => {\n const entry = entries[0];\n if (entry) {\n const { width, height } = entry.contentRect;\n setSize((prev) => {\n // Only update if dimensions actually changed (avoid re-renders)\n if (\n Math.abs(prev.width - width) < 1 &&\n Math.abs(prev.height - height) < 1\n ) {\n return prev;\n }\n return { width, height };\n });\n }\n });\n }, []);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const observer = new ResizeObserver(handleResize);\n observer.observe(el);\n\n return () => {\n cancelAnimationFrame(rafRef.current);\n observer.disconnect();\n };\n }, [handleResize]);\n\n return { containerRef, size };\n}\n","import { useState, useCallback, useRef, useEffect } from \"react\";\nimport {\n readColumnValues,\n buildFilterIndex,\n buildGroups,\n collectUniqueValues,\n createEmptyPipeline,\n compareValues,\n asyncSort,\n yieldToUI,\n type ParquetMetadata,\n type ParquetRow,\n type ParquetSource,\n type SortDef,\n type SortDirection,\n type FilterDef,\n type GroupDef,\n type GroupNode,\n type PipelineState,\n} from \"@parqui/core\";\nimport { useSourceLoader } from \"./useSourceLoader.js\";\nimport { useChunkLoader } from \"./useChunkLoader.js\";\nimport type { ParquetInputSource } from \"../source.js\";\n\n// ── Public interface ──\n\nexport interface UseParquetDataReturn {\n metadata: ParquetMetadata | null;\n loading: boolean;\n error: string | null;\n totalRows: number;\n\n pipeline: PipelineState;\n computing: boolean;\n filteredRowCount: number;\n groups: GroupNode[];\n\n getRow: (displayIndex: number) => ParquetRow | undefined;\n ensureRange: (start: number, end: number) => void;\n ensureIndices: (displayIndices: number[]) => void;\n renderTick: number;\n\n // Sort\n toggleSort: (column: string, multi?: boolean) => void;\n setSort: (sorts: SortDef[]) => void;\n clearSort: () => void;\n getSortDirection: (column: string) => SortDirection | null;\n getSortPriority: (column: string) => number | null;\n\n // Filter\n setFilter: (filter: FilterDef) => void;\n removeFilter: (column: string) => void;\n clearFilters: () => void;\n getFilter: (column: string) => FilterDef | undefined;\n getUniqueValues: (column: string) => Promise<unknown[]>;\n\n // Group\n setGroups: (groups: GroupDef[]) => void;\n toggleGroup: (column: string) => void;\n clearGroups: () => void;\n toggleGroupExpanded: (index: number) => void;\n\n resetAll: () => void;\n}\n\n// ── Hook ──\n\nexport function useParquetData(\n inputSource?: ParquetInputSource,\n columns?: string[],\n searchText?: string,\n): UseParquetDataReturn {\n // ── Layer 1: Source loading ──\n const { state: sourceState, sourceRef, metadataRef, mountedRef } = useSourceLoader(inputSource);\n\n // ── Layer 2: Pipeline state ──\n const [pipeline, setPipeline] = useState<PipelineState>(createEmptyPipeline);\n const [computing, setComputing] = useState(false);\n const [mapping, setMapping] = useState<number[] | null>(null);\n const [groups, setGroups] = useState<GroupNode[]>([]);\n\n const mappingRef = useRef<number[] | null>(null);\n const genRef = useRef(0);\n\n // Column value cache (survives pipeline recomputes, cleared on source change)\n const columnCacheRef = useRef<Map<string, unknown[]>>(new Map());\n const uniqueCacheRef = useRef<Map<string, unknown[]>>(new Map());\n\n const filteredRowCount = mapping ? mapping.length : sourceState.totalRows;\n\n // ── Layer 3: Chunk loading ──\n const chunks = useChunkLoader(\n sourceRef, metadataRef, mountedRef, mappingRef, genRef,\n columns, computing,\n );\n\n // ── Reset pipeline when source changes ──\n useEffect(() => {\n columnCacheRef.current.clear();\n uniqueCacheRef.current.clear();\n chunks.clearCaches();\n mappingRef.current = null;\n genRef.current++;\n setPipeline(createEmptyPipeline());\n setMapping(null);\n setGroups([]);\n setComputing(false);\n }, [inputSource]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // ── Pipeline compute ──\n\n useEffect(() => {\n const source = sourceRef.current;\n const metadata = metadataRef.current;\n const totalRows = metadata?.rowCount ?? 0;\n\n if (!source || !metadata || totalRows === 0) {\n if (mappingRef.current !== null) {\n genRef.current++;\n }\n mappingRef.current = null;\n setMapping(null);\n setGroups([]);\n setComputing(false);\n return;\n }\n\n // Capture narrowed values for async closure\n const narrowedSource: import(\"@parqui/core\").ParquetSource = source;\n const allColumnNames = metadata.columns.map((c) => c.name);\n const { sorts, filters, groups: groupDefs } = pipeline;\n const needle = searchText?.trim().toLowerCase() ?? \"\";\n\n // Fast path: no transforms → identity\n if (sorts.length === 0 && filters.length === 0 && groupDefs.length === 0 && !needle) {\n const hadMapping = mappingRef.current !== null;\n mappingRef.current = null;\n setMapping(null);\n setGroups([]);\n setComputing(false);\n if (hadMapping) {\n // Only invalidate in-flight loads when transitioning FROM a pipeline\n // back to identity. On initial load (hadMapping=false) there are no\n // stale reads to discard, and incrementing gen here would race with\n // child-component effects that already captured the current gen.\n genRef.current++;\n chunks.clearCaches();\n }\n return;\n }\n\n // Async compute\n const gen = ++genRef.current;\n const isStale = () => gen !== genRef.current;\n\n chunks.clearCaches();\n setComputing(true);\n\n async function compute() {\n try {\n // 1. Read needed columns\n const neededCols = new Set<string>();\n for (const s of sorts) neededCols.add(s.column);\n for (const f of filters) neededCols.add(f.column);\n for (const g of groupDefs) neededCols.add(g.column);\n // Full-text search needs all columns\n if (needle) {\n for (const c of allColumnNames) neededCols.add(c);\n }\n\n const toRead = [...neededCols].filter(\n (c) => !columnCacheRef.current.has(c),\n );\n if (toRead.length > 0) {\n const newCols = await readColumnValues(narrowedSource, toRead, isStale);\n if (isStale()) return;\n for (const [key, vals] of newCols) {\n columnCacheRef.current.set(key, vals);\n }\n }\n\n if (isStale()) return;\n await yieldToUI();\n\n // 2. Filter\n let indices = buildFilterIndex(totalRows, filters, columnCacheRef.current);\n if (indices === null) {\n indices = Array.from({ length: totalRows }, (_, i) => i);\n }\n\n // 2b. Full-text search filter\n if (needle) {\n indices = indices.filter((rowIdx) => {\n for (const colName of allColumnNames) {\n const col = columnCacheRef.current.get(colName);\n if (!col) continue;\n const val = col[rowIdx];\n if (val === null || val === undefined) continue;\n const str = typeof val === \"object\" ? JSON.stringify(val) : String(val);\n if (str.toLowerCase().includes(needle)) return true;\n }\n return false;\n });\n }\n\n if (isStale()) return;\n await yieldToUI();\n\n // 3. Sort\n if (sorts.length > 0) {\n const colValues = columnCacheRef.current;\n const compareFn = (a: number, b: number) => {\n for (const sort of sorts) {\n const col = colValues.get(sort.column);\n if (!col) continue;\n const va = col[a];\n const vb = col[b];\n const cmp = compareValues(va, vb);\n if (cmp !== 0) return sort.direction === \"asc\" ? cmp : -cmp;\n }\n return a - b;\n };\n\n if (indices.length > 100_000) {\n indices = await asyncSort(indices, compareFn, isStale);\n } else {\n indices.sort(compareFn);\n }\n }\n\n if (isStale()) return;\n\n // 4. Group\n let groupNodes: GroupNode[] = [];\n if (groupDefs.length > 0) {\n groupNodes = buildGroups(indices, groupDefs, columnCacheRef.current);\n }\n\n // 5. Apply\n mappingRef.current = indices;\n setMapping(indices);\n setGroups(groupNodes);\n } catch {\n // Keep previous state on error\n } finally {\n if (!isStale()) setComputing(false);\n }\n }\n\n compute();\n }, [sourceState.source, sourceState.metadata, sourceState.totalRows, pipeline, searchText]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // ── Sort actions ──\n\n const toggleSort = useCallback((column: string, multi = false) => {\n setPipeline((prev) => {\n const existing = prev.sorts.find((s) => s.column === column);\n let newSorts: SortDef[];\n if (!existing) {\n newSorts = multi ? [...prev.sorts, { column, direction: \"asc\" }] : [{ column, direction: \"asc\" }];\n } else if (existing.direction === \"asc\") {\n newSorts = multi\n ? prev.sorts.map((s) =>\n s.column === column ? { ...s, direction: \"desc\" as const } : s,\n )\n : [{ column, direction: \"desc\" }];\n } else {\n newSorts = multi ? prev.sorts.filter((s) => s.column !== column) : [];\n }\n return { ...prev, sorts: newSorts };\n });\n }, []);\n\n const setSort = useCallback((sorts: SortDef[]) => {\n setPipeline((prev) => ({ ...prev, sorts }));\n }, []);\n\n const clearSort = useCallback(() => {\n setPipeline((prev) => ({ ...prev, sorts: [] }));\n }, []);\n\n const getSortDirection = useCallback(\n (column: string): SortDirection | null =>\n pipeline.sorts.find((s) => s.column === column)?.direction ?? null,\n [pipeline.sorts],\n );\n\n const getSortPriority = useCallback(\n (column: string): number | null => {\n const idx = pipeline.sorts.findIndex((s) => s.column === column);\n return idx >= 0 ? idx + 1 : null;\n },\n [pipeline.sorts],\n );\n\n // ── Filter actions ──\n\n const setFilter = useCallback((filter: FilterDef) => {\n setPipeline((prev) => ({\n ...prev,\n filters: [\n ...prev.filters.filter((f) => f.column !== filter.column),\n filter,\n ],\n }));\n }, []);\n\n const removeFilter = useCallback((column: string) => {\n setPipeline((prev) => ({\n ...prev,\n filters: prev.filters.filter((f) => f.column !== column),\n }));\n }, []);\n\n const clearFilters = useCallback(() => {\n setPipeline((prev) => ({ ...prev, filters: [] }));\n }, []);\n\n const getFilter = useCallback(\n (column: string): FilterDef | undefined =>\n pipeline.filters.find((f) => f.column === column),\n [pipeline.filters],\n );\n\n const getUniqueValues = useCallback(\n async (column: string): Promise<unknown[]> => {\n if (uniqueCacheRef.current.has(column)) {\n return uniqueCacheRef.current.get(column)!;\n }\n const source = sourceRef.current;\n if (!source) return [];\n\n let values = columnCacheRef.current.get(column);\n if (!values) {\n const cols = await readColumnValues(source, [column]);\n values = cols.get(column) ?? [];\n columnCacheRef.current.set(column, values);\n }\n\n const unique = collectUniqueValues(values, 500);\n uniqueCacheRef.current.set(column, unique);\n return unique;\n },\n [], // eslint-disable-line react-hooks/exhaustive-deps\n );\n\n // ── Group actions ──\n\n const setGroupDefs = useCallback((groupDefs: GroupDef[]) => {\n setPipeline((prev) => ({ ...prev, groups: groupDefs }));\n }, []);\n\n const toggleGroup = useCallback((column: string) => {\n setPipeline((prev) => {\n const exists = prev.groups.some((g) => g.column === column);\n const newGroups = exists\n ? prev.groups.filter((g) => g.column !== column)\n : [...prev.groups, { column }];\n return { ...prev, groups: newGroups };\n });\n }, []);\n\n const clearGroups = useCallback(() => {\n setPipeline((prev) => ({ ...prev, groups: [] }));\n }, []);\n\n const toggleGroupExpanded = useCallback((groupIndex: number) => {\n setGroups((prev) =>\n prev.map((g, i) =>\n i === groupIndex ? { ...g, expanded: !g.expanded } : g,\n ),\n );\n }, []);\n\n // ── Reset ──\n\n const resetAll = useCallback(() => {\n setPipeline(createEmptyPipeline());\n mappingRef.current = null;\n genRef.current++;\n chunks.clearCaches();\n setMapping(null);\n setGroups([]);\n setComputing(false);\n columnCacheRef.current.clear();\n uniqueCacheRef.current.clear();\n }, [chunks]);\n\n return {\n metadata: sourceState.metadata,\n loading: sourceState.loading,\n error: sourceState.error,\n totalRows: sourceState.totalRows,\n pipeline,\n computing,\n filteredRowCount,\n groups,\n getRow: chunks.getRow,\n ensureRange: chunks.ensureRange,\n ensureIndices: chunks.ensureIndices,\n renderTick: chunks.renderTick,\n toggleSort,\n setSort,\n clearSort,\n getSortDirection,\n getSortPriority,\n setFilter,\n removeFilter,\n clearFilters,\n getFilter,\n getUniqueValues,\n setGroups: setGroupDefs,\n toggleGroup,\n clearGroups,\n toggleGroupExpanded,\n resetAll,\n };\n}\n","import { useState, useEffect, useRef } from \"react\";\nimport {\n readParquetMetadata,\n sourceFromFile,\n sourceFromBuffer,\n sourceFromUrl,\n type ParquetMetadata,\n type ParquetSource,\n} from \"@parqui/core\";\nimport {\n resolveSourceInput,\n type ParquetInputSource,\n} from \"../source.js\";\n\nexport interface SourceState {\n metadata: ParquetMetadata | null;\n source: ParquetSource | null;\n loading: boolean;\n error: string | null;\n totalRows: number;\n}\n\nconst EMPTY_STATE: SourceState = {\n metadata: null,\n source: null,\n loading: false,\n error: null,\n totalRows: 0,\n};\n\n/**\n * Resolves a ParquetInputSource into a ParquetSource and reads its metadata.\n * Handles File, ArrayBuffer, URL, and raw ParquetSource inputs.\n *\n * Returns stable refs for the source and metadata alongside React state.\n */\nexport function useSourceLoader(inputSource?: ParquetInputSource) {\n const [state, setState] = useState<SourceState>(EMPTY_STATE);\n\n // Refs for synchronous access (no re-render needed)\n const sourceRef = useRef<ParquetSource | null>(null);\n const metadataRef = useRef<ParquetMetadata | null>(null);\n const mountedRef = useRef(true);\n\n useEffect(() => {\n mountedRef.current = true;\n sourceRef.current = null;\n metadataRef.current = null;\n setState({ ...EMPTY_STATE, loading: true });\n\n let cancelled = false;\n\n async function init() {\n try {\n let source: ParquetSource;\n const resolved = resolveSourceInput(inputSource);\n\n if (resolved.source) source = resolved.source;\n else if (resolved.data) source = sourceFromBuffer(resolved.data);\n else if (resolved.file) source = sourceFromFile(resolved.file);\n else if (resolved.url) source = await sourceFromUrl(resolved.url);\n else {\n setState(EMPTY_STATE);\n return;\n }\n\n if (cancelled) return;\n sourceRef.current = source;\n\n const metadata = await readParquetMetadata(source);\n if (cancelled) return;\n\n metadataRef.current = metadata;\n setState({\n metadata,\n source,\n loading: false,\n error: null,\n totalRows: metadata.rowCount,\n });\n } catch (err) {\n if (!cancelled) {\n setState({\n ...EMPTY_STATE,\n error: err instanceof Error ? err.message : \"Failed to load file\",\n });\n }\n }\n }\n\n init();\n\n return () => {\n cancelled = true;\n mountedRef.current = false;\n };\n }, [inputSource]);\n\n return { state, sourceRef, metadataRef, mountedRef };\n}\n","import type { ParquetSource } from \"@parqui/core\";\n\nexport type ParquetInputSource = File | ArrayBuffer | string | ParquetSource;\n\nexport interface ResolvedSourceInput {\n file?: File;\n data?: ArrayBuffer;\n url?: string;\n source?: ParquetSource;\n}\n\ntype SliceablePromise = Promise<ArrayBuffer> & {\n slice: (start: number, end?: number) => Promise<ArrayBuffer>;\n};\n\nfunction makeSliceablePromise(input: Promise<ArrayBuffer>): SliceablePromise {\n const promise = Promise.resolve(input) as SliceablePromise;\n promise.slice = (start: number, end?: number) =>\n promise.then((buffer) => buffer.slice(start, end));\n return promise;\n}\n\nconst sourceCache = new WeakMap<ParquetSource, ParquetSource>();\n\nfunction normalizeParquetSource(source: ParquetSource): ParquetSource {\n const cached = sourceCache.get(source);\n if (cached) return cached;\n\n const wrapped: ParquetSource = {\n byteLength: source.byteLength,\n slice(start: number, end?: number): Promise<ArrayBuffer> {\n return makeSliceablePromise(\n Promise.resolve(source.slice(start, end)),\n );\n },\n };\n\n sourceCache.set(source, wrapped);\n return wrapped;\n}\n\nexport function isFileSource(value: unknown): value is File {\n return typeof File !== \"undefined\" && value instanceof File;\n}\n\nexport function isArrayBufferSource(value: unknown): value is ArrayBuffer {\n return value instanceof ArrayBuffer;\n}\n\nexport function isParquetSource(value: unknown): value is ParquetSource {\n if (!value || typeof value !== \"object\") return false;\n const candidate = value as Partial<ParquetSource>;\n return typeof candidate.byteLength === \"number\" && typeof candidate.slice === \"function\";\n}\n\nexport function resolveSourceInput(\n source: ParquetInputSource | undefined,\n): ResolvedSourceInput {\n if (source === undefined) return {};\n if (isFileSource(source)) return { file: source };\n if (isArrayBufferSource(source)) return { data: source };\n if (typeof source === \"string\") return { url: source };\n if (isParquetSource(source)) return { source: normalizeParquetSource(source) };\n return {};\n}\n\nexport function sourceToDisplayName(source: ParquetInputSource): string {\n if (isFileSource(source)) return source.name;\n if (typeof source === \"string\") return urlToName(source);\n return \"\";\n}\n\nexport function sourceToDisplaySize(\n source: ParquetInputSource,\n): number | undefined {\n if (isFileSource(source)) return source.size;\n return undefined;\n}\n\nfunction urlToName(url: string): string {\n try {\n const pathname = new URL(url).pathname;\n return pathname.split(\"/\").pop() ?? url;\n } catch {\n return url;\n }\n}\n","import { useState, useCallback, useRef } from \"react\";\nimport {\n readParquetData,\n runWithConcurrency,\n type ParquetRow,\n type ParquetSource,\n type ParquetMetadata,\n} from \"@parqui/core\";\n\n// ── Constants ──\n\nconst CHUNK_SIZE = 500;\nconst MAX_DISPLAY_CHUNKS = 10;\nconst SOURCE_CACHE_MAX = 5_000;\nconst MAX_CONCURRENT_READS = 4;\nconst GAP_TOLERANCE = 200;\n\ninterface ChunkEntry {\n rows: ParquetRow[];\n loadedAt: number;\n}\n\nexport interface ChunkLoader {\n /** Get a row by display index. Returns undefined if not yet loaded. */\n getRow: (displayIndex: number) => ParquetRow | undefined;\n /** Ensure rows in [start, end) range are loaded. */\n ensureRange: (start: number, end: number) => void;\n /** Ensure specific display indices are loaded (for grouped view). */\n ensureIndices: (displayIndices: number[]) => void;\n /** Clear all caches. Call when pipeline changes. */\n clearCaches: () => void;\n /** Counter that increments when display data changes. */\n renderTick: number;\n}\n\n/**\n * Manages chunked, on-demand loading of parquet row data.\n *\n * Two modes:\n * 1. Sequential (no mapping): reads offset/limit directly.\n * 2. Mapped (filtered/sorted): uses mapping array to fetch source rows,\n * clustering nearby indices for efficient batch reads.\n *\n * @param sourceRef — ref to current ParquetSource\n * @param metadataRef — ref to current metadata\n * @param mountedRef — ref to mounted flag\n * @param mappingRef — ref to filtered+sorted row index array (null = identity)\n * @param genRef — ref to generation counter for staleness detection\n * @param columns — optional column filter\n * @param computing — whether pipeline is currently computing (blocks loading)\n */\nexport function useChunkLoader(\n sourceRef: React.RefObject<ParquetSource | null>,\n metadataRef: React.RefObject<ParquetMetadata | null>,\n mountedRef: React.RefObject<boolean>,\n mappingRef: React.RefObject<number[] | null>,\n genRef: React.RefObject<number>,\n columns?: string[],\n computing?: boolean,\n): ChunkLoader {\n const [renderTick, setRenderTick] = useState(0);\n\n const columnsRef = useRef<string[] | undefined>(columns);\n columnsRef.current = columns;\n\n // Display chunk cache: chunkIndex → rows\n const chunksRef = useRef<Map<number, ChunkEntry>>(new Map());\n const loadingChunksRef = useRef<Set<number>>(new Set());\n\n // Source row cache for mapped mode: sourceRowIndex → row\n const sourceRowCacheRef = useRef<Map<number, ParquetRow>>(new Map());\n\n const tick = useCallback(() => setRenderTick((v) => v + 1), []);\n\n const clearCaches = useCallback(() => {\n chunksRef.current.clear();\n loadingChunksRef.current.clear();\n sourceRowCacheRef.current.clear();\n tick();\n }, [tick]);\n\n // ── Fetch source rows by clustering nearby indices ──\n\n const fetchSourceRows = useCallback(\n async (neededIndices: number[], gen: number): Promise<void> => {\n if (!sourceRef.current || !metadataRef.current || neededIndices.length === 0) return;\n\n const totalRows = metadataRef.current.rowCount;\n const unique = [...new Set(neededIndices)].filter(\n (idx) => !sourceRowCacheRef.current.has(idx),\n );\n if (unique.length === 0) return;\n\n unique.sort((a, b) => a - b);\n\n // Cluster nearby indices\n const clusters: { start: number; end: number; needed: Set<number> }[] = [];\n let curStart = unique[0];\n let curEnd = unique[0] + 1;\n let curNeeded = new Set([unique[0]]);\n\n for (let i = 1; i < unique.length; i++) {\n if (unique[i] <= curEnd + GAP_TOLERANCE) {\n curEnd = unique[i] + 1;\n curNeeded.add(unique[i]);\n } else {\n clusters.push({ start: curStart, end: curEnd, needed: curNeeded });\n curStart = unique[i];\n curEnd = unique[i] + 1;\n curNeeded = new Set([unique[i]]);\n }\n }\n clusters.push({ start: curStart, end: curEnd, needed: curNeeded });\n\n await runWithConcurrency(clusters, MAX_CONCURRENT_READS, async (cluster) => {\n if (gen !== genRef.current) return;\n try {\n const readStart = Math.max(0, cluster.start);\n const readEnd = Math.min(cluster.end, totalRows);\n const result = await readParquetData(sourceRef.current!, {\n columns: columnsRef.current,\n offset: readStart,\n limit: readEnd - readStart,\n });\n if (!mountedRef.current || gen !== genRef.current) return;\n\n for (let i = 0; i < result.rows.length; i++) {\n const sourceIdx = readStart + i;\n if (cluster.needed.has(sourceIdx)) {\n sourceRowCacheRef.current.set(sourceIdx, result.rows[i]);\n }\n }\n } catch (err) {\n console.error(\"[parqui] chunk load error:\", err);\n // Will be retried on next ensureRange\n }\n });\n\n // Evict oldest if cache is too large\n const cache = sourceRowCacheRef.current;\n if (cache.size > SOURCE_CACHE_MAX) {\n const toDelete = cache.size - SOURCE_CACHE_MAX;\n let count = 0;\n for (const key of cache.keys()) {\n if (count >= toDelete) break;\n cache.delete(key);\n count++;\n }\n }\n },\n [sourceRef, metadataRef, mountedRef, genRef],\n );\n\n // ── Load a single display chunk ──\n\n const loadChunk = useCallback(\n async (chunkIndex: number) => {\n if (loadingChunksRef.current.has(chunkIndex)) return;\n if (chunksRef.current.has(chunkIndex)) return;\n if (!sourceRef.current) return;\n\n loadingChunksRef.current.add(chunkIndex);\n const gen = genRef.current;\n\n try {\n const curMapping = mappingRef.current;\n const displayStart = chunkIndex * CHUNK_SIZE;\n\n if (curMapping) {\n // Mapped mode: resolve source indices\n const displayEnd = Math.min(displayStart + CHUNK_SIZE, curMapping.length);\n const sourceIndices = curMapping.slice(displayStart, displayEnd);\n const uncached = sourceIndices.filter(\n (idx) => !sourceRowCacheRef.current.has(idx),\n );\n\n if (uncached.length > 0) {\n await fetchSourceRows(uncached, gen);\n if (!mountedRef.current || gen !== genRef.current) return;\n }\n\n const rows: ParquetRow[] = [];\n for (const sourceIdx of sourceIndices) {\n rows.push(sourceRowCacheRef.current.get(sourceIdx) ?? {});\n }\n\n if (mountedRef.current && gen === genRef.current) {\n chunksRef.current.set(chunkIndex, { rows, loadedAt: Date.now() });\n evictOldChunks(chunksRef.current);\n tick();\n }\n } else {\n // Sequential mode: direct offset/limit read\n const result = await readParquetData(sourceRef.current!, {\n columns: columnsRef.current,\n offset: displayStart,\n limit: CHUNK_SIZE,\n });\n\n if (mountedRef.current && gen === genRef.current) {\n chunksRef.current.set(chunkIndex, { rows: result.rows, loadedAt: Date.now() });\n evictOldChunks(chunksRef.current);\n tick();\n }\n }\n } catch (err) {\n console.error(\"[parqui] loadChunk error for chunk\", chunkIndex, err);\n // Will be retried on next ensureRange\n } finally {\n loadingChunksRef.current.delete(chunkIndex);\n }\n },\n [sourceRef, mappingRef, mountedRef, genRef, fetchSourceRows, tick],\n );\n\n // ── Public API ──\n\n const getRow = useCallback(\n (displayIndex: number): ParquetRow | undefined => {\n const chunkIndex = Math.floor(displayIndex / CHUNK_SIZE);\n const chunk = chunksRef.current.get(chunkIndex);\n if (!chunk) return undefined;\n return chunk.rows[displayIndex - chunkIndex * CHUNK_SIZE];\n },\n [],\n );\n\n const ensureRange = useCallback(\n (start: number, end: number) => {\n if (computing) return;\n const startChunk = Math.floor(start / CHUNK_SIZE);\n const endChunk = Math.floor(Math.max(0, end - 1) / CHUNK_SIZE);\n for (let i = startChunk; i <= endChunk; i++) {\n if (!chunksRef.current.has(i) && !loadingChunksRef.current.has(i)) {\n loadChunk(i);\n }\n }\n },\n [loadChunk, computing],\n );\n\n const ensureIndices = useCallback(\n (displayIndices: number[]) => {\n if (computing) return;\n const chunkSet = new Set<number>();\n for (const idx of displayIndices) {\n chunkSet.add(Math.floor(idx / CHUNK_SIZE));\n }\n for (const chunkIdx of chunkSet) {\n if (!chunksRef.current.has(chunkIdx) && !loadingChunksRef.current.has(chunkIdx)) {\n loadChunk(chunkIdx);\n }\n }\n },\n [loadChunk, computing],\n );\n\n return { getRow, ensureRange, ensureIndices, clearCaches, renderTick };\n}\n\n// ── Internal helpers ──\n\nfunction evictOldChunks(chunks: Map<number, ChunkEntry>) {\n if (chunks.size <= MAX_DISPLAY_CHUNKS) return;\n const entries = [...chunks.entries()].sort(\n (a, b) => a[1].loadedAt - b[1].loadedAt,\n );\n const toRemove = entries.length - MAX_DISPLAY_CHUNKS;\n for (let i = 0; i < toRemove; i++) {\n chunks.delete(entries[i][0]);\n }\n}\n","import { useState, useCallback, useRef, useEffect } from \"react\";\n\nexport const ROW_HEIGHT = 32;\nexport const HEADER_HEIGHT = 36;\nconst OVERSCAN = 10; // extra rows rendered above/below viewport\n\nconst MAX_SCROLL_HEIGHT = 1_500_000;\n\nexport interface VirtualScrollState {\n scrollTop: number;\n startIndex: number;\n endIndex: number;\n visibleCount: number;\n totalHeight: number;\n offsetY: number;\n}\n\nexport interface VirtualScroll extends VirtualScrollState {\n onScroll: (e: React.UIEvent<HTMLDivElement>) => void;\n scrollToRow: (rowIndex: number) => void;\n /** Callback ref — attach to the scroll container element. */\n scrollRef: (el: HTMLDivElement | null) => void;\n /** Read-only ref to the scroll container (for imperative access). */\n scrollEl: React.RefObject<HTMLDivElement | null>;\n}\n\n/**\n * Virtual scroll engine.\n *\n * Uses a callback ref to attach a ResizeObserver the moment the scroll\n * container mounts (not on first render — the element may not exist yet\n * if the component shows a loading state first).\n *\n * On resize, adjusts scrollTop to maintain the same first visible row.\n */\nexport function useVirtualScroll(\n containerHeight: number,\n totalRows: number,\n resetKey?: unknown,\n): VirtualScroll {\n const elRef = useRef<HTMLDivElement | null>(null);\n const roRef = useRef<ResizeObserver | null>(null);\n const [scrollTop, setScrollTop] = useState(0);\n const [measuredHeight, setMeasuredHeight] = useState(0);\n\n // Current scroll params — used by ResizeObserver to maintain rawStart\n const paramsRef = useRef({\n rawStart: 0,\n scaled: false,\n totalHeight: 0,\n totalRows: 0,\n });\n\n // Callback ref: sets up ResizeObserver when the element mounts,\n // cleans up when it unmounts. This works even if the element appears\n // after the first render (e.g. after loading finishes).\n const scrollRef = useCallback((el: HTMLDivElement | null) => {\n // Clean up previous observer\n if (roRef.current) {\n roRef.current.disconnect();\n roRef.current = null;\n }\n\n elRef.current = el;\n\n if (!el) return;\n\n // Initial measurement\n setMeasuredHeight(el.clientHeight);\n setScrollTop(el.scrollTop);\n\n roRef.current = new ResizeObserver(() => {\n const newClientHeight = el.clientHeight;\n const p = paramsRef.current;\n\n if (p.scaled && p.totalRows > 0) {\n const newBodyHeight = Math.max(1, newClientHeight - HEADER_HEIGHT);\n const newMaxScroll = Math.max(1, p.totalHeight - newBodyHeight);\n const newFullyVisible = Math.floor(newBodyHeight / ROW_HEIGHT);\n const newMaxFirstRow = Math.max(1, p.totalRows - newFullyVisible);\n const targetRaw = Math.min(p.rawStart, newMaxFirstRow);\n const newScrollTop = (targetRaw / newMaxFirstRow) * newMaxScroll;\n\n el.scrollTop = newScrollTop;\n setScrollTop(el.scrollTop);\n } else {\n setScrollTop(el.scrollTop);\n }\n\n setMeasuredHeight(newClientHeight);\n });\n\n roRef.current.observe(el);\n }, []);\n\n // Always prefer the live DOM height over React state to avoid stale values after resize.\n // `measuredHeight` state is only used to trigger re-renders via ResizeObserver;\n // the actual computation uses the real clientHeight from the DOM.\n const liveHeight = elRef.current?.clientHeight ?? 0;\n const effectiveHeight = liveHeight > 0 ? liveHeight : (measuredHeight > 0 ? measuredHeight : containerHeight);\n\n // Reset scroll only when the data source changes\n useEffect(() => {\n setScrollTop(0);\n if (elRef.current) {\n elRef.current.scrollTop = 0;\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resetKey]);\n\n const bodyHeight = Math.max(1, effectiveHeight - HEADER_HEIGHT);\n const visibleCount = Math.ceil(bodyHeight / ROW_HEIGHT);\n\n const naturalHeight = totalRows * ROW_HEIGHT;\n const scaled = naturalHeight > MAX_SCROLL_HEIGHT;\n const totalHeight = scaled ? MAX_SCROLL_HEIGHT : naturalHeight + ROW_HEIGHT;\n\n let startIndex: number;\n let endIndex: number;\n let offsetY: number;\n let rawStart: number;\n\n if (scaled) {\n const maxScroll = Math.max(1, totalHeight - bodyHeight);\n const scrollFraction = Math.min(1, Math.max(0, scrollTop / maxScroll));\n const fullyVisibleRows = Math.floor(bodyHeight / ROW_HEIGHT);\n const maxFirstRow = Math.max(0, totalRows - fullyVisibleRows);\n rawStart = Math.round(scrollFraction * maxFirstRow);\n startIndex = Math.max(0, rawStart - OVERSCAN);\n endIndex = Math.min(totalRows, rawStart + visibleCount + OVERSCAN);\n\n const overscanAbove = rawStart - startIndex;\n offsetY = scrollTop - overscanAbove * ROW_HEIGHT;\n } else {\n rawStart = Math.floor(scrollTop / ROW_HEIGHT);\n startIndex = Math.max(0, rawStart - OVERSCAN);\n endIndex = Math.min(totalRows, rawStart + visibleCount + OVERSCAN);\n offsetY = startIndex * ROW_HEIGHT;\n }\n\n // Keep params ref in sync for ResizeObserver\n paramsRef.current = { rawStart, scaled, totalHeight, totalRows };\n\n const onScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {\n const el = e.currentTarget;\n setScrollTop(el.scrollTop);\n setMeasuredHeight((prev) => {\n const h = el.clientHeight;\n return h === prev ? prev : h;\n });\n }, []);\n\n const scrollToRow = useCallback(\n (rowIndex: number) => {\n const el = elRef.current;\n if (!el) return;\n const idx = Math.max(0, Math.min(totalRows - 1, rowIndex));\n const actualBodyHeight = el.clientHeight - HEADER_HEIGHT;\n\n if (scaled) {\n const maxScroll = Math.max(1, totalHeight - actualBodyHeight);\n const fullyVisible = Math.floor(actualBodyHeight / ROW_HEIGHT);\n const maxFirstRow = Math.max(1, totalRows - fullyVisible);\n\n // Check visibility using the same Math.round as the render\n const frac = Math.min(1, Math.max(0, el.scrollTop / maxScroll));\n const renderRawStart = Math.round(frac * maxFirstRow);\n\n if (idx < renderRawStart) {\n el.scrollTop = (idx / maxFirstRow) * maxScroll;\n } else if (idx >= renderRawStart + fullyVisible) {\n el.scrollTop =\n ((idx - fullyVisible + 1) / maxFirstRow) * maxScroll;\n // Verify render's Math.round agrees; nudge if needed\n const checkFrac = Math.min(1, Math.max(0, el.scrollTop / maxScroll));\n const checkRaw = Math.round(checkFrac * maxFirstRow);\n if (idx >= checkRaw + fullyVisible) {\n el.scrollTop += 1;\n }\n }\n } else {\n const rowTop = idx * ROW_HEIGHT;\n const rowBottom = rowTop + ROW_HEIGHT;\n const viewTop = el.scrollTop;\n const viewBottom = viewTop + actualBodyHeight;\n\n if (rowTop < viewTop) {\n el.scrollTop = rowTop;\n } else if (rowBottom > viewBottom) {\n el.scrollTop = rowBottom - actualBodyHeight;\n }\n }\n\n // Sync state immediately\n setScrollTop(el.scrollTop);\n setMeasuredHeight(el.clientHeight);\n },\n [scaled, totalHeight, totalRows],\n );\n\n return {\n scrollTop,\n startIndex,\n endIndex,\n visibleCount,\n totalHeight,\n offsetY,\n onScroll,\n scrollToRow,\n scrollRef,\n scrollEl: elRef,\n };\n}\n","import { useState, useCallback, useRef } from \"react\";\n\nconst DEFAULT_COL_WIDTH = 150;\nconst MIN_COL_WIDTH = 50;\n\nexport interface ColumnDef {\n key: string;\n width: number;\n visible: boolean;\n}\n\nexport interface DragState {\n /** Column key being dragged */\n dragKey: string | null;\n /** Insert position index (the dragged column will be placed at this index) */\n insertIndex: number | null;\n}\n\nexport interface ResizeState {\n /** Column key being resized */\n columnKey: string | null;\n /** Starting mouse X */\n startX: number;\n /** Starting width */\n startWidth: number;\n}\n\nexport interface ColumnManager {\n columns: ColumnDef[];\n visibleColumns: ColumnDef[];\n totalWidth: number;\n /** Start dragging a column for reorder */\n startDrag: (key: string) => void;\n /** Update insert position based on mouse position over a column */\n updateDragOver: (overKey: string, mouseXInColumn: number, columnWidth: number) => void;\n /** Set insert position to after last column */\n updateDragOverEnd: () => void;\n /** Finish drag — apply the reorder */\n endDrag: () => void;\n dragState: DragState;\n /** Start resizing a column */\n startResize: (key: string, clientX: number) => void;\n /** Update resize (call on mousemove) */\n updateResize: (clientX: number) => void;\n /** End resize */\n endResize: () => void;\n resizeState: ResizeState;\n /** Toggle column visibility */\n toggleColumn: (key: string) => void;\n /** Show all columns */\n showAllColumns: () => void;\n /** Set column width explicitly */\n setColumnWidth: (key: string, width: number) => void;\n}\n\n/**\n * Manages column definitions: order, width, visibility, drag-and-drop, resize.\n */\nexport function useColumnManager(\n columnNames: string[],\n initialWidths?: Record<string, number>,\n): ColumnManager {\n const [columns, setColumns] = useState<ColumnDef[]>(() =>\n columnNames.map((key) => ({\n key,\n width: initialWidths?.[key] ?? DEFAULT_COL_WIDTH,\n visible: true,\n })),\n );\n\n // Track if columnNames changed (new file)\n const prevNamesRef = useRef<string[]>(columnNames);\n if (\n columnNames.length !== prevNamesRef.current.length ||\n columnNames.some((n, i) => n !== prevNamesRef.current[i])\n ) {\n prevNamesRef.current = columnNames;\n const newCols = columnNames.map((key) => ({\n key,\n width: initialWidths?.[key] ?? DEFAULT_COL_WIDTH,\n visible: true,\n }));\n setColumns(newCols);\n }\n\n const [dragState, setDragState] = useState<DragState>({\n dragKey: null,\n insertIndex: null,\n });\n\n // Use a ref to reliably read drag state in endDrag (avoids stale closure)\n const dragRef = useRef<DragState>(dragState);\n dragRef.current = dragState;\n\n const [resizeState, setResizeState] = useState<ResizeState>({\n columnKey: null,\n startX: 0,\n startWidth: 0,\n });\n\n const visibleColumns = columns.filter((c) => c.visible);\n const totalWidth = visibleColumns.reduce((sum, c) => sum + c.width, 0);\n\n // ── Drag & Drop reorder ──\n\n const startDrag = useCallback((key: string) => {\n setDragState({ dragKey: key, insertIndex: null });\n }, []);\n\n const updateDragOver = useCallback(\n (overKey: string, mouseXInColumn: number, columnWidth: number) => {\n setDragState((prev) => {\n if (!prev.dragKey || prev.dragKey === overKey) {\n return { ...prev, insertIndex: null };\n }\n\n // Find indices in the visible columns list\n const visibleCols = columns.filter((c) => c.visible);\n const overIdx = visibleCols.findIndex((c) => c.key === overKey);\n if (overIdx === -1) return prev;\n\n // If mouse is in the left half of the column → insert before it\n // If mouse is in the right half → insert after it\n const isLeftHalf = mouseXInColumn < columnWidth / 2;\n const insertIndex = isLeftHalf ? overIdx : overIdx + 1;\n\n return { ...prev, insertIndex };\n });\n },\n [columns],\n );\n\n const updateDragOverEnd = useCallback(() => {\n setDragState((prev) => {\n if (!prev.dragKey) return prev;\n const visibleCols = columns.filter((c) => c.visible);\n return { ...prev, insertIndex: visibleCols.length };\n });\n }, [columns]);\n\n const endDrag = useCallback(() => {\n const { dragKey, insertIndex } = dragRef.current;\n\n // Reset state first\n setDragState({ dragKey: null, insertIndex: null });\n\n if (!dragKey || insertIndex === null) return;\n\n setColumns((cols) => {\n const visibleCols = cols.filter((c) => c.visible);\n const fromIdx = visibleCols.findIndex((c) => c.key === dragKey);\n if (fromIdx === -1) return cols;\n\n // If dropping in the same position or the next one (no actual move), skip\n if (insertIndex === fromIdx || insertIndex === fromIdx + 1) return cols;\n\n // Work with the full column array but compute reorder from visible indices.\n // Map visible indices to full array indices.\n const visibleToFullIdx: number[] = [];\n cols.forEach((c, fullIdx) => {\n if (c.visible) visibleToFullIdx.push(fullIdx);\n });\n\n const fullFromIdx = visibleToFullIdx[fromIdx];\n const moved = cols[fullFromIdx];\n\n // Remove the dragged column\n const newCols = cols.filter((_, i) => i !== fullFromIdx);\n\n // Calculate insert position in the new (removed) array.\n // insertIndex is the target slot among visible columns.\n // We need to find where that maps in newCols.\n let targetFullIdx: number;\n if (insertIndex >= visibleCols.length) {\n // Insert after last visible column\n const lastVisibleFullIdx = visibleToFullIdx[visibleCols.length - 1];\n // After removal, adjust index\n targetFullIdx =\n lastVisibleFullIdx > fullFromIdx\n ? lastVisibleFullIdx // -1 for removal +1 for after = net 0\n : lastVisibleFullIdx + 1;\n } else {\n // Insert before the column currently at insertIndex\n const adjustedInsertIdx =\n insertIndex > fromIdx ? insertIndex - 1 : insertIndex;\n const remainingVisible = newCols.filter((c) => c.visible);\n const targetKey = remainingVisible[adjustedInsertIdx]?.key;\n targetFullIdx = targetKey\n ? newCols.findIndex((c) => c.key === targetKey)\n : newCols.length;\n }\n\n newCols.splice(targetFullIdx, 0, moved);\n return newCols;\n });\n }, []);\n\n // ── Resize ──\n\n const startResize = useCallback(\n (key: string, clientX: number) => {\n const col = columns.find((c) => c.key === key);\n if (col) {\n setResizeState({\n columnKey: key,\n startX: clientX,\n startWidth: col.width,\n });\n }\n },\n [columns],\n );\n\n const updateResize = useCallback(\n (clientX: number) => {\n if (!resizeState.columnKey) return;\n const delta = clientX - resizeState.startX;\n const newWidth = Math.max(MIN_COL_WIDTH, resizeState.startWidth + delta);\n setColumns((cols) =>\n cols.map((c) =>\n c.key === resizeState.columnKey ? { ...c, width: newWidth } : c,\n ),\n );\n },\n [resizeState],\n );\n\n const endResize = useCallback(() => {\n setResizeState({ columnKey: null, startX: 0, startWidth: 0 });\n }, []);\n\n // ── Visibility ──\n\n const toggleColumn = useCallback((key: string) => {\n setColumns((cols) =>\n cols.map((c) => (c.key === key ? { ...c, visible: !c.visible } : c)),\n );\n }, []);\n\n const showAllColumns = useCallback(() => {\n setColumns((cols) => cols.map((c) => ({ ...c, visible: true })));\n }, []);\n\n const setColumnWidth = useCallback((key: string, width: number) => {\n setColumns((cols) =>\n cols.map((c) =>\n c.key === key ? { ...c, width: Math.max(MIN_COL_WIDTH, width) } : c,\n ),\n );\n }, []);\n\n return {\n columns,\n visibleColumns,\n totalWidth,\n startDrag,\n updateDragOver,\n updateDragOverEnd,\n endDrag,\n dragState,\n startResize,\n updateResize,\n endResize,\n resizeState,\n toggleColumn,\n showAllColumns,\n setColumnWidth,\n };\n}\n","import { useState, useCallback } from \"react\";\n\nexport interface CellPosition {\n row: number;\n col: number;\n}\n\nexport interface KeyboardNavigation {\n activeCell: CellPosition | null;\n setActiveCell: (pos: CellPosition | null) => void;\n handleKeyDown: (\n e: React.KeyboardEvent,\n totalRows: number,\n totalCols: number,\n ) => void;\n handleCellClick: (row: number, col: number) => void;\n}\n\n/**\n * Manages active cell state and keyboard navigation (arrows, Tab, Home/End, PgUp/PgDn).\n *\n * @param onScrollToCell — called with (row, col) when the active cell changes\n * so the scroll container can bring it into view (both vertical and horizontal).\n * @param isNavigable — optional predicate. When provided, arrow/tab/page\n * movement skips rows where `isNavigable(row)` returns false (e.g. group\n * headers in a grouped view).\n */\nexport function useKeyboardNavigation(\n onScrollToCell?: (row: number, col: number) => void,\n isNavigable?: (row: number) => boolean,\n): KeyboardNavigation {\n const [activeCell, setActiveCell] = useState<CellPosition | null>(null);\n\n const moveTo = useCallback(\n (row: number, col: number, totalRows: number, totalCols: number) => {\n let r = Math.max(0, Math.min(totalRows - 1, row));\n const clampedCol = Math.max(0, Math.min(totalCols - 1, col));\n\n if (isNavigable) {\n // If we landed on a non-navigable row, advance in the direction of movement\n if (!isNavigable(r)) {\n const currentRow = activeCell?.row ?? 0;\n const direction = row >= currentRow ? 1 : -1;\n // Search in direction\n let candidate = r;\n while (candidate >= 0 && candidate < totalRows && !isNavigable(candidate)) {\n candidate += direction;\n }\n if (candidate >= 0 && candidate < totalRows) {\n r = candidate;\n } else {\n // Try opposite direction\n candidate = r;\n while (candidate >= 0 && candidate < totalRows && !isNavigable(candidate)) {\n candidate -= direction;\n }\n if (candidate >= 0 && candidate < totalRows) {\n r = candidate;\n } else {\n return; // no navigable row found\n }\n }\n }\n }\n\n setActiveCell({ row: r, col: clampedCol });\n onScrollToCell?.(r, clampedCol);\n },\n [onScrollToCell, isNavigable, activeCell?.row],\n );\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent, totalRows: number, totalCols: number) => {\n if (!activeCell) {\n // If no cell is active and user presses arrow, activate first cell\n if (\n [\"ArrowDown\", \"ArrowUp\", \"ArrowLeft\", \"ArrowRight\"].includes(e.key)\n ) {\n e.preventDefault();\n moveTo(0, 0, totalRows, totalCols);\n }\n return;\n }\n\n const { row, col } = activeCell;\n const PAGE_SIZE = 20;\n\n switch (e.key) {\n case \"ArrowDown\":\n e.preventDefault();\n moveTo(row + 1, col, totalRows, totalCols);\n break;\n case \"ArrowUp\":\n e.preventDefault();\n moveTo(row - 1, col, totalRows, totalCols);\n break;\n case \"ArrowRight\":\n e.preventDefault();\n moveTo(row, col + 1, totalRows, totalCols);\n break;\n case \"ArrowLeft\":\n e.preventDefault();\n moveTo(row, col - 1, totalRows, totalCols);\n break;\n case \"Tab\":\n e.preventDefault();\n if (e.shiftKey) {\n if (col > 0) {\n moveTo(row, col - 1, totalRows, totalCols);\n } else if (row > 0) {\n moveTo(row - 1, totalCols - 1, totalRows, totalCols);\n }\n } else {\n if (col < totalCols - 1) {\n moveTo(row, col + 1, totalRows, totalCols);\n } else if (row < totalRows - 1) {\n moveTo(row + 1, 0, totalRows, totalCols);\n }\n }\n break;\n case \"Home\":\n e.preventDefault();\n if (e.ctrlKey) {\n moveTo(0, 0, totalRows, totalCols);\n } else {\n moveTo(row, 0, totalRows, totalCols);\n }\n break;\n case \"End\":\n e.preventDefault();\n if (e.ctrlKey) {\n moveTo(totalRows - 1, totalCols - 1, totalRows, totalCols);\n } else {\n moveTo(row, totalCols - 1, totalRows, totalCols);\n }\n break;\n case \"PageDown\":\n e.preventDefault();\n moveTo(row + PAGE_SIZE, col, totalRows, totalCols);\n break;\n case \"PageUp\":\n e.preventDefault();\n moveTo(row - PAGE_SIZE, col, totalRows, totalCols);\n break;\n case \"Escape\":\n e.preventDefault();\n setActiveCell(null);\n break;\n }\n },\n [activeCell, moveTo],\n );\n\n const handleCellClick = useCallback((row: number, col: number) => {\n setActiveCell({ row, col });\n }, []);\n\n return {\n activeCell,\n setActiveCell,\n handleKeyDown,\n handleCellClick,\n };\n}\n","import { useState, useCallback, useEffect, useRef } from \"react\";\n\nconst SEARCH_DEBOUNCE_MS = 300;\n\nexport interface SearchState {\n /** Raw input text (updates immediately on keystroke). */\n searchText: string;\n /** Debounced search text (updates after delay). */\n debouncedSearch: string;\n /** Input change handler. */\n handleSearchChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n /** Clear search text and debounced value. */\n clearSearch: () => void;\n /** Reset search (e.g. when file changes). */\n resetSearch: () => void;\n}\n\n/**\n * Manages search input state with debouncing.\n * Search is used for highlighting matching cells — not for filtering rows.\n */\nexport function useSearch(): SearchState {\n const [searchText, setSearchText] = useState(\"\");\n const [debouncedSearch, setDebouncedSearch] = useState(\"\");\n const timerRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const val = e.target.value;\n setSearchText(val);\n if (timerRef.current) clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setDebouncedSearch(val), SEARCH_DEBOUNCE_MS);\n }, []);\n\n const clearSearch = useCallback(() => {\n setSearchText(\"\");\n setDebouncedSearch(\"\");\n if (timerRef.current) clearTimeout(timerRef.current);\n }, []);\n\n const resetSearch = useCallback(() => {\n setSearchText(\"\");\n setDebouncedSearch(\"\");\n if (timerRef.current) clearTimeout(timerRef.current);\n }, []);\n\n // Cleanup timer on unmount\n useEffect(() => () => {\n if (timerRef.current) clearTimeout(timerRef.current);\n }, []);\n\n return { searchText, debouncedSearch, handleSearchChange, clearSearch, resetSearch };\n}\n","import { useCallback, useRef } from \"react\";\nimport type { PipelineState } from \"@parqui/core\";\nimport { PipelineChip } from \"./PipelineChip.js\";\nimport { FolderOpenIcon, FileIcon, CloseIcon, SearchIcon } from \"./Icons.js\";\nimport { formatFilterValue } from \"../utils/formatting.js\";\nimport { s } from \"../styles.js\";\n\nexport interface ToolbarProps {\n allowOpen: boolean;\n hasSource: boolean;\n fileName: string;\n pipeline: PipelineState;\n\n // Search\n searchText: string;\n onSearchChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n onClearSearch: () => void;\n\n // File actions\n onRequestOpen?: () => void | Promise<void>;\n onFileSelect: (file: File) => void;\n onClose: () => void;\n\n // Pipeline chip actions\n onRemoveSort: (column: string) => void;\n onRemoveFilter: (column: string) => void;\n onRemoveGroup: (column: string) => void;\n}\n\nexport function Toolbar({\n allowOpen,\n hasSource,\n fileName,\n pipeline,\n searchText,\n onSearchChange,\n onClearSearch,\n onRequestOpen,\n onFileSelect,\n onClose,\n onRemoveSort,\n onRemoveFilter,\n onRemoveGroup,\n}: ToolbarProps) {\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const handleOpenClick = useCallback(() => {\n if (onRequestOpen) {\n void onRequestOpen();\n } else {\n fileInputRef.current?.click();\n }\n }, [onRequestOpen]);\n\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const f = e.target.files?.[0];\n if (f) onFileSelect(f);\n e.target.value = \"\";\n },\n [onFileSelect],\n );\n\n return (\n <div style={s.toolbar}>\n {/* Left zone: Open + filename/close + group/sort chips */}\n <div style={s.toolbarFileZone}>\n {allowOpen && (\n <>\n <button\n type=\"button\"\n onClick={handleOpenClick}\n className=\"parqui-toolbar-open\"\n style={s.openButton}\n title=\"Open file (Ctrl+O)\"\n aria-label=\"Open file\"\n >\n <FolderOpenIcon />\n <span>Open</span>\n </button>\n {!onRequestOpen && (\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".parquet\"\n style={{ display: \"none\" }}\n onChange={handleInputChange}\n />\n )}\n </>\n )}\n\n {hasSource && (\n <>\n {allowOpen && <div style={s.separator} />}\n <span style={s.fileIcon}>\n <FileIcon />\n </span>\n <span style={s.fileName}>{fileName}</span>\n {allowOpen && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"parqui-close-btn\"\n style={s.closeButton}\n title=\"Close file\"\n aria-label=\"Close file\"\n >\n <CloseIcon />\n </button>\n )}\n\n {/* Group & sort chips */}\n {(pipeline.groups.length > 0 || pipeline.sorts.length > 0) && (\n <>\n <div style={s.separator} />\n <div style={s.chipsScroll} className=\"parqui-chips-scroll\">\n {pipeline.groups.map((g) => (\n <PipelineChip\n key={`group-${g.column}`}\n label={`\\u229e ${g.column}`}\n color=\"green\"\n onRemove={() => onRemoveGroup(g.column)}\n />\n ))}\n {pipeline.sorts.map((sort) => (\n <PipelineChip\n key={`sort-${sort.column}`}\n label={`${sort.column} ${sort.direction === \"asc\" ? \"\\u2191\" : \"\\u2193\"}`}\n color=\"blue\"\n onRemove={() => onRemoveSort(sort.column)}\n />\n ))}\n </div>\n </>\n )}\n </>\n )}\n </div>\n\n {/* Right zone: filter chips + search */}\n {hasSource && (\n <div style={s.toolbarPipeline}>\n {pipeline.filters.length > 0 && (\n <div style={{ ...s.chipsScroll, flex: \"none\" }} className=\"parqui-chips-scroll\">\n {pipeline.filters.map((f) => (\n <PipelineChip\n key={`filter-${f.column}`}\n label={`${f.column}: ${formatFilterValue(f.value)}`}\n color=\"amber\"\n onRemove={() => onRemoveFilter(f.column)}\n />\n ))}\n </div>\n )}\n <div style={s.searchWrapper}>\n <SearchIcon />\n <input\n type=\"text\"\n value={searchText}\n onChange={onSearchChange}\n placeholder=\"Search\"\n className=\"parqui-search-input\"\n style={s.searchInput}\n aria-label=\"Search cell values\"\n />\n {searchText && (\n <button\n type=\"button\"\n onClick={onClearSearch}\n style={s.searchClear}\n aria-label=\"Clear search\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </div>\n )}\n </div>\n );\n}\n","export function FolderOpenIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n\nexport function FileIcon() {\n return (\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n );\n}\n\nexport function CloseIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\nexport function SearchIcon() {\n return (\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" style={{ flexShrink: 0, color: \"#94a3b8\" }}>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n );\n}\n\nexport function ChipCloseIcon() {\n return (\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n","import { ChipCloseIcon } from \"./Icons.js\";\n\nconst chipColors = {\n blue: { bg: \"#eff6ff\", border: \"#bfdbfe\", text: \"#1e40af\" },\n amber: { bg: \"#fffbeb\", border: \"#fde68a\", text: \"#92400e\" },\n green: { bg: \"#ecfdf5\", border: \"#a7f3d0\", text: \"#065f46\" },\n} as const;\n\nexport function PipelineChip({\n label,\n color,\n onRemove,\n}: {\n label: string;\n color: \"blue\" | \"amber\" | \"green\";\n onRemove: () => void;\n}) {\n const c = chipColors[color];\n return (\n <span\n className=\"parqui-chip\"\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 4,\n padding: \"2px 4px 2px 8px\",\n fontSize: 11,\n fontWeight: 600,\n color: c.text,\n backgroundColor: c.bg,\n border: `1px solid ${c.border}`,\n borderRadius: 5,\n whiteSpace: \"nowrap\",\n cursor: \"default\",\n transition: \"background-color 0.15s, border-color 0.15s\",\n }}\n >\n <span style={{ overflow: \"hidden\", textOverflow: \"ellipsis\", maxWidth: 160 }}>\n {label}\n </span>\n <button\n type=\"button\"\n className=\"parqui-chip-remove\"\n onClick={onRemove}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 16,\n height: 16,\n border: \"none\",\n backgroundColor: \"transparent\",\n color: c.text,\n borderRadius: 3,\n cursor: \"pointer\",\n padding: 0,\n flexShrink: 0,\n transition: \"background-color 0.15s\",\n }}\n aria-label={`Remove ${label}`}\n >\n <ChipCloseIcon />\n </button>\n </span>\n );\n}\n","import type React from \"react\";\nimport { createElement } from \"react\";\n\n/** Format a cell value for display. */\nexport function formatCell(value: unknown): string {\n if (value === null || value === undefined) return \"\\u2205\";\n if (typeof value === \"object\") return JSON.stringify(value);\n return String(value);\n}\n\n/** Format a filter value for chip display. */\nexport function formatFilterValue(value: unknown): string {\n if (Array.isArray(value)) {\n if (value.length <= 3) return value.map(String).join(\", \");\n return `${value.slice(0, 3).map(String).join(\", \")} +${value.length - 3}`;\n }\n if (value === null || value === undefined) return \"\\u2205\";\n return String(value);\n}\n\n/**\n * Render a cell value with optional search term highlighting.\n * Returns a plain string when no match, or a React element with <mark> tags.\n */\nexport function highlightCell(value: unknown, searchText?: string): React.ReactNode {\n const text = formatCell(value);\n if (!searchText || !searchText.trim()) return text;\n\n const needle = searchText.trim().toLowerCase();\n const lowerText = text.toLowerCase();\n const idx = lowerText.indexOf(needle);\n if (idx === -1) return text;\n\n const parts: React.ReactNode[] = [];\n let cursor = 0;\n let pos = idx;\n let key = 0;\n while (pos !== -1) {\n if (pos > cursor) parts.push(text.slice(cursor, pos));\n parts.push(\n createElement(\"mark\", { key: key++, className: \"parqui-search-highlight\" }, text.slice(pos, pos + needle.length)),\n );\n cursor = pos + needle.length;\n pos = lowerText.indexOf(needle, cursor);\n }\n if (cursor < text.length) parts.push(text.slice(cursor));\n return createElement(\"span\", null, ...parts);\n}\n\n/** Check if any column value in a row matches the search needle. */\nexport function rowMatchesSearch(row: Record<string, unknown>, needle: string): boolean {\n for (const key in row) {\n const val = row[key];\n if (val === null || val === undefined) continue;\n const str = typeof val === \"object\" ? JSON.stringify(val) : String(val);\n if (str.toLowerCase().includes(needle)) return true;\n }\n return false;\n}\n","import type React from \"react\";\n\n/** Global CSS injected once into the document. */\nexport const PARKUI_CSS = `\n.parqui-toolbar-open:hover {\n background-color: #1e40af;\n border-color: #1e3a8a;\n}\n.parqui-toolbar-open:focus-visible {\n outline: 2px solid #93c5fd;\n outline-offset: 2px;\n}\n.parqui-toolbar-icon:hover {\n background-color: #eef3f9;\n color: #111827;\n border-color: #c7d1dd;\n}\n.parqui-toolbar-icon:focus-visible {\n outline: 2px solid #93c5fd;\n outline-offset: 1px;\n}\n.parqui-close-btn:hover {\n background-color: #fee2e2;\n color: #dc2626;\n}\n.parqui-chip:hover {\n background-color: #dbeafe;\n border-color: #93c5fd;\n}\n.parqui-chip-remove:hover {\n background-color: #bfdbfe;\n color: #1e40af;\n}\n.parqui-search-input:focus {\n border-color: #93c5fd;\n outline: none;\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.15);\n}\n.parqui-chips-scroll::-webkit-scrollbar {\n display: none;\n}\n@keyframes parqui-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n.parqui-grid-scrollbar::-webkit-scrollbar {\n width: 10px;\n height: 10px;\n}\n.parqui-grid-scrollbar::-webkit-scrollbar-track {\n background: #e9edf2;\n}\n.parqui-grid-scrollbar::-webkit-scrollbar-thumb {\n background: #b0bccb;\n border-radius: 999px;\n border: 2px solid #e9edf2;\n}\n.parqui-grid-scrollbar::-webkit-scrollbar-thumb:hover {\n background: #8ea0b6;\n}\n.parqui-grid-header-cell:hover {\n background: #edf2f7;\n color: #111827;\n}\n.parqui-grid-header-cell:hover .parqui-grid-header-label {\n color: #111827;\n}\n.parqui-grid-row:hover .parqui-grid-cell,\n.parqui-grid-row:hover .parqui-grid-row-num {\n background-color: #f0f4fa;\n}\n.parqui-grid-row .parqui-grid-cell {\n background-color: #ffffff;\n}\n.parqui-grid-row .parqui-grid-row-num {\n background-color: #f6f8fb;\n}\n.parqui-grid-row.parqui-grid-row-selected .parqui-grid-cell,\n.parqui-grid-row.parqui-grid-row-selected .parqui-grid-row-num {\n background-color: #e9f0fb;\n}\n.parqui-grid-group-header {\n background-color: #edf2f7;\n}\n.parqui-grid-group-header:hover {\n background-color: #e2ebf7;\n}\n.parqui-search-highlight {\n background-color: #fde68a;\n color: inherit;\n padding: 0;\n margin: 0;\n border-radius: 0;\n line-height: inherit;\n font-size: inherit;\n}\n`;\n\nexport const s: Record<string, React.CSSProperties> = {\n root: {\n fontFamily: \"'Plus Jakarta Sans', 'Inter', system-ui, sans-serif\",\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: \"#f3f5f8\",\n color: \"#1f2937\",\n overflow: \"hidden\",\n },\n toolbar: {\n display: \"flex\",\n alignItems: \"center\",\n padding: \"0 10px\",\n height: 40,\n userSelect: \"none\",\n flexShrink: 0,\n backgroundColor: \"#ffffff\",\n borderBottom: \"1px solid #d9e0ea\",\n gap: 0,\n },\n toolbarFileZone: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n flexShrink: 0,\n },\n toolbarPipeline: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n flex: 1,\n minWidth: 0,\n marginLeft: 12,\n justifyContent: \"flex-end\",\n },\n chipsScroll: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 5,\n flex: 1,\n minWidth: 0,\n overflowX: \"auto\",\n overflowY: \"hidden\",\n scrollbarWidth: \"none\",\n },\n searchWrapper: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"0 8px\",\n border: \"1px solid #d9e0ea\",\n borderRadius: 7,\n height: 28,\n backgroundColor: \"#f9fafb\",\n flexShrink: 0,\n minWidth: 160,\n maxWidth: 260,\n },\n searchInput: {\n border: \"none\",\n background: \"transparent\",\n outline: \"none\",\n fontSize: 12,\n color: \"#1f2937\",\n fontFamily: \"inherit\",\n width: \"100%\",\n padding: 0,\n },\n searchClear: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 16,\n height: 16,\n border: \"none\",\n backgroundColor: \"transparent\",\n color: \"#94a3b8\",\n cursor: \"pointer\",\n padding: 0,\n flexShrink: 0,\n borderRadius: 3,\n },\n openButton: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"0 12px\",\n fontSize: 12,\n fontWeight: 700,\n fontFamily: \"inherit\",\n color: \"#ffffff\",\n backgroundColor: \"#1d4ed8\",\n border: \"1px solid #1e40af\",\n borderRadius: 7,\n cursor: \"pointer\",\n whiteSpace: \"nowrap\",\n flexShrink: 0,\n height: 28,\n transition: \"background-color 0.15s, border-color 0.15s\",\n boxShadow: \"none\",\n },\n separator: {\n width: 1,\n height: 18,\n backgroundColor: \"#dce3ed\",\n margin: \"0 6px\",\n flexShrink: 0,\n },\n fileIcon: {\n flexShrink: 0,\n color: \"#64748b\",\n display: \"flex\",\n alignItems: \"center\",\n },\n fileName: {\n fontSize: 12,\n fontWeight: 600,\n color: \"#111827\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n maxWidth: 200,\n },\n closeButton: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 20,\n height: 20,\n border: \"none\",\n borderRadius: 4,\n backgroundColor: \"transparent\",\n color: \"#94a3b8\",\n cursor: \"pointer\",\n flexShrink: 0,\n padding: 0,\n transition: \"background-color 0.15s, color 0.15s\",\n marginLeft: 2,\n },\n content: {\n flex: 1,\n minHeight: 0,\n display: \"flex\",\n flexDirection: \"column\",\n fontSize: 13,\n outline: \"none\",\n position: \"relative\",\n },\n placeholder: {\n padding: 40,\n textAlign: \"center\",\n color: \"#6b7280\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flex: 1,\n },\n error: {\n padding: 20,\n color: \"#dc2626\",\n textAlign: \"center\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flex: 1,\n },\n dropZoneWrapper: {\n flex: 1,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n scrollContainer: {\n overflow: \"auto\",\n flex: 1,\n minHeight: 0,\n position: \"relative\",\n backgroundColor: \"#f7f9fc\",\n },\n headerRow: {\n display: \"flex\",\n position: \"sticky\",\n top: 0,\n zIndex: 2,\n backgroundColor: \"#ffffff\",\n boxShadow: \"0 1px 0 #d8e0ea\",\n },\n rowNumHeader: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"#f3f5f8\",\n borderBottom: \"1px solid #d9e0ea\",\n borderRight: \"1px solid #d9e0ea\",\n fontWeight: 600,\n fontSize: 12,\n color: \"#6b7280\",\n flexShrink: 0,\n boxSizing: \"border-box\",\n },\n groupHeader: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n padding: \"0 12px\",\n borderBottom: \"1px solid #d8e0ea\",\n cursor: \"pointer\",\n userSelect: \"none\",\n fontSize: 13,\n fontWeight: 600,\n boxSizing: \"border-box\",\n },\n groupChevron: {\n fontSize: 12,\n color: \"#4b5563\",\n width: 12,\n },\n groupLabel: {\n color: \"#1f2937\",\n },\n groupCount: {\n color: \"#6b7280\",\n fontSize: 12,\n },\n row: {\n display: \"flex\",\n borderBottom: \"1px solid #e5eaf1\",\n boxSizing: \"border-box\",\n backgroundColor: \"#ffffff\",\n },\n rowNum: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"flex-end\",\n padding: \"0 8px\",\n borderRight: \"1px solid #dfe6ef\",\n fontSize: 11,\n color: \"#6b7280\",\n flexShrink: 0,\n boxSizing: \"border-box\",\n userSelect: \"none\",\n },\n cell: {\n display: \"flex\",\n alignItems: \"center\",\n padding: \"0 12px\",\n borderRight: \"1px solid #e8edf3\",\n overflow: \"hidden\",\n whiteSpace: \"nowrap\",\n textOverflow: \"ellipsis\",\n cursor: \"default\",\n flexShrink: 0,\n boxSizing: \"border-box\",\n color: \"#1f2937\",\n },\n cellActive: {\n outline: \"2px solid #2563eb\",\n outlineOffset: -2,\n backgroundColor: \"#e8f1ff\",\n zIndex: 1,\n },\n cellSkeleton: {\n width: \"60%\",\n height: 8,\n borderRadius: 3,\n background:\n \"linear-gradient(90deg, #e6ebf2 25%, #f1f4f8 50%, #e6ebf2 75%)\",\n backgroundSize: \"200% 100%\",\n animation: \"parqui-shimmer 1.5s ease-in-out infinite\",\n opacity: 0.7,\n },\n};\n","import { useEffect, useMemo, useCallback, useRef } from \"react\";\nimport type { GroupNode, ParquetRow } from \"@parqui/core\";\nimport type { ColumnDef, DragState, ResizeState } from \"../hooks/useColumnManager.js\";\nimport type { VirtualScroll } from \"../hooks/useVirtualScroll.js\";\nimport { HEADER_HEIGHT } from \"../hooks/useVirtualScroll.js\";\nimport type { CellPosition, KeyboardNavigation } from \"../hooks/useKeyboardNavigation.js\";\nimport { ColumnHeader, ColumnDropEndZone } from \"./ColumnHeader.js\";\nimport { ParquiLogo } from \"./ParquiLogo.js\";\nimport { VirtualRow } from \"./VirtualRow.js\";\nimport { GroupHeaderRow } from \"./GroupHeaderRow.js\";\nimport { s } from \"../styles.js\";\n\n// ── Flat list types for grouped view ──\n\ntype FlatItem =\n | { type: \"header\"; groupIndex: number }\n | { type: \"row\"; displayIndex: number };\n\nfunction buildFlatItems(groups: GroupNode[]): FlatItem[] {\n const items: FlatItem[] = [];\n for (let gi = 0; gi < groups.length; gi++) {\n items.push({ type: \"header\", groupIndex: gi });\n if (groups[gi].expanded) {\n for (const displayIdx of groups[gi].rowIndices) {\n items.push({ type: \"row\", displayIndex: displayIdx });\n }\n }\n }\n return items;\n}\n\n// ── Props ──\n\nexport interface DataGridProps {\n // Virtual scroll\n vScroll: VirtualScroll;\n scrollRowCount: number;\n\n // Columns\n visibleColumns: ColumnDef[];\n totalColWidth: number;\n rowNumWidth: number;\n\n // Data\n getRow: (displayIndex: number) => ParquetRow | undefined;\n ensureRange: (start: number, end: number) => void;\n ensureIndices: (displayIndices: number[]) => void;\n renderTick: number;\n\n // Pipeline\n groups: GroupNode[];\n isGrouped: boolean;\n computing: boolean;\n toggleGroupExpanded: (index: number) => void;\n\n // Column management\n dragState: DragState;\n resizeState: ResizeState;\n onDragStart: (key: string) => void;\n onDragOver: (overKey: string, mouseXInColumn: number, columnWidth: number) => void;\n onDragOverEnd: () => void;\n onDragEnd: () => void;\n onResizeStart: (key: string, clientX: number) => void;\n onUpdateResize: (clientX: number) => void;\n onEndResize: () => void;\n\n // Sort & filter display\n getSortDirection: (column: string) => import(\"@parqui/core\").SortDirection | null;\n getSortPriority: (column: string) => number | null;\n getFilter: (column: string) => import(\"@parqui/core\").FilterDef | undefined;\n isColumnGrouped: (column: string) => boolean;\n onSortClick: (column: string, multi: boolean) => void;\n onContextMenu: (column: string, x: number, y: number) => void;\n\n // Keyboard\n keyboard: KeyboardNavigation;\n\n // Search (highlighting only)\n searchText?: string;\n}\n\nexport function DataGrid({\n vScroll,\n scrollRowCount,\n visibleColumns,\n totalColWidth,\n rowNumWidth,\n getRow,\n ensureRange,\n ensureIndices,\n renderTick,\n groups,\n isGrouped,\n computing,\n toggleGroupExpanded,\n dragState,\n resizeState,\n onDragStart,\n onDragOver,\n onDragOverEnd,\n onDragEnd,\n onResizeStart,\n onUpdateResize,\n onEndResize,\n getSortDirection,\n getSortPriority,\n getFilter,\n isColumnGrouped,\n onSortClick,\n onContextMenu,\n keyboard,\n searchText,\n}: DataGridProps) {\n // ── Grouped view: flat item list ──\n const flatItems = useMemo(() => {\n if (!isGrouped) return null;\n return buildFlatItems(groups);\n }, [isGrouped, groups]);\n\n // ── Load visible rows ──\n useEffect(() => {\n if (scrollRowCount === 0 || computing) return;\n\n if (flatItems) {\n const displayIndices: number[] = [];\n for (let i = vScroll.startIndex; i < vScroll.endIndex && i < flatItems.length; i++) {\n const item = flatItems[i];\n if (item.type === \"row\") displayIndices.push(item.displayIndex);\n }\n if (displayIndices.length > 0) ensureIndices(displayIndices);\n } else {\n ensureRange(vScroll.startIndex, vScroll.endIndex);\n }\n }, [vScroll.startIndex, vScroll.endIndex, scrollRowCount, renderTick, flatItems, computing, ensureRange, ensureIndices]);\n\n // ── Global mousemove/mouseup for column resizing ──\n useEffect(() => {\n if (!resizeState.columnKey) return;\n const handleMouseMove = (e: MouseEvent) => onUpdateResize(e.clientX);\n const handleMouseUp = () => onEndResize();\n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseup\", handleMouseUp);\n return () => {\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [resizeState.columnKey, onUpdateResize, onEndResize]);\n\n const totalWidth = totalColWidth + rowNumWidth;\n\n return (\n <div\n ref={vScroll.scrollRef}\n onScroll={vScroll.onScroll}\n style={s.scrollContainer}\n className=\"parqui-grid-scrollbar\"\n >\n {/* Header row */}\n <div\n style={{\n ...s.headerRow,\n width: totalWidth,\n minWidth: \"100%\",\n }}\n >\n <div\n style={{\n ...s.rowNumHeader,\n width: rowNumWidth,\n minWidth: rowNumWidth,\n height: HEADER_HEIGHT,\n }}\n >\n <ParquiLogo size={18} color=\"#64748b\" />\n </div>\n {visibleColumns.map((col, idx) => (\n <ColumnHeader\n key={col.key}\n column={col}\n visibleIndex={idx}\n dragState={dragState}\n sortDirection={getSortDirection(col.key)}\n sortPriority={getSortPriority(col.key)}\n hasFilter={!!getFilter(col.key)}\n isGrouped={isColumnGrouped(col.key)}\n onDragStart={onDragStart}\n onDragOver={onDragOver}\n onDragEnd={onDragEnd}\n onResizeStart={onResizeStart}\n onSortClick={onSortClick}\n onContextMenu={onContextMenu}\n />\n ))}\n <ColumnDropEndZone\n dragState={dragState}\n totalColumns={visibleColumns.length}\n onDragOverEnd={onDragOverEnd}\n onDragEnd={onDragEnd}\n />\n </div>\n\n {/* Virtual body */}\n <div\n style={{\n height: vScroll.totalHeight,\n position: \"relative\",\n width: totalWidth,\n minWidth: \"100%\",\n }}\n >\n <div\n style={{\n position: \"absolute\",\n top: vScroll.offsetY,\n left: 0,\n right: 0,\n }}\n >\n {flatItems\n ? renderFlatItems(\n flatItems, groups, vScroll.startIndex, vScroll.endIndex,\n visibleColumns, getRow, rowNumWidth,\n keyboard.activeCell, keyboard.handleCellClick,\n toggleGroupExpanded, totalWidth, searchText,\n )\n : renderRows(\n vScroll.startIndex, vScroll.endIndex,\n visibleColumns, getRow, rowNumWidth,\n keyboard.activeCell, keyboard.handleCellClick,\n searchText,\n )\n }\n </div>\n </div>\n </div>\n );\n}\n\n// ── Row rendering (non-grouped) ──\n\nfunction renderRows(\n start: number,\n end: number,\n columns: ColumnDef[],\n getRow: (index: number) => Record<string, unknown> | undefined,\n rowNumWidth: number,\n activeCell: CellPosition | null,\n onCellClick: (row: number, col: number) => void,\n searchText?: string,\n) {\n const rows: React.ReactNode[] = [];\n for (let i = start; i < end; i++) {\n rows.push(\n <VirtualRow\n key={i}\n flatIndex={i}\n displayIndex={i}\n columns={columns}\n row={getRow(i)}\n rowNumWidth={rowNumWidth}\n isActiveRow={activeCell?.row === i}\n activeCol={activeCell?.row === i ? activeCell.col : -1}\n onCellClick={onCellClick}\n searchText={searchText}\n />,\n );\n }\n return rows;\n}\n\n// ── Row rendering (grouped — flat list) ──\n\nfunction renderFlatItems(\n flatItems: FlatItem[],\n groups: GroupNode[],\n start: number,\n end: number,\n columns: ColumnDef[],\n getRow: (index: number) => Record<string, unknown> | undefined,\n rowNumWidth: number,\n activeCell: CellPosition | null,\n onCellClick: (row: number, col: number) => void,\n onToggleGroup: (groupIndex: number) => void,\n totalWidth: number,\n searchText?: string,\n) {\n const items: React.ReactNode[] = [];\n for (let i = start; i < end && i < flatItems.length; i++) {\n const item = flatItems[i];\n if (item.type === \"header\") {\n const group = groups[item.groupIndex];\n items.push(\n <GroupHeaderRow\n key={`gh-${item.groupIndex}`}\n group={group}\n groupIndex={item.groupIndex}\n onToggle={onToggleGroup}\n totalWidth={totalWidth}\n />,\n );\n } else {\n items.push(\n <VirtualRow\n key={`r-${item.displayIndex}`}\n flatIndex={i}\n displayIndex={item.displayIndex}\n columns={columns}\n row={getRow(item.displayIndex)}\n rowNumWidth={rowNumWidth}\n isActiveRow={activeCell?.row === i}\n activeCol={activeCell?.row === i ? activeCell.col : -1}\n onCellClick={onCellClick}\n searchText={searchText}\n />,\n );\n }\n }\n return items;\n}\n","import { useCallback, useRef } from \"react\";\nimport type { ColumnDef, DragState } from \"../hooks/useColumnManager.js\";\nimport type { SortDirection } from \"@parqui/core\";\nimport { HEADER_HEIGHT } from \"../hooks/useVirtualScroll.js\";\n\ninterface ColumnHeaderProps {\n column: ColumnDef;\n /** Index of this column among visible columns */\n visibleIndex: number;\n dragState: DragState;\n /** Current sort direction */\n sortDirection: SortDirection | null;\n /** Sort priority (1-based) for multi-column sort, null if not sorted */\n sortPriority: number | null;\n /** Whether a filter is active on this column */\n hasFilter: boolean;\n /** Whether this column is grouped */\n isGrouped: boolean;\n onDragStart: (key: string) => void;\n onDragOver: (\n overKey: string,\n mouseXInColumn: number,\n columnWidth: number,\n ) => void;\n onDragEnd: () => void;\n onResizeStart: (key: string, clientX: number) => void;\n /** Left-click on header — toggle sort */\n onSortClick: (column: string, multi: boolean) => void;\n /** Right-click on header — open context menu */\n onContextMenu: (column: string, x: number, y: number) => void;\n}\n\nexport function ColumnHeader({\n column,\n visibleIndex,\n dragState,\n sortDirection,\n sortPriority,\n hasFilter,\n isGrouped,\n onDragStart,\n onDragOver,\n onDragEnd,\n onResizeStart,\n onSortClick,\n onContextMenu,\n}: ColumnHeaderProps) {\n const cellRef = useRef<HTMLDivElement>(null);\n\n const isDragging = dragState.dragKey === column.key;\n\n const showLeftIndicator =\n dragState.dragKey !== null &&\n dragState.dragKey !== column.key &&\n dragState.insertIndex === visibleIndex;\n\n const showRightIndicator =\n dragState.dragKey !== null &&\n dragState.dragKey !== column.key &&\n dragState.insertIndex === visibleIndex + 1;\n\n const handleDragStart = useCallback(\n (e: React.DragEvent) => {\n e.dataTransfer.effectAllowed = \"move\";\n e.dataTransfer.setData(\"text/plain\", column.key);\n onDragStart(column.key);\n },\n [column.key, onDragStart],\n );\n\n const handleDragOver = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = \"move\";\n const rect = cellRef.current?.getBoundingClientRect();\n if (rect) {\n const mouseXInColumn = e.clientX - rect.left;\n onDragOver(column.key, mouseXInColumn, rect.width);\n }\n },\n [column.key, onDragOver],\n );\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n onDragEnd();\n },\n [onDragEnd],\n );\n\n const handleNativeDragEnd = useCallback(() => {\n onDragEnd();\n }, [onDragEnd]);\n\n const handleResizeMouseDown = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onResizeStart(column.key, e.clientX);\n },\n [column.key, onResizeStart],\n );\n\n const handleClick = useCallback(\n (e: React.MouseEvent) => {\n // Don't trigger sort if user is resizing\n if ((e.target as HTMLElement).dataset.resize) return;\n onSortClick(column.key, e.ctrlKey || e.metaKey);\n },\n [column.key, onSortClick],\n );\n\n const handleContextMenu = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n onContextMenu(column.key, e.clientX, e.clientY);\n },\n [column.key, onContextMenu],\n );\n\n return (\n <div\n ref={cellRef}\n className=\"parqui-grid-header-cell\"\n draggable\n onDragStart={handleDragStart}\n onDragOver={handleDragOver}\n onDrop={handleDrop}\n onDragEnd={handleNativeDragEnd}\n onClick={handleClick}\n onContextMenu={handleContextMenu}\n style={{\n ...headerStyles.cell,\n width: column.width,\n minWidth: column.width,\n maxWidth: column.width,\n height: HEADER_HEIGHT,\n opacity: isDragging ? 0.4 : 1,\n }}\n title={column.key}\n >\n {/* Left insertion indicator */}\n {showLeftIndicator && <div style={headerStyles.indicatorLeft} />}\n {/* Right insertion indicator */}\n {showRightIndicator && <div style={headerStyles.indicatorRight} />}\n\n {/* Column label + indicators */}\n <span style={headerStyles.label} className=\"parqui-grid-header-label\">{column.key}</span>\n\n {/* Status indicators area */}\n <span style={headerStyles.indicators}>\n {/* Filter dot */}\n {hasFilter && <span style={headerStyles.filterDot} />}\n\n {/* Group icon */}\n {isGrouped && <span style={headerStyles.groupIcon}>▦</span>}\n\n {/* Sort arrow */}\n {sortDirection && (\n <span style={headerStyles.sortArrow}>\n {sortDirection === \"asc\" ? \"↑\" : \"↓\"}\n {sortPriority !== null && sortPriority > 1 && (\n <span style={headerStyles.sortPriority}>{sortPriority}</span>\n )}\n </span>\n )}\n </span>\n\n {/* Resize handle */}\n <div\n data-resize=\"true\"\n onMouseDown={handleResizeMouseDown}\n style={headerStyles.resizeHandle}\n role=\"separator\"\n aria-orientation=\"vertical\"\n />\n </div>\n );\n}\n\n/**\n * A trailing drop zone rendered after the last column header.\n */\nexport function ColumnDropEndZone({\n dragState,\n totalColumns,\n onDragOverEnd,\n onDragEnd,\n}: {\n dragState: DragState;\n totalColumns: number;\n onDragOverEnd: () => void;\n onDragEnd: () => void;\n}) {\n const showIndicator =\n dragState.dragKey !== null && dragState.insertIndex === totalColumns;\n\n const handleDragOver = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = \"move\";\n onDragOverEnd();\n },\n [onDragOverEnd],\n );\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n onDragEnd();\n },\n [onDragEnd],\n );\n\n if (!dragState.dragKey) return null;\n\n return (\n <div\n onDragOver={handleDragOver}\n onDrop={handleDrop}\n style={headerStyles.endZone}\n >\n {showIndicator && <div style={headerStyles.indicatorLeft} />}\n </div>\n );\n}\n\nconst headerStyles: Record<string, React.CSSProperties> = {\n cell: {\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\",\n padding: \"0 12px\",\n backgroundColor: \"#ffffff\",\n borderBottom: \"1px solid #d8e0ea\",\n borderRight: \"1px solid #d8e0ea\",\n fontWeight: 600,\n fontSize: 13,\n color: \"#334155\",\n cursor: \"pointer\",\n userSelect: \"none\",\n overflow: \"hidden\",\n flexShrink: 0,\n boxSizing: \"border-box\",\n gap: 4,\n },\n label: {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n flex: 1,\n color: \"#334155\",\n },\n indicators: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 4,\n flexShrink: 0,\n },\n sortArrow: {\n display: \"flex\",\n alignItems: \"center\",\n fontSize: 12,\n color: \"#2563eb\",\n fontWeight: 700,\n },\n sortPriority: {\n fontSize: 9,\n marginLeft: 1,\n },\n filterDot: {\n width: 5,\n height: 5,\n borderRadius: \"50%\",\n backgroundColor: \"#0ea5e9\",\n },\n groupIcon: {\n fontSize: 11,\n color: \"#2563eb\",\n },\n resizeHandle: {\n position: \"absolute\",\n right: 0,\n top: 0,\n bottom: 0,\n width: 6,\n cursor: \"col-resize\",\n zIndex: 2,\n backgroundColor: \"transparent\",\n },\n indicatorLeft: {\n position: \"absolute\",\n left: 0,\n top: 0,\n bottom: 0,\n width: 3,\n backgroundColor: \"#2563eb\",\n zIndex: 3,\n borderRadius: \"2px 0 0 2px\",\n },\n indicatorRight: {\n position: \"absolute\",\n right: 0,\n top: 0,\n bottom: 0,\n width: 3,\n backgroundColor: \"#2563eb\",\n zIndex: 3,\n borderRadius: \"0 2px 2px 0\",\n },\n endZone: {\n position: \"relative\",\n width: 32,\n minWidth: 32,\n flexShrink: 0,\n backgroundColor: \"#ffffff\",\n borderBottom: \"1px solid #d8e0ea\",\n },\n};\n","import { useId } from \"react\";\n\nexport interface ParquiLogoProps {\n size?: number;\n color?: string;\n style?: React.CSSProperties;\n}\n\nexport function ParquiLogo({\n size = 28,\n color = \"#50ABF1\",\n style,\n}: ParquiLogoProps) {\n const clipId = useId();\n const r = (size / 28) * 3;\n\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 28 28\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ flexShrink: 0, ...style }}\n >\n <defs>\n <clipPath id={clipId}>\n <rect width=\"28\" height=\"28\" rx={r} />\n </clipPath>\n </defs>\n <g clipPath={`url(#${clipId})`}>\n <g transform=\"rotate(45 14 14)\">\n <rect x=\"-20\" y=\"-5\" width=\"68\" height=\"10\" fill={color} />\n <rect x=\"-20\" y=\"9\" width=\"32\" height=\"10\" fill={color} />\n <rect x=\"16\" y=\"9\" width=\"32\" height=\"10\" fill={color} />\n <rect x=\"-20\" y=\"23\" width=\"68\" height=\"10\" fill={color} />\n </g>\n </g>\n </svg>\n );\n}\n\n","import type { ColumnDef } from \"../hooks/useColumnManager.js\";\nimport { ROW_HEIGHT } from \"../hooks/useVirtualScroll.js\";\nimport { highlightCell } from \"../utils/formatting.js\";\nimport { s } from \"../styles.js\";\n\ninterface VirtualRowProps {\n flatIndex: number;\n displayIndex: number;\n columns: ColumnDef[];\n row: Record<string, unknown> | undefined;\n rowNumWidth: number;\n isActiveRow: boolean;\n activeCol: number;\n onCellClick: (row: number, col: number) => void;\n searchText?: string;\n}\n\nexport function VirtualRow({\n flatIndex,\n displayIndex,\n columns,\n row,\n rowNumWidth,\n isActiveRow,\n activeCol,\n onCellClick,\n searchText,\n}: VirtualRowProps) {\n const isLoading = !row;\n\n return (\n <div\n className={`parqui-grid-row${isActiveRow ? \" parqui-grid-row-selected\" : \"\"}`}\n style={{ ...s.row, height: ROW_HEIGHT }}\n role=\"row\"\n aria-rowindex={displayIndex + 1}\n >\n <div\n className=\"parqui-grid-row-num\"\n style={{\n ...s.rowNum,\n width: rowNumWidth,\n minWidth: rowNumWidth,\n height: ROW_HEIGHT,\n }}\n >\n {displayIndex + 1}\n </div>\n {columns.map((col, colIdx) => {\n const isActive = isActiveRow && activeCol === colIdx;\n return (\n <div\n key={col.key}\n onClick={() => onCellClick(flatIndex, colIdx)}\n className=\"parqui-grid-cell\"\n style={{\n ...s.cell,\n width: col.width,\n minWidth: col.width,\n maxWidth: col.width,\n height: ROW_HEIGHT,\n ...(isActive ? s.cellActive : undefined),\n }}\n role=\"gridcell\"\n aria-colindex={colIdx + 1}\n aria-selected={isActive}\n >\n {isLoading ? (\n <div style={s.cellSkeleton} />\n ) : (\n highlightCell(row[col.key], searchText)\n )}\n </div>\n );\n })}\n </div>\n );\n}\n","import type { GroupNode } from \"@parqui/core\";\nimport { ROW_HEIGHT } from \"../hooks/useVirtualScroll.js\";\nimport { s } from \"../styles.js\";\n\nexport function GroupHeaderRow({\n group,\n groupIndex,\n onToggle,\n totalWidth,\n}: {\n group: GroupNode;\n groupIndex: number;\n onToggle: (index: number) => void;\n totalWidth: number;\n}) {\n return (\n <div\n className=\"parqui-grid-group-header\"\n style={{ ...s.groupHeader, height: ROW_HEIGHT, width: totalWidth }}\n onClick={() => onToggle(groupIndex)}\n role=\"row\"\n >\n <span style={s.groupChevron}>\n {group.expanded ? \"\\u25BE\" : \"\\u25B8\"}\n </span>\n <span style={s.groupLabel}>{group.label}</span>\n <span style={s.groupCount}>\n ({group.count.toLocaleString()})\n </span>\n </div>\n );\n}\n","import { useState, useEffect, useCallback, useRef } from \"react\";\nimport type { SortDirection, FilterDef } from \"@parqui/core\";\n\nexport interface ColumnContextMenuProps {\n /** Column name */\n column: string;\n /** Screen position */\n x: number;\n y: number;\n /** Current sort direction for this column */\n sortDirection: SortDirection | null;\n /** Current sort priority (1-based), or null */\n sortPriority: number | null;\n /** Current filter for this column */\n activeFilter: FilterDef | undefined;\n /** Whether this column is grouped */\n isGrouped: boolean;\n /** Callback to close the menu */\n onClose: () => void;\n /** Sort actions */\n onSortAsc: () => void;\n onSortDesc: () => void;\n onSortClear: () => void;\n /** Filter actions */\n onFilterSet: (filter: FilterDef) => void;\n onFilterClear: () => void;\n /** Group actions */\n onGroupToggle: () => void;\n /** Async loader for unique values */\n loadUniqueValues: () => Promise<unknown[]>;\n}\n\nexport function ColumnContextMenu({\n column,\n x,\n y,\n sortDirection,\n sortPriority,\n activeFilter,\n isGrouped,\n onClose,\n onSortAsc,\n onSortDesc,\n onSortClear,\n onFilterSet,\n onFilterClear,\n onGroupToggle,\n loadUniqueValues,\n}: ColumnContextMenuProps) {\n const [showFilterPanel, setShowFilterPanel] = useState(false);\n const [uniqueValues, setUniqueValues] = useState<unknown[] | null>(null);\n const [selectedValues, setSelectedValues] = useState<Set<string>>(new Set());\n const [filterSearch, setFilterSearch] = useState(\"\");\n const [loadingValues, setLoadingValues] = useState(false);\n const menuRef = useRef<HTMLDivElement>(null);\n\n // Close on click outside\n useEffect(() => {\n const handle = (e: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(e.target as Node)) {\n onClose();\n }\n };\n document.addEventListener(\"mousedown\", handle);\n return () => document.removeEventListener(\"mousedown\", handle);\n }, [onClose]);\n\n // Close on Escape\n useEffect(() => {\n const handle = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", handle);\n return () => document.removeEventListener(\"keydown\", handle);\n }, [onClose]);\n\n // Load unique values when filter panel opens\n useEffect(() => {\n if (showFilterPanel && uniqueValues === null && !loadingValues) {\n setLoadingValues(true);\n loadUniqueValues().then((values) => {\n setUniqueValues(values);\n // Pre-select all values if \"in\" filter is active\n if (activeFilter?.operator === \"in\" && Array.isArray(activeFilter.value)) {\n setSelectedValues(new Set(activeFilter.value.map(String)));\n } else {\n setSelectedValues(new Set(values.map((v) => String(v))));\n }\n setLoadingValues(false);\n });\n }\n }, [showFilterPanel, uniqueValues, loadingValues, loadUniqueValues, activeFilter]);\n\n const handleFilterApply = useCallback(() => {\n if (!uniqueValues) return;\n const allSelected = selectedValues.size === uniqueValues.length;\n if (allSelected) {\n onFilterClear();\n } else {\n onFilterSet({\n column,\n operator: \"in\",\n value: [...selectedValues],\n });\n }\n onClose();\n }, [column, selectedValues, uniqueValues, onFilterSet, onFilterClear, onClose]);\n\n const toggleValue = useCallback((val: string) => {\n setSelectedValues((prev) => {\n const next = new Set(prev);\n if (next.has(val)) next.delete(val);\n else next.add(val);\n return next;\n });\n }, []);\n\n const selectAll = useCallback(() => {\n if (uniqueValues) {\n setSelectedValues(new Set(uniqueValues.map((v) => String(v))));\n }\n }, [uniqueValues]);\n\n const selectNone = useCallback(() => {\n setSelectedValues(new Set());\n }, []);\n\n // Adjust position so menu doesn't go off screen\n const adjustedX = Math.min(x, window.innerWidth - 260);\n const adjustedY = Math.min(y, window.innerHeight - 400);\n\n const filteredUniqueValues = uniqueValues?.filter((v) =>\n filterSearch\n ? String(v).toLowerCase().includes(filterSearch.toLowerCase())\n : true,\n );\n\n return (\n <div\n ref={menuRef}\n style={{ ...menuStyles.overlay, left: adjustedX, top: adjustedY }}\n onContextMenu={(e) => e.preventDefault()}\n >\n <div style={menuStyles.container}>\n {/* ── Sort section ── */}\n <div style={menuStyles.sectionLabel}>Sort</div>\n <MenuItem\n active={sortDirection === \"asc\"}\n onClick={() => { onSortAsc(); onClose(); }}\n >\n <span style={menuStyles.itemIcon}>↑</span>\n Sort ascending\n {sortPriority && sortPriority > 0 && (\n <span style={menuStyles.badge}>{sortPriority}</span>\n )}\n </MenuItem>\n <MenuItem\n active={sortDirection === \"desc\"}\n onClick={() => { onSortDesc(); onClose(); }}\n >\n <span style={menuStyles.itemIcon}>↓</span>\n Sort descending\n </MenuItem>\n {sortDirection && (\n <MenuItem\n onClick={() => { onSortClear(); onClose(); }}\n >\n <span style={menuStyles.itemIcon}>✕</span>\n Clear sort\n </MenuItem>\n )}\n\n <div style={menuStyles.divider} />\n\n {/* ── Filter section ── */}\n <div style={menuStyles.sectionLabel}>Filter</div>\n <MenuItem\n active={showFilterPanel}\n onClick={() => setShowFilterPanel(!showFilterPanel)}\n >\n <span style={menuStyles.itemIcon}>⊞</span>\n Filter by values...\n {activeFilter && <span style={menuStyles.activeDot} />}\n </MenuItem>\n {activeFilter && (\n <MenuItem\n onClick={() => { onFilterClear(); onClose(); }}\n >\n <span style={menuStyles.itemIcon}>✕</span>\n Clear filter\n </MenuItem>\n )}\n\n {showFilterPanel && (\n <div style={menuStyles.filterPanel}>\n <input\n type=\"text\"\n placeholder=\"Search values...\"\n value={filterSearch}\n onChange={(e) => setFilterSearch(e.target.value)}\n style={menuStyles.filterSearch}\n autoFocus\n />\n <div style={menuStyles.filterActions}>\n <button style={menuStyles.linkButton} onClick={selectAll}>\n Select all\n </button>\n <button style={menuStyles.linkButton} onClick={selectNone}>\n Select none\n </button>\n </div>\n <div style={menuStyles.filterList}>\n {loadingValues ? (\n <div style={menuStyles.filterLoading}>Loading values...</div>\n ) : (\n filteredUniqueValues?.map((val) => {\n const key = String(val);\n return (\n <label key={key} style={menuStyles.filterItem}>\n <input\n type=\"checkbox\"\n checked={selectedValues.has(key)}\n onChange={() => toggleValue(key)}\n style={menuStyles.checkbox}\n />\n <span style={menuStyles.filterValue}>\n {val === null || val === undefined\n ? \"(null)\"\n : String(val)}\n </span>\n </label>\n );\n })\n )}\n </div>\n <button style={menuStyles.applyButton} onClick={handleFilterApply}>\n Apply filter\n </button>\n </div>\n )}\n\n <div style={menuStyles.divider} />\n\n {/* ── Group section ── */}\n <div style={menuStyles.sectionLabel}>Group</div>\n <MenuItem\n active={isGrouped}\n onClick={() => { onGroupToggle(); onClose(); }}\n >\n <span style={menuStyles.itemIcon}>{isGrouped ? \"▤\" : \"▦\"}</span>\n {isGrouped ? \"Remove grouping\" : \"Group by this column\"}\n </MenuItem>\n </div>\n </div>\n );\n}\n\nfunction MenuItem({\n active,\n onClick,\n children,\n}: {\n active?: boolean;\n onClick: () => void;\n children: React.ReactNode;\n}) {\n const [isHovered, setIsHovered] = useState(false);\n\n return (\n <button\n style={{\n ...menuStyles.item,\n ...(active ? menuStyles.itemActive : {}),\n ...(!active && isHovered ? menuStyles.itemHover : {}),\n }}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n onClick={onClick}\n >\n {children}\n </button>\n );\n}\n\nconst menuStyles: Record<string, React.CSSProperties> = {\n overlay: {\n position: \"fixed\",\n zIndex: 10000,\n },\n container: {\n backgroundColor: \"#ffffff\",\n border: \"1px solid #d7e0ea\",\n borderRadius: 10,\n boxShadow: \"0 14px 28px rgba(15, 23, 42, 0.14), 0 3px 10px rgba(15, 23, 42, 0.08)\",\n minWidth: 230,\n maxWidth: 320,\n padding: \"6px 0\",\n fontFamily: \"'Plus Jakarta Sans', 'Inter', system-ui, sans-serif\",\n fontSize: 13,\n color: \"#1f2937\",\n },\n sectionLabel: {\n padding: \"8px 12px 3px\",\n fontSize: 11,\n fontWeight: 700,\n color: \"#6b7280\",\n textTransform: \"uppercase\",\n letterSpacing: \"0.06em\",\n },\n item: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n width: \"100%\",\n padding: \"8px 12px\",\n border: \"none\",\n background: \"none\",\n textAlign: \"left\",\n fontSize: 13,\n color: \"#334155\",\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n borderRadius: 7,\n margin: \"1px 6px\",\n transition: \"background-color 120ms ease, color 120ms ease\",\n },\n itemHover: {\n backgroundColor: \"#eef3f9\",\n color: \"#111827\",\n },\n itemActive: {\n backgroundColor: \"#e8f1ff\",\n color: \"#1d4ed8\",\n },\n itemIcon: {\n width: 16,\n textAlign: \"center\",\n flexShrink: 0,\n fontSize: 13,\n color: \"#64748b\",\n },\n badge: {\n marginLeft: \"auto\",\n backgroundColor: \"#eaf0f7\",\n color: \"#475569\",\n fontSize: 10,\n fontWeight: 700,\n padding: \"2px 6px\",\n borderRadius: 4,\n },\n activeDot: {\n marginLeft: \"auto\",\n width: 7,\n height: 7,\n borderRadius: \"50%\",\n backgroundColor: \"#2563eb\",\n },\n divider: {\n height: 1,\n backgroundColor: \"#e6ebf2\",\n margin: \"6px 0\",\n },\n filterPanel: {\n padding: \"6px 12px 10px\",\n },\n filterSearch: {\n width: \"100%\",\n padding: \"7px 9px\",\n border: \"1px solid #d1dbe7\",\n borderRadius: 7,\n fontSize: 12,\n fontFamily: \"inherit\",\n outline: \"none\",\n boxSizing: \"border-box\",\n backgroundColor: \"#ffffff\",\n color: \"#1f2937\",\n },\n filterActions: {\n display: \"flex\",\n gap: 12,\n padding: \"6px 0\",\n },\n linkButton: {\n background: \"none\",\n border: \"none\",\n color: \"#1d4ed8\",\n fontSize: 11,\n cursor: \"pointer\",\n padding: 0,\n fontFamily: \"inherit\",\n fontWeight: 600,\n },\n filterList: {\n maxHeight: 200,\n overflowY: \"auto\",\n border: \"1px solid #d8e0ea\",\n borderRadius: 7,\n marginBottom: 6,\n backgroundColor: \"#ffffff\",\n },\n filterLoading: {\n padding: 12,\n textAlign: \"center\",\n color: \"#6b7280\",\n fontSize: 12,\n },\n filterItem: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"4px 8px\",\n cursor: \"pointer\",\n fontSize: 12,\n color: \"#334155\",\n },\n checkbox: {\n margin: 0,\n flexShrink: 0,\n accentColor: \"#2563eb\",\n },\n filterValue: {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n },\n applyButton: {\n width: \"100%\",\n padding: \"8px 12px\",\n backgroundColor: \"#1d4ed8\",\n color: \"white\",\n border: \"1px solid #1e40af\",\n borderRadius: 7,\n fontSize: 12,\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n boxShadow: \"none\",\n },\n};\n","import { useState, useCallback, useRef } from \"react\";\n\nexport interface FileDropZoneProps {\n /** Called when a file is selected (via drop or file picker) */\n onFileSelect: (file: File) => void;\n /**\n * Custom open handler (e.g. Tauri native dialog).\n * When provided, the \"Select file\" button calls this instead of the\n * browser file picker. Drag-and-drop still uses onFileSelect.\n */\n onCustomOpen?: () => void;\n /** Accepted file extensions (default: [\".parquet\"]) */\n accept?: string[];\n /** Compact mode — renders as a small inline drop area (for use alongside viewer) */\n compact?: boolean;\n /** Additional CSS class name */\n className?: string;\n /** Custom label text */\n label?: string;\n /** Custom button text */\n buttonLabel?: string;\n}\n\nexport function FileDropZone({\n onFileSelect,\n onCustomOpen,\n accept = [\".parquet\"],\n compact = false,\n className,\n label,\n buttonLabel,\n}: FileDropZoneProps) {\n const [isDragOver, setIsDragOver] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const acceptString = accept.join(\",\");\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(false);\n\n const droppedFile = e.dataTransfer.files[0];\n if (droppedFile && accept.some((ext) => droppedFile.name.endsWith(ext))) {\n onFileSelect(droppedFile);\n }\n },\n [onFileSelect, accept],\n );\n\n const handleDragOver = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(true);\n }, []);\n\n const handleDragLeave = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragOver(false);\n }, []);\n\n const handleFileInput = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const selectedFile = e.target.files?.[0];\n if (selectedFile) {\n onFileSelect(selectedFile);\n }\n // Reset input so the same file can be re-selected\n if (inputRef.current) {\n inputRef.current.value = \"\";\n }\n },\n [onFileSelect],\n );\n\n const handleClick = useCallback(() => {\n if (onCustomOpen) {\n onCustomOpen();\n } else {\n inputRef.current?.click();\n }\n }, [onCustomOpen]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleClick();\n }\n },\n [handleClick],\n );\n\n if (compact) {\n return (\n <div\n className={className}\n role=\"button\"\n tabIndex={0}\n aria-label={label ?? \"Drop a file here or click to select\"}\n onDrop={handleDrop}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n style={{\n ...compactStyles.zone,\n ...(isDragOver ? compactStyles.zoneDragOver : {}),\n }}\n >\n <span style={compactStyles.icon}>+</span>\n <span style={compactStyles.text}>\n {buttonLabel ?? \"Open file\"}\n </span>\n <input\n ref={inputRef}\n type=\"file\"\n accept={acceptString}\n onChange={handleFileInput}\n style={{ display: \"none\" }}\n tabIndex={-1}\n aria-hidden=\"true\"\n />\n </div>\n );\n }\n\n return (\n <div\n className={className}\n role=\"button\"\n tabIndex={0}\n aria-label={label ?? \"Drop a parquet file here or click to select\"}\n onDrop={handleDrop}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n style={{\n ...fullStyles.zone,\n ...(isDragOver ? fullStyles.zoneDragOver : {}),\n }}\n >\n <div style={fullStyles.iconCircle}>\n <svg\n width=\"32\"\n height=\"32\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n </div>\n <div style={fullStyles.textGroup}>\n <p style={fullStyles.title}>\n {label ?? \"Open a Parquet file\"}\n </p>\n <p style={fullStyles.hint}>\n Drag & drop a .parquet file here, or click to browse\n </p>\n </div>\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n handleClick();\n }}\n style={fullStyles.button}\n >\n {buttonLabel ?? \"Choose file\"}\n </button>\n <p style={fullStyles.supportedLabel}>.parquet</p>\n <input\n ref={inputRef}\n type=\"file\"\n accept={acceptString}\n onChange={handleFileInput}\n style={{ display: \"none\" }}\n tabIndex={-1}\n aria-hidden=\"true\"\n />\n </div>\n );\n}\n\nconst fullStyles: Record<string, React.CSSProperties> = {\n zone: {\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 20,\n padding: \"56px 48px\",\n border: \"2px dashed #b9c6d7\",\n borderRadius: 14,\n cursor: \"pointer\",\n transition: \"all 0.2s ease\",\n backgroundColor: \"#ffffff\",\n fontFamily: \"'Plus Jakarta Sans', 'Inter', system-ui, sans-serif\",\n outline: \"none\",\n maxWidth: 420,\n width: \"100%\",\n },\n zoneDragOver: {\n borderColor: \"#2563eb\",\n backgroundColor: \"#f5f9ff\",\n transform: \"scale(1.01)\",\n },\n iconCircle: {\n width: 72,\n height: 72,\n borderRadius: \"50%\",\n backgroundColor: \"#edf2f7\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: \"#64748b\",\n transition: \"background-color 0.2s, color 0.2s\",\n },\n textGroup: {\n textAlign: \"center\" as const,\n },\n title: {\n fontSize: 17,\n fontWeight: 700,\n color: \"#111827\",\n margin: 0,\n },\n hint: {\n fontSize: 13,\n color: \"#64748b\",\n margin: \"6px 0 0\",\n },\n button: {\n padding: \"10px 32px\",\n backgroundColor: \"#1d4ed8\",\n color: \"#ffffff\",\n border: \"1px solid #1e40af\",\n borderRadius: 8,\n fontSize: 14,\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"'Plus Jakarta Sans', 'Inter', system-ui, sans-serif\",\n transition: \"background-color 0.15s\",\n boxShadow: \"none\",\n },\n supportedLabel: {\n fontSize: 11,\n color: \"#94a3b8\",\n margin: 0,\n letterSpacing: \"0.03em\",\n },\n};\n\nconst compactStyles: Record<string, React.CSSProperties> = {\n zone: {\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n padding: \"6px 14px\",\n border: \"1px dashed #c2cfde\",\n borderRadius: 8,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n backgroundColor: \"#ffffff\",\n fontFamily: \"'Plus Jakarta Sans', 'Inter', system-ui, sans-serif\",\n fontSize: 13,\n color: \"#64748b\",\n whiteSpace: \"nowrap\",\n outline: \"none\",\n },\n zoneDragOver: {\n borderColor: \"#2563eb\",\n backgroundColor: \"#f5f9ff\",\n color: \"#1d4ed8\",\n },\n icon: {\n fontSize: 16,\n fontWeight: 700,\n lineHeight: 1,\n },\n text: {\n lineHeight: 1,\n },\n};\n"],"mappings":"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","names":["import_react","import_react","import_core","import_react","import_react","import_core","s","import_react","import_react","import_react","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","rowNumWidth"]}