diff --git a/package-lock.json b/package-lock.json index 5fc7202..bddcd5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,10 +8,10 @@ "name": "rowbinary-explorer", "version": "0.0.1", "dependencies": { - "react": "^18.3.1", - "react-dom": "^18.3.1", + "react": "^19.2.8", + "react-dom": "^19.2.8", "react-resizable-panels": "^2.1.7", - "react-window": "^1.8.10", + "react-window": "^2.3.0", "zustand": "^5.0.3" }, "bin": { @@ -22,9 +22,8 @@ "@playwright/test": "^1.60.0", "@testcontainers/clickhouse": "^12.0.1", "@types/node": "^25.9.3", - "@types/react": "^18.3.18", - "@types/react-dom": "^18.3.5", - "@types/react-window": "^1.8.8", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.5", "@vitejs/plugin-react": "^6.0.2", "electron": "^42.4.0", "electron-builder": "^26.7.0", @@ -32,7 +31,7 @@ "eslint": "^10.4.1", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.3", - "globals": "^15.14.0", + "globals": "^17.11.0", "testcontainers": "^12.0.1", "tsx": "^4.22.4", "typescript": "~5.6.2", @@ -255,15 +254,6 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", @@ -2107,42 +2097,24 @@ "undici-types": ">=7.24.0 <7.24.7" } }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "devOptional": true, - "license": "MIT" - }, "node_modules/@types/react": { - "version": "18.3.31", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", - "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", + "version": "19.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", + "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", "devOptional": true, "license": "MIT", "dependencies": { - "@types/prop-types": "*", "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.5.tgz", + "integrity": "sha512-fMPwH9v7r/pp43yUd2/Mbiex5KouJwwR3dzHkhLREUC6764VyDsqxhAxv6OFEYR1RhjOyD1naqba8ECDBe7ZQg==", "dev": true, "license": "MIT", "peerDependencies": { - "@types/react": "^18.0.0" - } - }, - "node_modules/@types/react-window": { - "version": "1.8.8", - "resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.8.tgz", - "integrity": "sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" + "@types/react": "^19.2.0" } }, "node_modules/@types/responselike": { @@ -5084,9 +5056,9 @@ } }, "node_modules/globals": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", - "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.11.0.tgz", + "integrity": "sha512-Z2I8hM+PbJDXQDq3Icgpzv+mPdwr68iZUU9d5WW4FuXfDUQfkZaZuvjMv42/5crNyw154+9+VWXbYrUgDXbxNw==", "dev": true, "license": "MIT", "engines": { @@ -5493,6 +5465,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -5979,18 +5952,6 @@ "dev": true, "license": "Apache-2.0" }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, "node_modules/lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -6045,12 +6006,6 @@ "node": ">= 0.4" } }, - "node_modules/memoize-one": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", - "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", - "license": "MIT" - }, "node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -6909,28 +6864,24 @@ } }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^18.3.1" + "react": "^19.2.8" } }, "node_modules/react-resizable-panels": { @@ -6944,20 +6895,13 @@ } }, "node_modules/react-window": { - "version": "1.8.11", - "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.11.tgz", - "integrity": "sha512-+SRbUVT2scadgFSWx+R1P754xHPEqvcfSfVX10QYg6POOz+WNgkN48pS+BtZNIMGiL1HYrSEiCkwsMS15QogEQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-window/-/react-window-2.3.0.tgz", + "integrity": "sha512-FW6TIpaOH646k51X7yE+LSCWGkt5Pfsnc1fVyq/sCI9h0pTqmMiBXM04pzFKg3Bt7NGkeV6kqbU8d/QjmFS7Ug==", "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.0.0", - "memoize-one": ">=3.1.1 <6" - }, - "engines": { - "node": ">8.0.0" - }, "peerDependencies": { - "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/read-binary-file-arch": { @@ -7191,13 +7135,10 @@ } }, "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" }, "node_modules/semver": { "version": "7.8.4", diff --git a/package.json b/package.json index e177100..07aa0dc 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,10 @@ "prepublishOnly": "npm run cli:build" }, "dependencies": { - "react": "^18.3.1", - "react-dom": "^18.3.1", + "react": "^19.2.8", + "react-dom": "^19.2.8", "react-resizable-panels": "^2.1.7", - "react-window": "^1.8.10", + "react-window": "^2.3.0", "zustand": "^5.0.3" }, "devDependencies": { @@ -39,9 +39,8 @@ "@playwright/test": "^1.60.0", "@testcontainers/clickhouse": "^12.0.1", "@types/node": "^25.9.3", - "@types/react": "^18.3.18", - "@types/react-dom": "^18.3.5", - "@types/react-window": "^1.8.8", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.5", "@vitejs/plugin-react": "^6.0.2", "electron": "^42.4.0", "electron-builder": "^26.7.0", @@ -49,7 +48,7 @@ "eslint": "^10.4.1", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.3", - "globals": "^15.14.0", + "globals": "^17.11.0", "testcontainers": "^12.0.1", "tsx": "^4.22.4", "typescript": "~5.6.2", diff --git a/src/components/HexViewer/HexViewer.tsx b/src/components/HexViewer/HexViewer.tsx index 91fdc71..8d094c0 100644 --- a/src/components/HexViewer/HexViewer.tsx +++ b/src/components/HexViewer/HexViewer.tsx @@ -1,5 +1,5 @@ import { useMemo, useCallback, useRef, useEffect } from 'react'; -import { FixedSizeList as List, FixedSizeList } from 'react-window'; +import { List, useListRef, type RowComponentProps } from 'react-window'; import { useStore } from '../../store/store'; import { AstNode } from '../../core/types/ast'; import '../../styles/hex-viewer.css'; @@ -171,18 +171,19 @@ function getTypeColor(typeName: string): string { return colors[baseType] || '#9e9e9e'; } -interface HexRowProps { - index: number; - style: React.CSSProperties; - data: { - bytes: Uint8Array; - highlightMap: Map; - onByteClick: (offset: number) => void; - }; +interface HexRowData { + bytes: Uint8Array; + highlightMap: Map; + onByteClick: (offset: number) => void; } -function HexRow({ index, style, data }: HexRowProps) { - const { bytes, highlightMap, onByteClick } = data; +function HexRow({ + index, + style, + bytes, + highlightMap, + onByteClick, +}: RowComponentProps) { const startOffset = index * BYTES_PER_ROW; const rowBytes = bytes.slice(startOffset, startOffset + BYTES_PER_ROW); @@ -263,7 +264,7 @@ export function HexViewer() { const scrollRequest = useStore((s) => s.scrollRequest); const clearScrollTarget = useStore((s) => s.clearScrollTarget); - const listRef = useRef(null); + const listRef = useListRef(null); const lastScrollId = useRef(null); // Scroll to byte offset when requested @@ -271,10 +272,10 @@ export function HexViewer() { if (scrollRequest && listRef.current && scrollRequest.id !== lastScrollId.current) { lastScrollId.current = scrollRequest.id; const rowIndex = Math.floor(scrollRequest.byteOffset / BYTES_PER_ROW); - listRef.current.scrollToItem(rowIndex, 'center'); + listRef.current.scrollToRow({ index: rowIndex, align: 'center' }); clearScrollTarget(); } - }, [scrollRequest, clearScrollTarget]); + }, [scrollRequest, clearScrollTarget, listRef]); const highlightMap = useMemo( () => buildHighlightMap(parsedData, activeNodeId, hoveredNodeId), @@ -332,20 +333,16 @@ export function HexViewer() { return (
- {HexRow} - + />
); } diff --git a/src/components/QueryInput.tsx b/src/components/QueryInput.tsx index d668cba..b6e536c 100644 --- a/src/components/QueryInput.tsx +++ b/src/components/QueryInput.tsx @@ -26,7 +26,7 @@ export function QueryInput() { const fileInputRef = useRef(null); const [shareLabel, setShareLabel] = useState('Share'); const [hostUrl, setHostUrl] = useState('http://localhost:8123'); - const saveTimerRef = useRef>(); + const saveTimerRef = useRef | undefined>(undefined); // Load connection config in Electron mode useEffect(() => { diff --git a/src/styles/hex-viewer.css b/src/styles/hex-viewer.css index d8a74e6..1bc29ba 100644 --- a/src/styles/hex-viewer.css +++ b/src/styles/hex-viewer.css @@ -1,9 +1,11 @@ .hex-viewer { + display: flex; + flex-direction: column; font-family: var(--font-mono); font-size: 13px; line-height: 1.6; height: 100%; - overflow: auto; + overflow: hidden; background: var(--bg-secondary); }