From 736fb7be6af8df0cdf9d39485de72005675286e4 Mon Sep 17 00:00:00 2001 From: Red J Adaya Date: Thu, 26 Oct 2023 12:41:52 +0800 Subject: [PATCH] csvviwer focus support (#46) * more fixes * add delay and slight opacity animation * cleanup * focus support * use savedHeight as initial tbody height * cleanup * set container to savedHeight initially * fix calc issue * more calc fixes * more calc fixes --- package.json | 2 + src/plugins/csv/csv.less | 6 +-- src/plugins/csv/csv.tsx | 84 ++++++++++++++++++-------------------- src/plugins/csv/search.tsx | 35 ---------------- yarn.lock | 10 +++++ 5 files changed, 53 insertions(+), 84 deletions(-) delete mode 100644 src/plugins/csv/search.tsx diff --git a/package.json b/package.json index 8057192a..ec3e0e52 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,8 @@ "license": "Apache-2.0", "dependencies": { "@monaco-editor/react": "^4.5.1", + "@table-nav/core": "^0.0.7", + "@table-nav/react": "^0.0.7", "@tanstack/match-sorter-utils": "^8.8.4", "@tanstack/react-table": "^8.10.3", "autobind-decorator": "^2.4.0", diff --git a/src/plugins/csv/csv.less b/src/plugins/csv/csv.less index d51b2322..1c8398da 100644 --- a/src/plugins/csv/csv.less +++ b/src/plugins/csv/csv.less @@ -21,10 +21,6 @@ user-select: none; } - .global-search-render { - margin-bottom: 10px; - } - table.probe { position: absolute; visibility: hidden; @@ -98,6 +94,6 @@ } } -.csv-renderer.loaded { +.csv-renderer.show { opacity: 1; /* When loaded class is added, set the opacity to 1, making it visible */ } diff --git a/src/plugins/csv/csv.tsx b/src/plugins/csv/csv.tsx index 69f6380b..1a790136 100644 --- a/src/plugins/csv/csv.tsx +++ b/src/plugins/csv/csv.tsx @@ -10,11 +10,10 @@ import { flexRender, useReactTable, getCoreRowModel, - getFilteredRowModel, getSortedRowModel, FilterFn, } from "@tanstack/react-table"; -import { rankItem } from "@tanstack/match-sorter-utils"; +import { useTableNav } from "@table-nav/react"; import SortUpIcon from "./img/sort-up-solid.svg"; import SortDownIcon from "./img/sort-down-solid.svg"; import cn from "classnames"; @@ -27,27 +26,16 @@ type CSVRow = { [key: string]: string | number; }; -const fuzzyFilter: FilterFn = (row, columnId, value, addMeta) => { - // Rank the item - const itemRank = rankItem(row.getValue(columnId), value); - - // Store the itemRank info - addMeta({ - itemRank, - }); - - // Return if the item should be filtered in/out - return itemRank.passed; -}; - interface Props { data: Blob; readOnly: boolean; context: RendererContext; opts: RendererOpts; savedHeight: number; - scrollToBringIntoViewport: () => void; lineState: LineStateType; + shouldFocus: boolean; + rendererApi: RendererModelContainerApi; + scrollToBringIntoViewport: () => void; } interface State { @@ -59,7 +47,7 @@ interface State { const columnHelper = createColumnHelper(); const CSVRenderer: FC = (props: Props) => { - const { data, opts, lineState, context, savedHeight } = props; + const { data, opts, lineState, context, shouldFocus, rendererApi, savedHeight } = props; const { height: maxHeight } = opts.maxSize; const csvCacheRef = useRef(new Map()); @@ -70,11 +58,11 @@ const CSVRenderer: FC = (props: Props) => { const [state, setState] = useState({ content: null, showReadonly: true, - tbodyHeight: maxHeight, + tbodyHeight: 0, }); - const [globalFilter, setGlobalFilter] = useState(""); const [isFileTooLarge, setIsFileTooLarge] = useState(false); - const [isRendererLoaded, setRendererLoaded] = useState(false); + const [tableLoaded, setTableLoaded] = useState(false); + const { listeners } = useTableNav(); const filePath = lineState["prompt:file"]; const { screenId, lineId } = context; @@ -157,12 +145,12 @@ const CSVRenderer: FC = (props: Props) => { useEffect(() => { if (probeRef.current && headerRef.current && parsedData.length) { const rowHeight = probeRef.current.offsetHeight; - const tbodyHeight = rowHeight * parsedData.length - rowHeight; - const headerHeight = headerRef.current.offsetHeight; // For some reason, if we subtract this from maxHeight, the table is too short - const tbodyHeightLessHeader = tbodyHeight - headerHeight; - const maxTbodyHeight = Math.min(maxHeight, tbodyHeightLessHeader); + const fullTBodyHeight = rowHeight * parsedData.length; + const headerHeight = headerRef.current.offsetHeight; + const maxHeightLessHeader = maxHeight - headerHeight; + const tbodyHeight = Math.min(maxHeightLessHeader, fullTBodyHeight); - setState((prevState) => ({ ...prevState, tbodyHeight: maxTbodyHeight })); + setState((prevState) => ({ ...prevState, tbodyHeight })); } }, [probeRef, headerRef, maxHeight, parsedData]); @@ -172,27 +160,24 @@ const CSVRenderer: FC = (props: Props) => { if (rowRef.current.length === parsedData.length) { timer = setTimeout(() => { - setRendererLoaded(true); - }, 100); // Delay a bit to make sure the rows are rendered + setTableLoaded(true); + }, 50); // Delay a bit to make sure the rows are rendered } return () => clearTimeout(timer); }, [rowRef, parsedData]); + useEffect(() => { + if (shouldFocus) { + rendererApi.onFocusChanged(true); + } + }, [shouldFocus]); + const table = useReactTable({ manualPagination: true, data: parsedData, columns, - filterFns: { - fuzzy: fuzzyFilter, - }, - state: { - globalFilter, - }, - globalFilterFn: fuzzyFilter, - onGlobalFilterChange: setGlobalFilter, getCoreRowModel: getCoreRowModel(), - getFilteredRowModel: getFilteredRowModel(), getSortedRowModel: getSortedRowModel(), }); @@ -205,7 +190,10 @@ const CSVRenderer: FC = (props: Props) => { } return ( -
+
@@ -213,12 +201,18 @@ const CSVRenderer: FC = (props: Props) => {
- +
- {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - + {headerGroup.headers.map((header, index) => ( + {table.getRowModel().rows.map((row, index) => ( - (rowRef.current[index] = el)}> + (rowRef.current[index] = el)} id={row.id} tabIndex={index}> {row.getVisibleCells().map((cell) => ( - + ))} ))} diff --git a/src/plugins/csv/search.tsx b/src/plugins/csv/search.tsx deleted file mode 100644 index cfb1c850..00000000 --- a/src/plugins/csv/search.tsx +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2023, Command Line Inc. -// SPDX-License-Identifier: Apache-2.0 - -import React, { FC, useEffect, useState } from "react"; - -const DebouncedInput: FC<{ - value: string | number; - onChange: (value: string | number) => void; - debounce?: number; - } & Omit, 'onChange'>> = ({ - value: initialValue, - onChange, - debounce = 500, - ...props - }) => { - const [value, setValue] = useState(initialValue); - - useEffect(() => { - setValue(initialValue); - }, [initialValue]); - - useEffect(() => { - const timeout = setTimeout(() => { - onChange(value); - }, debounce); - - return () => clearTimeout(timeout); - }, [value]); - - return
- setValue(e.target.value)} /> -
; -}; - -export default DebouncedInput \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 129fe9ef..81ddceb9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1641,6 +1641,16 @@ dependencies: defer-to-connect "^2.0.0" +"@table-nav/core@^0.0.7": + version "0.0.7" + resolved "https://registry.yarnpkg.com/@table-nav/core/-/core-0.0.7.tgz#2d7f58eb81aacf5bdd1b40a823dbef5a88792995" + integrity sha512-pCh18jHDRe3tw9sJZXfKi4cSD6VjHbn40CYdqhp5X91SIX7rakDEQAsTx6F7Fv9TUv265l+5rUDcYNaJ0N0cqQ== + +"@table-nav/react@^0.0.7": + version "0.0.7" + resolved "https://registry.yarnpkg.com/@table-nav/react/-/react-0.0.7.tgz#a97699a490e31713fccd5f624ddb62e9fdc06a82" + integrity sha512-S+DsD/qDqp50Z4dqt5tZFMWA3sRu0OOT/grMQuq/z/52jPEKJB+b9t+YSH8Ms55vCJOJ0DxuYldJpYrJLMG5ew== + "@tanstack/match-sorter-utils@^8.8.4": version "8.8.4" resolved "https://registry.yarnpkg.com/@tanstack/match-sorter-utils/-/match-sorter-utils-8.8.4.tgz#0b2864d8b7bac06a9f84cb903d405852cc40a457"
+ {table.getHeaderGroups().map((headerGroup, index) => ( +
{header.isPlaceholder ? null : (
= (props: Props) => {
{flexRender(cell.column.columnDef.cell, cell.getContext())} + {flexRender(cell.column.columnDef.cell, cell.getContext())} +