Skip to content

Fix oxlint react next-line suppressions - #1711

Open
stipsan wants to merge 8 commits into
mainfrom
cursor/fix-oxlint-react-suppressions-9ac0
Open

Fix oxlint react next-line suppressions#1711
stipsan wants to merge 8 commits into
mainfrom
cursor/fix-oxlint-react-suppressions-9ac0

Conversation

@stipsan

@stipsan stipsan commented Jul 23, 2026

Copy link
Copy Markdown
Member

What

Remove all oxlint-disable-next-line suppressions for React rules by fixing the underlying violations (mostly React Compiler + hooks).

Why

These suppressions were papering over real React Compiler / hooks issues (EffectSetState, refs during render, nested components during render, PreserveManualMemo, exhaustive-deps, etc.). Fixing them keeps plugins compiler-safe without per-line escapes.

Approach

  • EffectSetState: derive during render, adjust state during render when props change, or move setState into async callbacks
  • StaticComponents (media dialogs): inline footer/header JSX instead of nested components
  • Refs during render: lazy state init, state instead of .current reads in render
  • PreserveManualMemo: align or remove manual memoization
  • exhaustive-deps: add deps / restructure with stable refs
  • workflow DocumentList: drop @tanstack/react-virtual (incompatible with React Compiler memoization); render filtered cards directly. Kanban columns typically stay small enough that this is acceptable; can revisit if TanStack Virtual becomes compiler-compatible.

Packages

Separate patch changesets for:

@sanity/assist, @sanity/block-insert-picker, @sanity/color-input, @sanity/cross-dataset-duplicator, @sanity/embeddings-index-ui, @sanity/personalization-plugin, @sanity/studio-secrets, sanity-plugin-hotspot-array, sanity-plugin-media, sanity-plugin-mux-input, sanity-plugin-utils, sanity-plugin-workflow

Verification

  • pnpm format
  • pnpm lint
  • pnpm knip
  • pnpm build
  • pnpm test run — 184 files / 1097 tests

Note: one block-level oxlint-disable react/react-compiler remains in sanity-plugin-hotspot-array's useDebouncedCallback (not a next-line suppression).

Open in Web Open in Cursor 

Remove all oxlint-disable-next-line suppressions for react rules by
fixing the underlying React Compiler and hooks violations across
plugins (effects that sync state, refs during render, nested
components, memoization mismatches, and exhaustive-deps).

Notable: workflow DocumentList no longer uses TanStack Virtual, which
is incompatible with React Compiler memoization.
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
plugins-studio Error Error Jul 23, 2026 2:35pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
plugins-e2e-test-studio Ignored Ignored Jul 23, 2026 2:35pm

Request Review

@stipsan stipsan added the 🤖 bot label Jul 23, 2026 — with Cursor
@stipsan
stipsan marked this pull request as ready for review July 23, 2026 11:28
Copilot AI review requested due to automatic review settings July 23, 2026 11:28
@stipsan
stipsan requested review from a team as code owners July 23, 2026 11:28
@stipsan
stipsan requested review from pedrobonamin and removed request for a team July 23, 2026 11:28
Comment thread plugins/sanity-plugin-workflow/src/hooks/useWorkflowDocuments.tsx
Comment thread plugins/sanity-plugin-mux-input/src/hooks/useMediaMetadata.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes oxlint-disable-next-line suppressions for React Compiler and hooks rules across multiple plugins by restructuring components/hooks to avoid effect-driven state sync, ref reads during render, nested component definitions, and unstable hook dependencies—keeping the codebase React Compiler–safe without per-line escapes.

Changes:

  • Refactors multiple hooks/components to avoid React Compiler violations (e.g., deferring state updates, deriving UI state, stabilizing callbacks/deps, and removing nested component definitions used as props).
  • Updates sanity-plugin-workflow’s DocumentList to render cards directly (dropping @tanstack/react-virtual) to avoid compiler incompatibilities.
  • Adds per-package patch changesets for all affected published plugins.

Reviewed changes

Copilot reviewed 55 out of 56 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pnpm-lock.yaml Updates lockfile for dependency graph changes (incl. removal of @tanstack/react-virtual from workflow).
plugins/sanity-plugin-workflow/src/hooks/useWorkflowDocuments.tsx Reworks local state syncing to avoid effect-driven setState.
plugins/sanity-plugin-workflow/src/components/DocumentList.tsx Removes virtualization and renders filtered document cards directly.
plugins/sanity-plugin-workflow/package.json Drops @tanstack/react-virtual dependency.
plugins/sanity-plugin-utils/src/hooks/useListeningQuery.tsx Fixes RxJS error handling and avoids synchronous state updates in effect error paths.
plugins/sanity-plugin-mux-input/src/hooks/useMuxAssets.ts Introduces ref-backed state access and fixes effect deps for asset pagination fetching.
plugins/sanity-plugin-mux-input/src/hooks/useMediaMetadata.ts Avoids synchronous state updates and adds cancellation guard for async metadata work.
plugins/sanity-plugin-mux-input/src/hooks/useFetchFileSize.ts Refactors URL file size fetching into a keyed state machine to avoid effect-driven sync issues.
plugins/sanity-plugin-mux-input/src/components/VideoThumbnail.tsx Makes suspense/error handling memo-safe by returning structured results instead of calling setters during render.
plugins/sanity-plugin-mux-input/src/components/VideoPlayer.tsx Refactors playback/poster/src/token derivation to avoid render-time state updates; snapshots current time via events.
plugins/sanity-plugin-mux-input/src/components/VideoDetails/DeleteDialog.tsx Derives dialog state instead of syncing via effect-driven setState.
plugins/sanity-plugin-mux-input/src/components/Uploader.tsx Stabilizes cancel observable creation and restructures upload starter logic to satisfy hooks/compiler rules.
plugins/sanity-plugin-mux-input/src/components/UploadConfiguration.tsx Moves validation to pure derivation and avoids ref reads during render by seeding immutable defaults via lazy state.
plugins/sanity-plugin-mux-input/src/components/TextTracksManager.tsx Replaces effect-setState merge logic with memo-derived track ID set.
plugins/sanity-plugin-mux-input/src/components/PlayerActionsMenu.tsx Closes menu via derived render logic instead of effect-driven syncing.
plugins/sanity-plugin-mux-input/src/components/Player.tsx Replaces memos with render-time derivation to avoid compiler issues and ref reads.
plugins/sanity-plugin-mux-input/src/components/EditCaptionDialog.tsx Replaces effect-driven prop sync with guarded render-time updates and extracted helper.
plugins/sanity-plugin-mux-input/src/components/DraggableWatermark.tsx Extracts video content-box measurement, adds observer-driven sizing, and avoids render-time ref reads.
plugins/sanity-plugin-media/src/contexts/ToolOptionsContext.tsx Adjusts memoization strategy for tool options context to satisfy React Compiler.
plugins/sanity-plugin-media/src/components/DialogTagEdit/index.tsx Inlines dialog footer JSX to avoid nested component definitions.
plugins/sanity-plugin-media/src/components/DialogTagCreate/index.tsx Inlines dialog footer JSX to avoid nested component definitions.
plugins/sanity-plugin-media/src/components/DialogConfirm/index.tsx Inlines dialog header/footer JSX to avoid nested component definitions.
plugins/sanity-plugin-media/src/components/DialogAssetEdit/index.tsx Inlines dialog footer JSX to avoid nested component definitions.
plugins/sanity-plugin-hotspot-array/src/useResizeObserver.ts Fixes exhaustive-deps by updating effect dependencies.
plugins/sanity-plugin-hotspot-array/src/useDebouncedCallback.ts Adjusts internal debounced-callback implementation to satisfy hooks rules.
plugins/sanity-plugin-hotspot-array/src/ImageHotspotArray.tsx Updates resize observer wiring to use the revised debounced callback usage.
plugins/@sanity/studio-secrets/src/Settings.tsx Replaces effect-based secrets sync with guarded render-time sync.
plugins/@sanity/personalization-plugin/src/launchDarkly/components/Secrets.tsx Derives settings visibility and simplifies secret propagation.
plugins/@sanity/personalization-plugin/src/growthbook/Components/Secrets.tsx Derives settings visibility and simplifies secret propagation.
plugins/@sanity/embeddings-index-ui/src/referenceInput/SemanticSearchReferenceInput.tsx Prevents ref reads during render by seeding one-time focus behavior via ref.
plugins/@sanity/embeddings-index-ui/src/embeddingsIndexDashboard/IndexEditor.tsx Reworks selected/default index syncing and fixes list keying.
plugins/@sanity/embeddings-index-ui/src/embeddingsIndexDashboard/EmbeddingsIndexTool.tsx Simplifies selection state and defers initial fetch to avoid compiler violations.
plugins/@sanity/cross-dataset-duplicator/src/components/Duplicator.tsx Reworks payload initialization/status fetching to avoid EffectSetState patterns.
plugins/@sanity/color-input/src/react-color/EditableInput.tsx Moves controlled-value syncing to getDerivedStateFromProps + explicit focus tracking.
plugins/@sanity/block-insert-picker/src/blockInsertPicker.tsx Derives cursor rect without effect-driven state syncing.
plugins/@sanity/block-insert-picker/src/blockInsertPicker.test.tsx Adds a provider wrapper to avoid constructed context values and satisfy lint.
plugins/@sanity/assist/src/fieldActions/customFieldActions.tsx Stabilizes config derivation and hook deps for custom field actions.
plugins/@sanity/assist/src/components/ImageContext.tsx Replaces state-based assetRef syncing with ref tracking to avoid compiler issues.
plugins/@sanity/assist/src/assistLayout/RunInstructionProvider.tsx Fixes context memo deps (includes getUserInput) without suppressions.
plugins/@sanity/assist/src/assistInspector/AssistInspector.tsx Avoids ref reads during render by mirroring boundary element via callback ref.
plugins/@sanity/assist/src/assistDocument/RequestRunInstructionProvider.tsx Refactors queued task handling using refs/microtasks to avoid effect setState patterns.
plugins/@sanity/assist/src/assistDocument/hooks/useAssistDocumentContextValue.tsx Restructures synthetic task state to reset per document without effect syncing.
plugins/@sanity/assist/src/assistDocument/components/instruction/PromptInput.tsx Fixes exhaustive-deps by making the “inline blocks” normalization track value/onChange.
plugins/@sanity/assist/src/assistConnectors/AssistConnectorsOverlay.tsx Defers initial redraw via requestAnimationFrame with cleanup.
.changeset/workflow-react-compiler.md Patch changeset for workflow compiler-related fixes (incl. virtualization removal).
.changeset/utils-react-compiler.md Patch changeset for utils useListeningQuery error handling change.
.changeset/studio-secrets-react-compiler.md Patch changeset for studio-secrets state sync refactor.
.changeset/personalization-plugin-react-compiler.md Patch changeset for personalization derived settings behavior.
.changeset/mux-input-react-compiler.md Patch changeset for mux-input compiler/hook fixes.
.changeset/media-react-compiler.md Patch changeset for media dialog/footer inlining + context memoization changes.
.changeset/hotspot-array-react-compiler.md Patch changeset for hotspot-array hook dependency fixes.
.changeset/embeddings-index-ui-react-compiler.md Patch changeset for embeddings-index-ui compiler/hook fixes.
.changeset/cross-dataset-duplicator-react-compiler.md Patch changeset for duplicator EffectSetState fix.
.changeset/color-input-react-compiler.md Patch changeset for color-input controlled state refactor.
.changeset/block-insert-picker-react-compiler.md Patch changeset for block-insert-picker compiler/hook fixes.
.changeset/assist-react-compiler.md Patch changeset for assist compiler/hook fixes.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

options?.directUploads,
options?.locales,
])
}, [options])
Comment on lines +190 to +193
onTimeUpdate={(event) => {
const target = event.currentTarget as EventTarget & {currentTime?: number}
if (typeof target.currentTime === 'number') setCurrentTime(target.currentTime)
}}
Copilot AI review requested due to automatic review settings July 23, 2026 14:25
@changeset-bot

changeset-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ef4d310

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
Name Type
@sanity/assist Patch
@sanity/block-insert-picker Patch
@sanity/cross-dataset-duplicator Patch
@sanity/embeddings-index-ui Patch
sanity-plugin-hotspot-array Patch
sanity-plugin-media Patch
sanity-plugin-mux-input Patch
@sanity/personalization-plugin Patch
@sanity/studio-secrets Patch
sanity-plugin-utils Patch
sanity-plugin-workflow Patch
sanity-plugin-internationalized-array Patch
sanity-plugin-cloudinary Patch
@sanity/sanity-plugin-async-list Patch
sanity-plugin-documents-pane Patch
@sanity/document-internationalization Patch
@sanity/orderable-document-list Patch
@sanity/sfcc Patch
@sanity/form-toolkit Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Prefer startTransition over requestAnimationFrame for the non-urgent
initial redraw force in AssistConnectorsOverlay.
Track whether PromptInput has already rewritten legacy blocks so
onChange runs once on load instead of on every value change.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 56 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

Comment on lines 52 to +60
catchError((err) => {
console.error(err)
setError(err)
setLoading(false)
setData(null)
queueMicrotask(() => {
setError(err)
setLoading(false)
setData(null)
})

return err
return EMPTY
Comment on lines +36 to +46
const fetchFileSize = async () => {
setUrlState((prev) =>
prev.url === url
? {
url,
fileSize: null,
isLoadingFileSize: true,
canSkipFileSizeValidation: false,
}
: prev,
)
Copilot AI review requested due to automatic review settings July 23, 2026 14:31
Merge the inspector boundary element state into the container ref with
useImperativeHandle instead of a decorating callback ref.
Pin the imperative handle generics so HTMLDivElement | null is accepted.
Capture the caret rect in useLayoutEffect again, wrapping setCursorRect
in startTransition to satisfy React Compiler EffectSetState.
Leave EditableInput alone — class-component refactor is handled in
another PR.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 53 out of 54 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Comments suppressed due to low confidence (1)

plugins/sanity-plugin-mux-input/src/components/VideoPlayer.tsx:193

  • onTimeUpdate fires frequently during playback; updating React state on every event will cause the entire VideoPlayer subtree to re-render continuously. Since currentTime is only used for the “edit thumbnail” dialog, consider only recording time updates while that dialog is open (or otherwise avoid per-frame state updates).

Comment on lines 60 to +69
// oxlint-disable-next-line no-unsafe-type-assertion
const data = _data as SanityDocumentWithMetadata[]

const [localDocuments, setLocalDocuments] = useState<SanityDocumentWithMetadata[]>([])
const [localDocuments, setLocalDocuments] = useState<SanityDocumentWithMetadata[]>(() => data)
const [previousData, setPreviousData] = useState(data)

useEffect(() => {
if (data) {
// Fix this later
// oxlint-disable-next-line react/react-compiler
setLocalDocuments(data)
}
}, [data])
if (data !== previousData) {
setPreviousData(data)
setLocalDocuments(data)
}
Copilot AI review requested due to automatic review settings July 23, 2026 14:36

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ef4d310. Configure here.

}
const blockRect = editor.dom.getStartBlockElement(snapshot)?.getBoundingClientRect()
if (blockRect) setCursorRect(blockRect)
if (blockRect) startTransition(() => setCursorRect(blockRect))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deferred popover anchor update

Medium Severity

setCursorRect in useLayoutEffect is wrapped in startTransition, so the anchor update can be deferred past paint. cursorElement returns null until cursorRect is set, so the insert picker can miss its first paint and open late or with a visible flicker.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ef4d310. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 53 out of 54 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Comments suppressed due to low confidence (1)

plugins/sanity-plugin-mux-input/src/components/VideoPlayer.tsx:193

  • onTimeUpdate updates React state on every timeupdate event, which can trigger frequent re-renders during playback and degrade performance even when the edit-thumbnail dialog isn't open. Consider only tracking currentTime while the thumbnail dialog is open (or otherwise throttling/storing it in a ref) so normal playback doesn't cause continuous re-renders.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants