diff --git a/src/islands/ToolHost.tsx b/src/islands/ToolHost.tsx index 7fba5a2..33f0208 100644 --- a/src/islands/ToolHost.tsx +++ b/src/islands/ToolHost.tsx @@ -48,10 +48,12 @@ class ToolErrorBoundary extends Component { export default function ToolHost({ toolId }: ToolHostProps) { const tool = getToolById(toolId); + // `tool` is a stable registry reference derived from `toolId`, so keying on + // both is equivalent to keying on `toolId` alone — and satisfies the linter. const LazyTool = useMemo(() => { if (!tool) return null; return lazy(tool.load); - }, [toolId]); + }, [toolId, tool]); if (!tool || !LazyTool) { return
Tool not found.
; diff --git a/src/islands/dev/HotkeyTest.tsx b/src/islands/dev/HotkeyTest.tsx index a8b93f9..4f5941f 100644 --- a/src/islands/dev/HotkeyTest.tsx +++ b/src/islands/dev/HotkeyTest.tsx @@ -29,7 +29,7 @@ export default function HotkeyTest() { const registerTestHotkey = async (keys: string, description: string) => { setError(null); try { - const id = await hotkeyService.register( + await hotkeyService.register( keys, () => { setLastTriggered(`${description} (${keys})`); diff --git a/src/islands/dev/JsonCompare.tsx b/src/islands/dev/JsonCompare.tsx index 8b0171d..723066f 100644 --- a/src/islands/dev/JsonCompare.tsx +++ b/src/islands/dev/JsonCompare.tsx @@ -195,11 +195,13 @@ export default function JsonCompare() { parseAndCompare(leftJson, value); }; - // Re-compare when ignoreArrayOrder changes + // Re-compare only when ignoreArrayOrder toggles; edits to left/right already + // trigger a compare via their change handlers, so they're intentionally omitted. useEffect(() => { if (leftJson.trim() && rightJson.trim()) { parseAndCompare(leftJson, rightJson); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [ignoreArrayOrder]); return ( diff --git a/src/islands/dev/PasswordGen.tsx b/src/islands/dev/PasswordGen.tsx index 0736410..dd6974c 100644 --- a/src/islands/dev/PasswordGen.tsx +++ b/src/islands/dev/PasswordGen.tsx @@ -37,7 +37,6 @@ export default function PasswordGen() { // Regenerate whenever any option changes. useEffect(() => { setPassword(generatePassword({ length, enabled, avoidAmbiguous, minNumbers, minSpecial })); - // eslint-disable-next-line react-hooks/exhaustive-deps }, [length, enabled, avoidAmbiguous, minNumbers, minSpecial]); const clampMin = (value: number) => setMinLength(Math.min(Math.max(value || 1, 1), maxLength)); diff --git a/src/islands/draw/Whiteboard.tsx b/src/islands/draw/Whiteboard.tsx index 9ccb211..146207a 100644 --- a/src/islands/draw/Whiteboard.tsx +++ b/src/islands/draw/Whiteboard.tsx @@ -113,7 +113,6 @@ export default function Whiteboard() { window.removeEventListener('pagehide', flushSave); window.removeEventListener('beforeunload', onBeforeUnload); }; - // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { diff --git a/src/islands/image/ImageAnnotate.tsx b/src/islands/image/ImageAnnotate.tsx index 4314c13..6783b63 100644 --- a/src/islands/image/ImageAnnotate.tsx +++ b/src/islands/image/ImageAnnotate.tsx @@ -478,7 +478,6 @@ export default function ImageAnnotate() { takePendingImage().then(pending => { if (pending) onDrop([new File([pending.blob], pending.name, { type: pending.blob.type })]); }); - // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const pointer = (e: { clientX: number; clientY: number }) => { @@ -759,7 +758,6 @@ export default function ImageAnnotate() { window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); // undo/redo use functional state updaters, so a stable listener is fine. - // eslint-disable-next-line react-hooks/exhaustive-deps }, [textEdit]); const toPngBlob = async (): Promise => { diff --git a/src/islands/image/ObjectRemove.tsx b/src/islands/image/ObjectRemove.tsx index 293182c..6ed071a 100644 --- a/src/islands/image/ObjectRemove.tsx +++ b/src/islands/image/ObjectRemove.tsx @@ -78,7 +78,7 @@ export default function ObjectRemove() { usePasteImage(f => onDrop([f])); - useEffect(() => { if (ready) redraw(); /* eslint-disable-next-line */ }, [ready]); + useEffect(() => { if (ready) redraw(); }, [ready]); const pointer = (e: React.PointerEvent) => { const c = viewRef.current!; diff --git a/src/islands/playground/CodeScratchpad.tsx b/src/islands/playground/CodeScratchpad.tsx index 47e3f9a..dcc3022 100644 --- a/src/islands/playground/CodeScratchpad.tsx +++ b/src/islands/playground/CodeScratchpad.tsx @@ -4,7 +4,6 @@ import { Button } from '@/components/ui/Button'; import MonacoEditor from './MonacoEditor'; import { extensionToLanguage } from '@/tools/playground/language.lib'; import { loadFiles, saveFiles, type ScratchFile } from '@/tools/playground/scratchpad.store'; -import { downloadService } from '@/services/download'; import { fileService } from '@/services/file'; import { clipboardService } from '@/services/clipboard'; diff --git a/src/services/file.service.ts b/src/services/file.service.ts index 96a7f40..5c605f3 100644 --- a/src/services/file.service.ts +++ b/src/services/file.service.ts @@ -14,7 +14,7 @@ export class FileService { return Array.from(source); } - async getFileHandle(file: File): Promise { + async getFileHandle(_file: File): Promise { // File System Access API - may not be available if (!('showOpenFilePicker' in window)) { return null; diff --git a/src/services/platform/index.ts b/src/services/platform/index.ts index c343987..a639fcb 100644 --- a/src/services/platform/index.ts +++ b/src/services/platform/index.ts @@ -20,7 +20,7 @@ export function getPlatform(): Platform { export function getArchitecture(): Architecture { if (typeof window === 'undefined') return 'unknown'; - // @ts-ignore - navigator.userAgentData is experimental + // @ts-expect-error - navigator.userAgentData is experimental const uaData = navigator.userAgentData; if (uaData && uaData.platform) { diff --git a/src/stores/worker.store.ts b/src/stores/worker.store.ts index 8a57ecc..41ae524 100644 --- a/src/stores/worker.store.ts +++ b/src/stores/worker.store.ts @@ -14,6 +14,6 @@ export function setProgress(id: string, label: string, percent: number): void { export function removeProgress(id: string): void { const current = progressMap.get(); - const { [id]: removed, ...rest } = current; + const { [id]: _removed, ...rest } = current; progressMap.set(rest); }