[Fiber] Ensure useEffectEvent reads latest values in forwardRef and memo() Components - #34831
Merged
Conversation
eps1lon
commented
Oct 13, 2025
Comment on lines
+865
to
+866
| logContextValue = fireLogContextValue; | ||
| }, []); |
Collaborator
Author
There was a problem hiding this comment.
The original report registered an interval here. Even after rendering with a new context value, the interval continued to log the initial value.
|
Comparing: 1d68bce...6bec011 Critical size changesIncludes critical production bundles, as well as any change greater than 2%:
Significant size changesIncludes any change greater than 0.2%: (No significant changes) |
forwardRef and memo() ComponentsuseEffectEvent reads latest values in forwardRef and memo() Components
eps1lon
marked this pull request as ready for review
October 13, 2025 08:08
sebmarkbage
approved these changes
Oct 13, 2025
sebmarkbage
pushed a commit
to vercel/next.js
that referenced
this pull request
Oct 14, 2025
[diff react/react@ead92181...d7215b49](react/react@ead9218...d7215b4) <details> <summary>React upstream changes</summary> - react/react#34829 - react/react#34827 - react/react#34824 - react/react#34823 - react/react#34831 - react/react#34821 </details>
SaiKarthikYamavaram
pushed a commit
to SaiKarthikYamavaram/react
that referenced
this pull request
May 15, 2026
…nd `memo()` Components (react#34831)
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Jul 30, 2026
React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Jul 30, 2026
React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
stipsan
added a commit
to sanity-io/ui
that referenced
this pull request
Jul 30, 2026
…ss contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Jul 31, 2026
…ss contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
stipsan
added a commit
to sanity-io/ui
that referenced
this pull request
Jul 31, 2026
* chore: enter changesets prerelease mode on next Enter the `next` prerelease tag, point Changesets and CI/release workflows at the `next` branch, and add a sample major changeset for @sanity/ui so the Version Packages bot can open the first pre-release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2504) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat(ui): tombstone deprecated props, hooks, and components (major) (#2509) * chore(ui): tombstone remaining deprecated props as never Remove runtime fallbacks for deprecated space, grid, MenuButton popover, Popover boundaryElement, Badge mode, and Avatar tone props. Defaults move onto their replacements (gap, gridTemplate*, popover). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(storybook): migrate deprecated space/columns/useElementRect props Replace Stack/Inline/Menu/Tree/TabList/Button `space` with `gap`, Grid `columns`/`rows` with `gridTemplateColumns`/`gridTemplateRows`, and `useElementRect` with `useElementSize` (border size). Drop matching no-deprecated suppressions; leave theme/_compat suppressions alone. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): tombstone deprecated APIs with never types (major) Finish call-site migrations, add throwing-hook tests, and a major changeset documenting removed props/hooks/components and their replacements. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert(ui): keep PortalProvider boundaryElement for PortalContext PortalProvider.boundaryElement still writes PortalContextValue, so it cannot be tombstoned like other deprecated props. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: drop PortalProvider from tombstone changeset notes Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2512) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat: React 19 compiler target and ^19.2 peer deps (#2507) * feat: target React 19 compiler and require react ^19.2 Compile @sanity/ui and @sanity/themer with reactCompiler target '19', drop the now-unnecessary react-compiler-runtime dependency, and tighten react (and react-dom for ui) peer ranges to ^19.2 across published packages. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: mark @sanity/themer bump as major in changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave @sanity/icons and @sanity/logos peer ranges unchanged Only @sanity/ui and @sanity/themer need the React 19.2 peer bump for the compiler target change. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): remove private `_visual-editing` entrypoint (#2513) * feat(ui): remove private `_visual-editing` entrypoint Drop `@sanity/ui/_visual-editing` now that tree-shaking from the main export is sufficient for visual-editing consumers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: stop deep-linking workspace packages into transitive deps Set linkWorkspacePackages to true (not deep) so sanity and @sanity/visual-editing keep registry @sanity/ui until those packages are updated for the removed _visual-editing entrypoint. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(ui): restore Popover max-width after boundaryElement migration (#2514) fix(ui): restore Popover max-width from floatingBoundary After tombstoning `boundaryElement`, max-width only came from BoundaryElementProvider, so migrating to floatingBoundary/referenceBoundary alone dropped constrainSize/preventOverflow width. Fall back to the floating boundary for size, and wrap the Aligned story in BoundaryElementProvider. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2515) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat!: drop CommonJS from @sanity/ui, require Node.js >=22.12 (#2510) * feat!: ship ESM only and require Node.js >=22.12 Drop CommonJS build outputs and `require` export conditions from @sanity/ui, @sanity/color, and @sanity/logos. Raise published package engines to >=22.12 to match sanity. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave color, logos, and icons unchanged Scope the ESM-only / engines bump to @sanity/ui and @sanity/themer only. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): drop custom chunkFileNames, use tsdown defaults Hashed shared-chunk filenames already prevent the entry/chunk collision that dist/_chunks/ was guarding against (#2262). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): restore UserConfig annotation on tsdown config Match themer/logos so the inferred config type stays portable in the package TypeScript program (TS2883). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2516) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * fix: revert @sanity/themer to last published prerelease * Revert "fix: revert @sanity/themer to last published prerelease" This reverts commit e325e53. * feat: replace AnimatePresence with AnimateActivity (#2508) * feat: replace AnimatePresence with AnimateActivity Vendor Motion's AnimateActivity (Activity + exit animations) and use it in Tooltip, Popover, and Toast. Requires React 19.2 (handled separately). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimateActivityProps module-private for knip Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimatePresence for ToastProvider Toasts are mount/unmount list items; AnimatePresence fits that better than Activity-based show/hide. AnimateActivity stays for Tooltip/Popover. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lazy-mount AnimateActivity until first open Keep tooltips/popovers out of the DOM until first shown so hidden Activity nodes do not leak duplicate text into Testing Library queries (e.g. delay-group stories). After first open, Activity still preserves exit animations and state on subsequent hides. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: drop lazy-mount ref, assert tooltip visibility in stories Hidden Activity content is intentionally pre-rendered in the DOM, so the tooltip stories wait for visibility instead of text presence. Flipping animate off while open skips the exit animation, which is acceptable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: await async expect in tooltip story play functions Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: keep closed tooltips/popovers mounted with Activity Wrap the animate=false paths in plain <Activity> instead of unmounting, so open/close preserves state in both modes. Reset the menu's active item via effect cleanup (Activity unmounts effects on hide) so shouldFocus and selected registration behave like a fresh mount on reopen. Update tooltip/menu tests to assert visibility rather than DOM presence, and gate the Recursive popover story's content on open since hidden activities pre-render (an unconditional recursive content would render an infinitely deep hidden tree). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: document why native useEffectEvent is blocked, pin the freshness contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui)!: drop @juggle/resize-observer, use native ResizeObserver (#2518) * fix(ui): drop @juggle/resize-observer, use native ResizeObserver ResizeObserver is available in all browsers Sanity UI targets, so the polyfill and its custom typings are no longer needed. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): remove _ResizeObserver wrapper, use native ResizeObserver directly Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: ban forwardRef, createRef, createElement, Component, PureComponent with oxlint (#2519) feat: ban forwardRef, createRef, createElement, Component, PureComponent via oxlint Adds react entries to eslint/no-restricted-imports in .oxlintrc.json and migrates every @sanity/ui component from forwardRef to React 19 ref-as-prop function components. @sanity/icons and @sanity/logos keep forwardRef through a scoped override since their react peer ranges still include React 18, where refs only attach to forwardRef-wrapped function components. The class ErrorBoundary keeps an inline disable (error boundaries have no function equivalent), and the useGlobalKeyDown freshness-contract test keeps its deliberate forwardRef usage with an inline disable. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore(deps): update renovatebot/github-action action to v46.2.0 (next) (#2521) * Version Packages (next) (#2517) * feat(ui): move heavy-dependency components to dedicated subpath entry points (#2522) * feat(ui): extract static CSS with vanilla-extract into @sanity/ui/styles.css (#2523) Sets up the vanilla-extract build pipeline in @sanity/ui via @sanity/tsdown-config's vanillaExtract option, with inject disabled so the stylesheet is never self-imported: consumers add `import '@sanity/ui/styles.css'` themselves, on the same export path the vanilla-extract based next major already uses. Migrates the first slice of fully static styled-components CSS (SrOnly, Spinner, SpanWithTextOverflow) to colocated .css.ts modules, and wires .css.ts compilation into every consumer of the package's TypeScript source: storybook, the icons app, the ui/themer vitest configs, the docs studio (sanity dev/build), and the docs Next app (Turbopack, via @vanilla-extract/next-plugin). Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: ban class components via react/prefer-function-component Replace the no-restricted-imports ban on Component/PureComponent with react/prefer-function-component (allowErrorBoundary), so ErrorBoundary no longer needs an inline disable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2524) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 2, 2026
…ss contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 2, 2026
* chore: enter changesets prerelease mode on next Enter the `next` prerelease tag, point Changesets and CI/release workflows at the `next` branch, and add a sample major changeset for @sanity/ui so the Version Packages bot can open the first pre-release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2504) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat(ui): tombstone deprecated props, hooks, and components (major) (#2509) * chore(ui): tombstone remaining deprecated props as never Remove runtime fallbacks for deprecated space, grid, MenuButton popover, Popover boundaryElement, Badge mode, and Avatar tone props. Defaults move onto their replacements (gap, gridTemplate*, popover). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(storybook): migrate deprecated space/columns/useElementRect props Replace Stack/Inline/Menu/Tree/TabList/Button `space` with `gap`, Grid `columns`/`rows` with `gridTemplateColumns`/`gridTemplateRows`, and `useElementRect` with `useElementSize` (border size). Drop matching no-deprecated suppressions; leave theme/_compat suppressions alone. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): tombstone deprecated APIs with never types (major) Finish call-site migrations, add throwing-hook tests, and a major changeset documenting removed props/hooks/components and their replacements. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert(ui): keep PortalProvider boundaryElement for PortalContext PortalProvider.boundaryElement still writes PortalContextValue, so it cannot be tombstoned like other deprecated props. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: drop PortalProvider from tombstone changeset notes Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2512) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat: React 19 compiler target and ^19.2 peer deps (#2507) * feat: target React 19 compiler and require react ^19.2 Compile @sanity/ui and @sanity/themer with reactCompiler target '19', drop the now-unnecessary react-compiler-runtime dependency, and tighten react (and react-dom for ui) peer ranges to ^19.2 across published packages. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: mark @sanity/themer bump as major in changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave @sanity/icons and @sanity/logos peer ranges unchanged Only @sanity/ui and @sanity/themer need the React 19.2 peer bump for the compiler target change. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): remove private `_visual-editing` entrypoint (#2513) * feat(ui): remove private `_visual-editing` entrypoint Drop `@sanity/ui/_visual-editing` now that tree-shaking from the main export is sufficient for visual-editing consumers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: stop deep-linking workspace packages into transitive deps Set linkWorkspacePackages to true (not deep) so sanity and @sanity/visual-editing keep registry @sanity/ui until those packages are updated for the removed _visual-editing entrypoint. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(ui): restore Popover max-width after boundaryElement migration (#2514) fix(ui): restore Popover max-width from floatingBoundary After tombstoning `boundaryElement`, max-width only came from BoundaryElementProvider, so migrating to floatingBoundary/referenceBoundary alone dropped constrainSize/preventOverflow width. Fall back to the floating boundary for size, and wrap the Aligned story in BoundaryElementProvider. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2515) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat!: drop CommonJS from @sanity/ui, require Node.js >=22.12 (#2510) * feat!: ship ESM only and require Node.js >=22.12 Drop CommonJS build outputs and `require` export conditions from @sanity/ui, @sanity/color, and @sanity/logos. Raise published package engines to >=22.12 to match sanity. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave color, logos, and icons unchanged Scope the ESM-only / engines bump to @sanity/ui and @sanity/themer only. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): drop custom chunkFileNames, use tsdown defaults Hashed shared-chunk filenames already prevent the entry/chunk collision that dist/_chunks/ was guarding against (#2262). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): restore UserConfig annotation on tsdown config Match themer/logos so the inferred config type stays portable in the package TypeScript program (TS2883). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2516) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * fix: revert @sanity/themer to last published prerelease * Revert "fix: revert @sanity/themer to last published prerelease" This reverts commit e325e53. * feat: replace AnimatePresence with AnimateActivity (#2508) * feat: replace AnimatePresence with AnimateActivity Vendor Motion's AnimateActivity (Activity + exit animations) and use it in Tooltip, Popover, and Toast. Requires React 19.2 (handled separately). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimateActivityProps module-private for knip Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimatePresence for ToastProvider Toasts are mount/unmount list items; AnimatePresence fits that better than Activity-based show/hide. AnimateActivity stays for Tooltip/Popover. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lazy-mount AnimateActivity until first open Keep tooltips/popovers out of the DOM until first shown so hidden Activity nodes do not leak duplicate text into Testing Library queries (e.g. delay-group stories). After first open, Activity still preserves exit animations and state on subsequent hides. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: drop lazy-mount ref, assert tooltip visibility in stories Hidden Activity content is intentionally pre-rendered in the DOM, so the tooltip stories wait for visibility instead of text presence. Flipping animate off while open skips the exit animation, which is acceptable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: await async expect in tooltip story play functions Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: keep closed tooltips/popovers mounted with Activity Wrap the animate=false paths in plain <Activity> instead of unmounting, so open/close preserves state in both modes. Reset the menu's active item via effect cleanup (Activity unmounts effects on hide) so shouldFocus and selected registration behave like a fresh mount on reopen. Update tooltip/menu tests to assert visibility rather than DOM presence, and gate the Recursive popover story's content on open since hidden activities pre-render (an unconditional recursive content would render an infinitely deep hidden tree). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: document why native useEffectEvent is blocked, pin the freshness contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui)!: drop @juggle/resize-observer, use native ResizeObserver (#2518) * fix(ui): drop @juggle/resize-observer, use native ResizeObserver ResizeObserver is available in all browsers Sanity UI targets, so the polyfill and its custom typings are no longer needed. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): remove _ResizeObserver wrapper, use native ResizeObserver directly Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: ban forwardRef, createRef, createElement, Component, PureComponent with oxlint (#2519) feat: ban forwardRef, createRef, createElement, Component, PureComponent via oxlint Adds react entries to eslint/no-restricted-imports in .oxlintrc.json and migrates every @sanity/ui component from forwardRef to React 19 ref-as-prop function components. @sanity/icons and @sanity/logos keep forwardRef through a scoped override since their react peer ranges still include React 18, where refs only attach to forwardRef-wrapped function components. The class ErrorBoundary keeps an inline disable (error boundaries have no function equivalent), and the useGlobalKeyDown freshness-contract test keeps its deliberate forwardRef usage with an inline disable. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore(deps): update renovatebot/github-action action to v46.2.0 (next) (#2521) * Version Packages (next) (#2517) * feat(ui): move heavy-dependency components to dedicated subpath entry points (#2522) * feat(ui): extract static CSS with vanilla-extract into @sanity/ui/styles.css (#2523) Sets up the vanilla-extract build pipeline in @sanity/ui via @sanity/tsdown-config's vanillaExtract option, with inject disabled so the stylesheet is never self-imported: consumers add `import '@sanity/ui/styles.css'` themselves, on the same export path the vanilla-extract based next major already uses. Migrates the first slice of fully static styled-components CSS (SrOnly, Spinner, SpanWithTextOverflow) to colocated .css.ts modules, and wires .css.ts compilation into every consumer of the package's TypeScript source: storybook, the icons app, the ui/themer vitest configs, the docs studio (sanity dev/build), and the docs Next app (Turbopack, via @vanilla-extract/next-plugin). Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: ban class components via react/prefer-function-component Replace the no-restricted-imports ban on Component/PureComponent with react/prefer-function-component (allowErrorBoundary), so ErrorBoundary no longer needs an inline disable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2524) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 5, 2026
…ss contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 5, 2026
* chore: enter changesets prerelease mode on next Enter the `next` prerelease tag, point Changesets and CI/release workflows at the `next` branch, and add a sample major changeset for @sanity/ui so the Version Packages bot can open the first pre-release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2504) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat(ui): tombstone deprecated props, hooks, and components (major) (#2509) * chore(ui): tombstone remaining deprecated props as never Remove runtime fallbacks for deprecated space, grid, MenuButton popover, Popover boundaryElement, Badge mode, and Avatar tone props. Defaults move onto their replacements (gap, gridTemplate*, popover). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(storybook): migrate deprecated space/columns/useElementRect props Replace Stack/Inline/Menu/Tree/TabList/Button `space` with `gap`, Grid `columns`/`rows` with `gridTemplateColumns`/`gridTemplateRows`, and `useElementRect` with `useElementSize` (border size). Drop matching no-deprecated suppressions; leave theme/_compat suppressions alone. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): tombstone deprecated APIs with never types (major) Finish call-site migrations, add throwing-hook tests, and a major changeset documenting removed props/hooks/components and their replacements. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert(ui): keep PortalProvider boundaryElement for PortalContext PortalProvider.boundaryElement still writes PortalContextValue, so it cannot be tombstoned like other deprecated props. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: drop PortalProvider from tombstone changeset notes Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2512) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat: React 19 compiler target and ^19.2 peer deps (#2507) * feat: target React 19 compiler and require react ^19.2 Compile @sanity/ui and @sanity/themer with reactCompiler target '19', drop the now-unnecessary react-compiler-runtime dependency, and tighten react (and react-dom for ui) peer ranges to ^19.2 across published packages. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: mark @sanity/themer bump as major in changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave @sanity/icons and @sanity/logos peer ranges unchanged Only @sanity/ui and @sanity/themer need the React 19.2 peer bump for the compiler target change. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): remove private `_visual-editing` entrypoint (#2513) * feat(ui): remove private `_visual-editing` entrypoint Drop `@sanity/ui/_visual-editing` now that tree-shaking from the main export is sufficient for visual-editing consumers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: stop deep-linking workspace packages into transitive deps Set linkWorkspacePackages to true (not deep) so sanity and @sanity/visual-editing keep registry @sanity/ui until those packages are updated for the removed _visual-editing entrypoint. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(ui): restore Popover max-width after boundaryElement migration (#2514) fix(ui): restore Popover max-width from floatingBoundary After tombstoning `boundaryElement`, max-width only came from BoundaryElementProvider, so migrating to floatingBoundary/referenceBoundary alone dropped constrainSize/preventOverflow width. Fall back to the floating boundary for size, and wrap the Aligned story in BoundaryElementProvider. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2515) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat!: drop CommonJS from @sanity/ui, require Node.js >=22.12 (#2510) * feat!: ship ESM only and require Node.js >=22.12 Drop CommonJS build outputs and `require` export conditions from @sanity/ui, @sanity/color, and @sanity/logos. Raise published package engines to >=22.12 to match sanity. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave color, logos, and icons unchanged Scope the ESM-only / engines bump to @sanity/ui and @sanity/themer only. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): drop custom chunkFileNames, use tsdown defaults Hashed shared-chunk filenames already prevent the entry/chunk collision that dist/_chunks/ was guarding against (#2262). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): restore UserConfig annotation on tsdown config Match themer/logos so the inferred config type stays portable in the package TypeScript program (TS2883). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2516) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * fix: revert @sanity/themer to last published prerelease * Revert "fix: revert @sanity/themer to last published prerelease" This reverts commit e325e53. * feat: replace AnimatePresence with AnimateActivity (#2508) * feat: replace AnimatePresence with AnimateActivity Vendor Motion's AnimateActivity (Activity + exit animations) and use it in Tooltip, Popover, and Toast. Requires React 19.2 (handled separately). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimateActivityProps module-private for knip Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimatePresence for ToastProvider Toasts are mount/unmount list items; AnimatePresence fits that better than Activity-based show/hide. AnimateActivity stays for Tooltip/Popover. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lazy-mount AnimateActivity until first open Keep tooltips/popovers out of the DOM until first shown so hidden Activity nodes do not leak duplicate text into Testing Library queries (e.g. delay-group stories). After first open, Activity still preserves exit animations and state on subsequent hides. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: drop lazy-mount ref, assert tooltip visibility in stories Hidden Activity content is intentionally pre-rendered in the DOM, so the tooltip stories wait for visibility instead of text presence. Flipping animate off while open skips the exit animation, which is acceptable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: await async expect in tooltip story play functions Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: keep closed tooltips/popovers mounted with Activity Wrap the animate=false paths in plain <Activity> instead of unmounting, so open/close preserves state in both modes. Reset the menu's active item via effect cleanup (Activity unmounts effects on hide) so shouldFocus and selected registration behave like a fresh mount on reopen. Update tooltip/menu tests to assert visibility rather than DOM presence, and gate the Recursive popover story's content on open since hidden activities pre-render (an unconditional recursive content would render an infinitely deep hidden tree). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: document why native useEffectEvent is blocked, pin the freshness contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui)!: drop @juggle/resize-observer, use native ResizeObserver (#2518) * fix(ui): drop @juggle/resize-observer, use native ResizeObserver ResizeObserver is available in all browsers Sanity UI targets, so the polyfill and its custom typings are no longer needed. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): remove _ResizeObserver wrapper, use native ResizeObserver directly Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: ban forwardRef, createRef, createElement, Component, PureComponent with oxlint (#2519) feat: ban forwardRef, createRef, createElement, Component, PureComponent via oxlint Adds react entries to eslint/no-restricted-imports in .oxlintrc.json and migrates every @sanity/ui component from forwardRef to React 19 ref-as-prop function components. @sanity/icons and @sanity/logos keep forwardRef through a scoped override since their react peer ranges still include React 18, where refs only attach to forwardRef-wrapped function components. The class ErrorBoundary keeps an inline disable (error boundaries have no function equivalent), and the useGlobalKeyDown freshness-contract test keeps its deliberate forwardRef usage with an inline disable. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore(deps): update renovatebot/github-action action to v46.2.0 (next) (#2521) * Version Packages (next) (#2517) * feat(ui): move heavy-dependency components to dedicated subpath entry points (#2522) * feat(ui): extract static CSS with vanilla-extract into @sanity/ui/styles.css (#2523) Sets up the vanilla-extract build pipeline in @sanity/ui via @sanity/tsdown-config's vanillaExtract option, with inject disabled so the stylesheet is never self-imported: consumers add `import '@sanity/ui/styles.css'` themselves, on the same export path the vanilla-extract based next major already uses. Migrates the first slice of fully static styled-components CSS (SrOnly, Spinner, SpanWithTextOverflow) to colocated .css.ts modules, and wires .css.ts compilation into every consumer of the package's TypeScript source: storybook, the icons app, the ui/themer vitest configs, the docs studio (sanity dev/build), and the docs Next app (Turbopack, via @vanilla-extract/next-plugin). Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: ban class components via react/prefer-function-component Replace the no-restricted-imports ban on Component/PureComponent with react/prefer-function-component (allowErrorBoundary), so ErrorBoundary no longer needs an inline disable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2524) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 5, 2026
…ss contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 5, 2026
* chore: enter changesets prerelease mode on next Enter the `next` prerelease tag, point Changesets and CI/release workflows at the `next` branch, and add a sample major changeset for @sanity/ui so the Version Packages bot can open the first pre-release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2504) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat(ui): tombstone deprecated props, hooks, and components (major) (#2509) * chore(ui): tombstone remaining deprecated props as never Remove runtime fallbacks for deprecated space, grid, MenuButton popover, Popover boundaryElement, Badge mode, and Avatar tone props. Defaults move onto their replacements (gap, gridTemplate*, popover). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(storybook): migrate deprecated space/columns/useElementRect props Replace Stack/Inline/Menu/Tree/TabList/Button `space` with `gap`, Grid `columns`/`rows` with `gridTemplateColumns`/`gridTemplateRows`, and `useElementRect` with `useElementSize` (border size). Drop matching no-deprecated suppressions; leave theme/_compat suppressions alone. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): tombstone deprecated APIs with never types (major) Finish call-site migrations, add throwing-hook tests, and a major changeset documenting removed props/hooks/components and their replacements. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert(ui): keep PortalProvider boundaryElement for PortalContext PortalProvider.boundaryElement still writes PortalContextValue, so it cannot be tombstoned like other deprecated props. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: drop PortalProvider from tombstone changeset notes Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2512) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat: React 19 compiler target and ^19.2 peer deps (#2507) * feat: target React 19 compiler and require react ^19.2 Compile @sanity/ui and @sanity/themer with reactCompiler target '19', drop the now-unnecessary react-compiler-runtime dependency, and tighten react (and react-dom for ui) peer ranges to ^19.2 across published packages. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: mark @sanity/themer bump as major in changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave @sanity/icons and @sanity/logos peer ranges unchanged Only @sanity/ui and @sanity/themer need the React 19.2 peer bump for the compiler target change. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): remove private `_visual-editing` entrypoint (#2513) * feat(ui): remove private `_visual-editing` entrypoint Drop `@sanity/ui/_visual-editing` now that tree-shaking from the main export is sufficient for visual-editing consumers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: stop deep-linking workspace packages into transitive deps Set linkWorkspacePackages to true (not deep) so sanity and @sanity/visual-editing keep registry @sanity/ui until those packages are updated for the removed _visual-editing entrypoint. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(ui): restore Popover max-width after boundaryElement migration (#2514) fix(ui): restore Popover max-width from floatingBoundary After tombstoning `boundaryElement`, max-width only came from BoundaryElementProvider, so migrating to floatingBoundary/referenceBoundary alone dropped constrainSize/preventOverflow width. Fall back to the floating boundary for size, and wrap the Aligned story in BoundaryElementProvider. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2515) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat!: drop CommonJS from @sanity/ui, require Node.js >=22.12 (#2510) * feat!: ship ESM only and require Node.js >=22.12 Drop CommonJS build outputs and `require` export conditions from @sanity/ui, @sanity/color, and @sanity/logos. Raise published package engines to >=22.12 to match sanity. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave color, logos, and icons unchanged Scope the ESM-only / engines bump to @sanity/ui and @sanity/themer only. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): drop custom chunkFileNames, use tsdown defaults Hashed shared-chunk filenames already prevent the entry/chunk collision that dist/_chunks/ was guarding against (#2262). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): restore UserConfig annotation on tsdown config Match themer/logos so the inferred config type stays portable in the package TypeScript program (TS2883). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2516) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * fix: revert @sanity/themer to last published prerelease * Revert "fix: revert @sanity/themer to last published prerelease" This reverts commit e325e53. * feat: replace AnimatePresence with AnimateActivity (#2508) * feat: replace AnimatePresence with AnimateActivity Vendor Motion's AnimateActivity (Activity + exit animations) and use it in Tooltip, Popover, and Toast. Requires React 19.2 (handled separately). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimateActivityProps module-private for knip Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimatePresence for ToastProvider Toasts are mount/unmount list items; AnimatePresence fits that better than Activity-based show/hide. AnimateActivity stays for Tooltip/Popover. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lazy-mount AnimateActivity until first open Keep tooltips/popovers out of the DOM until first shown so hidden Activity nodes do not leak duplicate text into Testing Library queries (e.g. delay-group stories). After first open, Activity still preserves exit animations and state on subsequent hides. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: drop lazy-mount ref, assert tooltip visibility in stories Hidden Activity content is intentionally pre-rendered in the DOM, so the tooltip stories wait for visibility instead of text presence. Flipping animate off while open skips the exit animation, which is acceptable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: await async expect in tooltip story play functions Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: keep closed tooltips/popovers mounted with Activity Wrap the animate=false paths in plain <Activity> instead of unmounting, so open/close preserves state in both modes. Reset the menu's active item via effect cleanup (Activity unmounts effects on hide) so shouldFocus and selected registration behave like a fresh mount on reopen. Update tooltip/menu tests to assert visibility rather than DOM presence, and gate the Recursive popover story's content on open since hidden activities pre-render (an unconditional recursive content would render an infinitely deep hidden tree). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: document why native useEffectEvent is blocked, pin the freshness contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui)!: drop @juggle/resize-observer, use native ResizeObserver (#2518) * fix(ui): drop @juggle/resize-observer, use native ResizeObserver ResizeObserver is available in all browsers Sanity UI targets, so the polyfill and its custom typings are no longer needed. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): remove _ResizeObserver wrapper, use native ResizeObserver directly Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: ban forwardRef, createRef, createElement, Component, PureComponent with oxlint (#2519) feat: ban forwardRef, createRef, createElement, Component, PureComponent via oxlint Adds react entries to eslint/no-restricted-imports in .oxlintrc.json and migrates every @sanity/ui component from forwardRef to React 19 ref-as-prop function components. @sanity/icons and @sanity/logos keep forwardRef through a scoped override since their react peer ranges still include React 18, where refs only attach to forwardRef-wrapped function components. The class ErrorBoundary keeps an inline disable (error boundaries have no function equivalent), and the useGlobalKeyDown freshness-contract test keeps its deliberate forwardRef usage with an inline disable. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore(deps): update renovatebot/github-action action to v46.2.0 (next) (#2521) * Version Packages (next) (#2517) * feat(ui): move heavy-dependency components to dedicated subpath entry points (#2522) * feat(ui): extract static CSS with vanilla-extract into @sanity/ui/styles.css (#2523) Sets up the vanilla-extract build pipeline in @sanity/ui via @sanity/tsdown-config's vanillaExtract option, with inject disabled so the stylesheet is never self-imported: consumers add `import '@sanity/ui/styles.css'` themselves, on the same export path the vanilla-extract based next major already uses. Migrates the first slice of fully static styled-components CSS (SrOnly, Spinner, SpanWithTextOverflow) to colocated .css.ts modules, and wires .css.ts compilation into every consumer of the package's TypeScript source: storybook, the icons app, the ui/themer vitest configs, the docs studio (sanity dev/build), and the docs Next app (Turbopack, via @vanilla-extract/next-plugin). Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: ban class components via react/prefer-function-component Replace the no-restricted-imports ban on Component/PureComponent with react/prefer-function-component (allowErrorBoundary), so ErrorBoundary no longer needs an inline disable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2524) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 5, 2026
…ss contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 5, 2026
* chore: enter changesets prerelease mode on next Enter the `next` prerelease tag, point Changesets and CI/release workflows at the `next` branch, and add a sample major changeset for @sanity/ui so the Version Packages bot can open the first pre-release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2504) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat(ui): tombstone deprecated props, hooks, and components (major) (#2509) * chore(ui): tombstone remaining deprecated props as never Remove runtime fallbacks for deprecated space, grid, MenuButton popover, Popover boundaryElement, Badge mode, and Avatar tone props. Defaults move onto their replacements (gap, gridTemplate*, popover). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(storybook): migrate deprecated space/columns/useElementRect props Replace Stack/Inline/Menu/Tree/TabList/Button `space` with `gap`, Grid `columns`/`rows` with `gridTemplateColumns`/`gridTemplateRows`, and `useElementRect` with `useElementSize` (border size). Drop matching no-deprecated suppressions; leave theme/_compat suppressions alone. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): tombstone deprecated APIs with never types (major) Finish call-site migrations, add throwing-hook tests, and a major changeset documenting removed props/hooks/components and their replacements. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert(ui): keep PortalProvider boundaryElement for PortalContext PortalProvider.boundaryElement still writes PortalContextValue, so it cannot be tombstoned like other deprecated props. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: drop PortalProvider from tombstone changeset notes Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2512) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat: React 19 compiler target and ^19.2 peer deps (#2507) * feat: target React 19 compiler and require react ^19.2 Compile @sanity/ui and @sanity/themer with reactCompiler target '19', drop the now-unnecessary react-compiler-runtime dependency, and tighten react (and react-dom for ui) peer ranges to ^19.2 across published packages. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: mark @sanity/themer bump as major in changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave @sanity/icons and @sanity/logos peer ranges unchanged Only @sanity/ui and @sanity/themer need the React 19.2 peer bump for the compiler target change. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): remove private `_visual-editing` entrypoint (#2513) * feat(ui): remove private `_visual-editing` entrypoint Drop `@sanity/ui/_visual-editing` now that tree-shaking from the main export is sufficient for visual-editing consumers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: stop deep-linking workspace packages into transitive deps Set linkWorkspacePackages to true (not deep) so sanity and @sanity/visual-editing keep registry @sanity/ui until those packages are updated for the removed _visual-editing entrypoint. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(ui): restore Popover max-width after boundaryElement migration (#2514) fix(ui): restore Popover max-width from floatingBoundary After tombstoning `boundaryElement`, max-width only came from BoundaryElementProvider, so migrating to floatingBoundary/referenceBoundary alone dropped constrainSize/preventOverflow width. Fall back to the floating boundary for size, and wrap the Aligned story in BoundaryElementProvider. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2515) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat!: drop CommonJS from @sanity/ui, require Node.js >=22.12 (#2510) * feat!: ship ESM only and require Node.js >=22.12 Drop CommonJS build outputs and `require` export conditions from @sanity/ui, @sanity/color, and @sanity/logos. Raise published package engines to >=22.12 to match sanity. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave color, logos, and icons unchanged Scope the ESM-only / engines bump to @sanity/ui and @sanity/themer only. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): drop custom chunkFileNames, use tsdown defaults Hashed shared-chunk filenames already prevent the entry/chunk collision that dist/_chunks/ was guarding against (#2262). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): restore UserConfig annotation on tsdown config Match themer/logos so the inferred config type stays portable in the package TypeScript program (TS2883). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2516) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * fix: revert @sanity/themer to last published prerelease * Revert "fix: revert @sanity/themer to last published prerelease" This reverts commit e325e53. * feat: replace AnimatePresence with AnimateActivity (#2508) * feat: replace AnimatePresence with AnimateActivity Vendor Motion's AnimateActivity (Activity + exit animations) and use it in Tooltip, Popover, and Toast. Requires React 19.2 (handled separately). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimateActivityProps module-private for knip Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimatePresence for ToastProvider Toasts are mount/unmount list items; AnimatePresence fits that better than Activity-based show/hide. AnimateActivity stays for Tooltip/Popover. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lazy-mount AnimateActivity until first open Keep tooltips/popovers out of the DOM until first shown so hidden Activity nodes do not leak duplicate text into Testing Library queries (e.g. delay-group stories). After first open, Activity still preserves exit animations and state on subsequent hides. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: drop lazy-mount ref, assert tooltip visibility in stories Hidden Activity content is intentionally pre-rendered in the DOM, so the tooltip stories wait for visibility instead of text presence. Flipping animate off while open skips the exit animation, which is acceptable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: await async expect in tooltip story play functions Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: keep closed tooltips/popovers mounted with Activity Wrap the animate=false paths in plain <Activity> instead of unmounting, so open/close preserves state in both modes. Reset the menu's active item via effect cleanup (Activity unmounts effects on hide) so shouldFocus and selected registration behave like a fresh mount on reopen. Update tooltip/menu tests to assert visibility rather than DOM presence, and gate the Recursive popover story's content on open since hidden activities pre-render (an unconditional recursive content would render an infinitely deep hidden tree). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: document why native useEffectEvent is blocked, pin the freshness contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui)!: drop @juggle/resize-observer, use native ResizeObserver (#2518) * fix(ui): drop @juggle/resize-observer, use native ResizeObserver ResizeObserver is available in all browsers Sanity UI targets, so the polyfill and its custom typings are no longer needed. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): remove _ResizeObserver wrapper, use native ResizeObserver directly Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: ban forwardRef, createRef, createElement, Component, PureComponent with oxlint (#2519) feat: ban forwardRef, createRef, createElement, Component, PureComponent via oxlint Adds react entries to eslint/no-restricted-imports in .oxlintrc.json and migrates every @sanity/ui component from forwardRef to React 19 ref-as-prop function components. @sanity/icons and @sanity/logos keep forwardRef through a scoped override since their react peer ranges still include React 18, where refs only attach to forwardRef-wrapped function components. The class ErrorBoundary keeps an inline disable (error boundaries have no function equivalent), and the useGlobalKeyDown freshness-contract test keeps its deliberate forwardRef usage with an inline disable. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore(deps): update renovatebot/github-action action to v46.2.0 (next) (#2521) * Version Packages (next) (#2517) * feat(ui): move heavy-dependency components to dedicated subpath entry points (#2522) * feat(ui): extract static CSS with vanilla-extract into @sanity/ui/styles.css (#2523) Sets up the vanilla-extract build pipeline in @sanity/ui via @sanity/tsdown-config's vanillaExtract option, with inject disabled so the stylesheet is never self-imported: consumers add `import '@sanity/ui/styles.css'` themselves, on the same export path the vanilla-extract based next major already uses. Migrates the first slice of fully static styled-components CSS (SrOnly, Spinner, SpanWithTextOverflow) to colocated .css.ts modules, and wires .css.ts compilation into every consumer of the package's TypeScript source: storybook, the icons app, the ui/themer vitest configs, the docs studio (sanity dev/build), and the docs Next app (Turbopack, via @vanilla-extract/next-plugin). Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: ban class components via react/prefer-function-component Replace the no-restricted-imports ban on Component/PureComponent with react/prefer-function-component (allowErrorBoundary), so ErrorBoundary no longer needs an inline disable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2524) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 6, 2026
…ss contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 6, 2026
* chore: enter changesets prerelease mode on next Enter the `next` prerelease tag, point Changesets and CI/release workflows at the `next` branch, and add a sample major changeset for @sanity/ui so the Version Packages bot can open the first pre-release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2504) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat(ui): tombstone deprecated props, hooks, and components (major) (#2509) * chore(ui): tombstone remaining deprecated props as never Remove runtime fallbacks for deprecated space, grid, MenuButton popover, Popover boundaryElement, Badge mode, and Avatar tone props. Defaults move onto their replacements (gap, gridTemplate*, popover). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(storybook): migrate deprecated space/columns/useElementRect props Replace Stack/Inline/Menu/Tree/TabList/Button `space` with `gap`, Grid `columns`/`rows` with `gridTemplateColumns`/`gridTemplateRows`, and `useElementRect` with `useElementSize` (border size). Drop matching no-deprecated suppressions; leave theme/_compat suppressions alone. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): tombstone deprecated APIs with never types (major) Finish call-site migrations, add throwing-hook tests, and a major changeset documenting removed props/hooks/components and their replacements. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert(ui): keep PortalProvider boundaryElement for PortalContext PortalProvider.boundaryElement still writes PortalContextValue, so it cannot be tombstoned like other deprecated props. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: drop PortalProvider from tombstone changeset notes Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2512) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat: React 19 compiler target and ^19.2 peer deps (#2507) * feat: target React 19 compiler and require react ^19.2 Compile @sanity/ui and @sanity/themer with reactCompiler target '19', drop the now-unnecessary react-compiler-runtime dependency, and tighten react (and react-dom for ui) peer ranges to ^19.2 across published packages. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: mark @sanity/themer bump as major in changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave @sanity/icons and @sanity/logos peer ranges unchanged Only @sanity/ui and @sanity/themer need the React 19.2 peer bump for the compiler target change. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): remove private `_visual-editing` entrypoint (#2513) * feat(ui): remove private `_visual-editing` entrypoint Drop `@sanity/ui/_visual-editing` now that tree-shaking from the main export is sufficient for visual-editing consumers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: stop deep-linking workspace packages into transitive deps Set linkWorkspacePackages to true (not deep) so sanity and @sanity/visual-editing keep registry @sanity/ui until those packages are updated for the removed _visual-editing entrypoint. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(ui): restore Popover max-width after boundaryElement migration (#2514) fix(ui): restore Popover max-width from floatingBoundary After tombstoning `boundaryElement`, max-width only came from BoundaryElementProvider, so migrating to floatingBoundary/referenceBoundary alone dropped constrainSize/preventOverflow width. Fall back to the floating boundary for size, and wrap the Aligned story in BoundaryElementProvider. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2515) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat!: drop CommonJS from @sanity/ui, require Node.js >=22.12 (#2510) * feat!: ship ESM only and require Node.js >=22.12 Drop CommonJS build outputs and `require` export conditions from @sanity/ui, @sanity/color, and @sanity/logos. Raise published package engines to >=22.12 to match sanity. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave color, logos, and icons unchanged Scope the ESM-only / engines bump to @sanity/ui and @sanity/themer only. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): drop custom chunkFileNames, use tsdown defaults Hashed shared-chunk filenames already prevent the entry/chunk collision that dist/_chunks/ was guarding against (#2262). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): restore UserConfig annotation on tsdown config Match themer/logos so the inferred config type stays portable in the package TypeScript program (TS2883). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2516) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * fix: revert @sanity/themer to last published prerelease * Revert "fix: revert @sanity/themer to last published prerelease" This reverts commit e325e53. * feat: replace AnimatePresence with AnimateActivity (#2508) * feat: replace AnimatePresence with AnimateActivity Vendor Motion's AnimateActivity (Activity + exit animations) and use it in Tooltip, Popover, and Toast. Requires React 19.2 (handled separately). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimateActivityProps module-private for knip Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimatePresence for ToastProvider Toasts are mount/unmount list items; AnimatePresence fits that better than Activity-based show/hide. AnimateActivity stays for Tooltip/Popover. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lazy-mount AnimateActivity until first open Keep tooltips/popovers out of the DOM until first shown so hidden Activity nodes do not leak duplicate text into Testing Library queries (e.g. delay-group stories). After first open, Activity still preserves exit animations and state on subsequent hides. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: drop lazy-mount ref, assert tooltip visibility in stories Hidden Activity content is intentionally pre-rendered in the DOM, so the tooltip stories wait for visibility instead of text presence. Flipping animate off while open skips the exit animation, which is acceptable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: await async expect in tooltip story play functions Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: keep closed tooltips/popovers mounted with Activity Wrap the animate=false paths in plain <Activity> instead of unmounting, so open/close preserves state in both modes. Reset the menu's active item via effect cleanup (Activity unmounts effects on hide) so shouldFocus and selected registration behave like a fresh mount on reopen. Update tooltip/menu tests to assert visibility rather than DOM presence, and gate the Recursive popover story's content on open since hidden activities pre-render (an unconditional recursive content would render an infinitely deep hidden tree). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: document why native useEffectEvent is blocked, pin the freshness contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui)!: drop @juggle/resize-observer, use native ResizeObserver (#2518) * fix(ui): drop @juggle/resize-observer, use native ResizeObserver ResizeObserver is available in all browsers Sanity UI targets, so the polyfill and its custom typings are no longer needed. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): remove _ResizeObserver wrapper, use native ResizeObserver directly Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: ban forwardRef, createRef, createElement, Component, PureComponent with oxlint (#2519) feat: ban forwardRef, createRef, createElement, Component, PureComponent via oxlint Adds react entries to eslint/no-restricted-imports in .oxlintrc.json and migrates every @sanity/ui component from forwardRef to React 19 ref-as-prop function components. @sanity/icons and @sanity/logos keep forwardRef through a scoped override since their react peer ranges still include React 18, where refs only attach to forwardRef-wrapped function components. The class ErrorBoundary keeps an inline disable (error boundaries have no function equivalent), and the useGlobalKeyDown freshness-contract test keeps its deliberate forwardRef usage with an inline disable. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore(deps): update renovatebot/github-action action to v46.2.0 (next) (#2521) * Version Packages (next) (#2517) * feat(ui): move heavy-dependency components to dedicated subpath entry points (#2522) * feat(ui): extract static CSS with vanilla-extract into @sanity/ui/styles.css (#2523) Sets up the vanilla-extract build pipeline in @sanity/ui via @sanity/tsdown-config's vanillaExtract option, with inject disabled so the stylesheet is never self-imported: consumers add `import '@sanity/ui/styles.css'` themselves, on the same export path the vanilla-extract based next major already uses. Migrates the first slice of fully static styled-components CSS (SrOnly, Spinner, SpanWithTextOverflow) to colocated .css.ts modules, and wires .css.ts compilation into every consumer of the package's TypeScript source: storybook, the icons app, the ui/themer vitest configs, the docs studio (sanity dev/build), and the docs Next app (Turbopack, via @vanilla-extract/next-plugin). Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: ban class components via react/prefer-function-component Replace the no-restricted-imports ban on Component/PureComponent with react/prefer-function-component (allowErrorBoundary), so ErrorBoundary no longer needs an inline disable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2524) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 7, 2026
…ss contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 7, 2026
* chore: enter changesets prerelease mode on next Enter the `next` prerelease tag, point Changesets and CI/release workflows at the `next` branch, and add a sample major changeset for @sanity/ui so the Version Packages bot can open the first pre-release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2504) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat(ui): tombstone deprecated props, hooks, and components (major) (#2509) * chore(ui): tombstone remaining deprecated props as never Remove runtime fallbacks for deprecated space, grid, MenuButton popover, Popover boundaryElement, Badge mode, and Avatar tone props. Defaults move onto their replacements (gap, gridTemplate*, popover). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(storybook): migrate deprecated space/columns/useElementRect props Replace Stack/Inline/Menu/Tree/TabList/Button `space` with `gap`, Grid `columns`/`rows` with `gridTemplateColumns`/`gridTemplateRows`, and `useElementRect` with `useElementSize` (border size). Drop matching no-deprecated suppressions; leave theme/_compat suppressions alone. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): tombstone deprecated APIs with never types (major) Finish call-site migrations, add throwing-hook tests, and a major changeset documenting removed props/hooks/components and their replacements. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert(ui): keep PortalProvider boundaryElement for PortalContext PortalProvider.boundaryElement still writes PortalContextValue, so it cannot be tombstoned like other deprecated props. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: drop PortalProvider from tombstone changeset notes Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2512) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat: React 19 compiler target and ^19.2 peer deps (#2507) * feat: target React 19 compiler and require react ^19.2 Compile @sanity/ui and @sanity/themer with reactCompiler target '19', drop the now-unnecessary react-compiler-runtime dependency, and tighten react (and react-dom for ui) peer ranges to ^19.2 across published packages. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: mark @sanity/themer bump as major in changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave @sanity/icons and @sanity/logos peer ranges unchanged Only @sanity/ui and @sanity/themer need the React 19.2 peer bump for the compiler target change. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): remove private `_visual-editing` entrypoint (#2513) * feat(ui): remove private `_visual-editing` entrypoint Drop `@sanity/ui/_visual-editing` now that tree-shaking from the main export is sufficient for visual-editing consumers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: stop deep-linking workspace packages into transitive deps Set linkWorkspacePackages to true (not deep) so sanity and @sanity/visual-editing keep registry @sanity/ui until those packages are updated for the removed _visual-editing entrypoint. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(ui): restore Popover max-width after boundaryElement migration (#2514) fix(ui): restore Popover max-width from floatingBoundary After tombstoning `boundaryElement`, max-width only came from BoundaryElementProvider, so migrating to floatingBoundary/referenceBoundary alone dropped constrainSize/preventOverflow width. Fall back to the floating boundary for size, and wrap the Aligned story in BoundaryElementProvider. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2515) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat!: drop CommonJS from @sanity/ui, require Node.js >=22.12 (#2510) * feat!: ship ESM only and require Node.js >=22.12 Drop CommonJS build outputs and `require` export conditions from @sanity/ui, @sanity/color, and @sanity/logos. Raise published package engines to >=22.12 to match sanity. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave color, logos, and icons unchanged Scope the ESM-only / engines bump to @sanity/ui and @sanity/themer only. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): drop custom chunkFileNames, use tsdown defaults Hashed shared-chunk filenames already prevent the entry/chunk collision that dist/_chunks/ was guarding against (#2262). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): restore UserConfig annotation on tsdown config Match themer/logos so the inferred config type stays portable in the package TypeScript program (TS2883). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2516) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * fix: revert @sanity/themer to last published prerelease * Revert "fix: revert @sanity/themer to last published prerelease" This reverts commit e325e53. * feat: replace AnimatePresence with AnimateActivity (#2508) * feat: replace AnimatePresence with AnimateActivity Vendor Motion's AnimateActivity (Activity + exit animations) and use it in Tooltip, Popover, and Toast. Requires React 19.2 (handled separately). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimateActivityProps module-private for knip Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimatePresence for ToastProvider Toasts are mount/unmount list items; AnimatePresence fits that better than Activity-based show/hide. AnimateActivity stays for Tooltip/Popover. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lazy-mount AnimateActivity until first open Keep tooltips/popovers out of the DOM until first shown so hidden Activity nodes do not leak duplicate text into Testing Library queries (e.g. delay-group stories). After first open, Activity still preserves exit animations and state on subsequent hides. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: drop lazy-mount ref, assert tooltip visibility in stories Hidden Activity content is intentionally pre-rendered in the DOM, so the tooltip stories wait for visibility instead of text presence. Flipping animate off while open skips the exit animation, which is acceptable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: await async expect in tooltip story play functions Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: keep closed tooltips/popovers mounted with Activity Wrap the animate=false paths in plain <Activity> instead of unmounting, so open/close preserves state in both modes. Reset the menu's active item via effect cleanup (Activity unmounts effects on hide) so shouldFocus and selected registration behave like a fresh mount on reopen. Update tooltip/menu tests to assert visibility rather than DOM presence, and gate the Recursive popover story's content on open since hidden activities pre-render (an unconditional recursive content would render an infinitely deep hidden tree). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: document why native useEffectEvent is blocked, pin the freshness contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui)!: drop @juggle/resize-observer, use native ResizeObserver (#2518) * fix(ui): drop @juggle/resize-observer, use native ResizeObserver ResizeObserver is available in all browsers Sanity UI targets, so the polyfill and its custom typings are no longer needed. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): remove _ResizeObserver wrapper, use native ResizeObserver directly Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: ban forwardRef, createRef, createElement, Component, PureComponent with oxlint (#2519) feat: ban forwardRef, createRef, createElement, Component, PureComponent via oxlint Adds react entries to eslint/no-restricted-imports in .oxlintrc.json and migrates every @sanity/ui component from forwardRef to React 19 ref-as-prop function components. @sanity/icons and @sanity/logos keep forwardRef through a scoped override since their react peer ranges still include React 18, where refs only attach to forwardRef-wrapped function components. The class ErrorBoundary keeps an inline disable (error boundaries have no function equivalent), and the useGlobalKeyDown freshness-contract test keeps its deliberate forwardRef usage with an inline disable. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore(deps): update renovatebot/github-action action to v46.2.0 (next) (#2521) * Version Packages (next) (#2517) * feat(ui): move heavy-dependency components to dedicated subpath entry points (#2522) * feat(ui): extract static CSS with vanilla-extract into @sanity/ui/styles.css (#2523) Sets up the vanilla-extract build pipeline in @sanity/ui via @sanity/tsdown-config's vanillaExtract option, with inject disabled so the stylesheet is never self-imported: consumers add `import '@sanity/ui/styles.css'` themselves, on the same export path the vanilla-extract based next major already uses. Migrates the first slice of fully static styled-components CSS (SrOnly, Spinner, SpanWithTextOverflow) to colocated .css.ts modules, and wires .css.ts compilation into every consumer of the package's TypeScript source: storybook, the icons app, the ui/themer vitest configs, the docs studio (sanity dev/build), and the docs Next app (Turbopack, via @vanilla-extract/next-plugin). Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: ban class components via react/prefer-function-component Replace the no-restricted-imports ban on Component/PureComponent with react/prefer-function-component (allowErrorBoundary), so ErrorBoundary no longer needs an inline disable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2524) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 7, 2026
…ss contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 7, 2026
* chore: enter changesets prerelease mode on next Enter the `next` prerelease tag, point Changesets and CI/release workflows at the `next` branch, and add a sample major changeset for @sanity/ui so the Version Packages bot can open the first pre-release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2504) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat(ui): tombstone deprecated props, hooks, and components (major) (#2509) * chore(ui): tombstone remaining deprecated props as never Remove runtime fallbacks for deprecated space, grid, MenuButton popover, Popover boundaryElement, Badge mode, and Avatar tone props. Defaults move onto their replacements (gap, gridTemplate*, popover). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(storybook): migrate deprecated space/columns/useElementRect props Replace Stack/Inline/Menu/Tree/TabList/Button `space` with `gap`, Grid `columns`/`rows` with `gridTemplateColumns`/`gridTemplateRows`, and `useElementRect` with `useElementSize` (border size). Drop matching no-deprecated suppressions; leave theme/_compat suppressions alone. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): tombstone deprecated APIs with never types (major) Finish call-site migrations, add throwing-hook tests, and a major changeset documenting removed props/hooks/components and their replacements. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert(ui): keep PortalProvider boundaryElement for PortalContext PortalProvider.boundaryElement still writes PortalContextValue, so it cannot be tombstoned like other deprecated props. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: drop PortalProvider from tombstone changeset notes Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2512) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat: React 19 compiler target and ^19.2 peer deps (#2507) * feat: target React 19 compiler and require react ^19.2 Compile @sanity/ui and @sanity/themer with reactCompiler target '19', drop the now-unnecessary react-compiler-runtime dependency, and tighten react (and react-dom for ui) peer ranges to ^19.2 across published packages. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: mark @sanity/themer bump as major in changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave @sanity/icons and @sanity/logos peer ranges unchanged Only @sanity/ui and @sanity/themer need the React 19.2 peer bump for the compiler target change. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): remove private `_visual-editing` entrypoint (#2513) * feat(ui): remove private `_visual-editing` entrypoint Drop `@sanity/ui/_visual-editing` now that tree-shaking from the main export is sufficient for visual-editing consumers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: stop deep-linking workspace packages into transitive deps Set linkWorkspacePackages to true (not deep) so sanity and @sanity/visual-editing keep registry @sanity/ui until those packages are updated for the removed _visual-editing entrypoint. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(ui): restore Popover max-width after boundaryElement migration (#2514) fix(ui): restore Popover max-width from floatingBoundary After tombstoning `boundaryElement`, max-width only came from BoundaryElementProvider, so migrating to floatingBoundary/referenceBoundary alone dropped constrainSize/preventOverflow width. Fall back to the floating boundary for size, and wrap the Aligned story in BoundaryElementProvider. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2515) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat!: drop CommonJS from @sanity/ui, require Node.js >=22.12 (#2510) * feat!: ship ESM only and require Node.js >=22.12 Drop CommonJS build outputs and `require` export conditions from @sanity/ui, @sanity/color, and @sanity/logos. Raise published package engines to >=22.12 to match sanity. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave color, logos, and icons unchanged Scope the ESM-only / engines bump to @sanity/ui and @sanity/themer only. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): drop custom chunkFileNames, use tsdown defaults Hashed shared-chunk filenames already prevent the entry/chunk collision that dist/_chunks/ was guarding against (#2262). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): restore UserConfig annotation on tsdown config Match themer/logos so the inferred config type stays portable in the package TypeScript program (TS2883). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2516) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * fix: revert @sanity/themer to last published prerelease * Revert "fix: revert @sanity/themer to last published prerelease" This reverts commit e325e53. * feat: replace AnimatePresence with AnimateActivity (#2508) * feat: replace AnimatePresence with AnimateActivity Vendor Motion's AnimateActivity (Activity + exit animations) and use it in Tooltip, Popover, and Toast. Requires React 19.2 (handled separately). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimateActivityProps module-private for knip Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimatePresence for ToastProvider Toasts are mount/unmount list items; AnimatePresence fits that better than Activity-based show/hide. AnimateActivity stays for Tooltip/Popover. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lazy-mount AnimateActivity until first open Keep tooltips/popovers out of the DOM until first shown so hidden Activity nodes do not leak duplicate text into Testing Library queries (e.g. delay-group stories). After first open, Activity still preserves exit animations and state on subsequent hides. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: drop lazy-mount ref, assert tooltip visibility in stories Hidden Activity content is intentionally pre-rendered in the DOM, so the tooltip stories wait for visibility instead of text presence. Flipping animate off while open skips the exit animation, which is acceptable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: await async expect in tooltip story play functions Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: keep closed tooltips/popovers mounted with Activity Wrap the animate=false paths in plain <Activity> instead of unmounting, so open/close preserves state in both modes. Reset the menu's active item via effect cleanup (Activity unmounts effects on hide) so shouldFocus and selected registration behave like a fresh mount on reopen. Update tooltip/menu tests to assert visibility rather than DOM presence, and gate the Recursive popover story's content on open since hidden activities pre-render (an unconditional recursive content would render an infinitely deep hidden tree). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: document why native useEffectEvent is blocked, pin the freshness contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui)!: drop @juggle/resize-observer, use native ResizeObserver (#2518) * fix(ui): drop @juggle/resize-observer, use native ResizeObserver ResizeObserver is available in all browsers Sanity UI targets, so the polyfill and its custom typings are no longer needed. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): remove _ResizeObserver wrapper, use native ResizeObserver directly Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: ban forwardRef, createRef, createElement, Component, PureComponent with oxlint (#2519) feat: ban forwardRef, createRef, createElement, Component, PureComponent via oxlint Adds react entries to eslint/no-restricted-imports in .oxlintrc.json and migrates every @sanity/ui component from forwardRef to React 19 ref-as-prop function components. @sanity/icons and @sanity/logos keep forwardRef through a scoped override since their react peer ranges still include React 18, where refs only attach to forwardRef-wrapped function components. The class ErrorBoundary keeps an inline disable (error boundaries have no function equivalent), and the useGlobalKeyDown freshness-contract test keeps its deliberate forwardRef usage with an inline disable. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore(deps): update renovatebot/github-action action to v46.2.0 (next) (#2521) * Version Packages (next) (#2517) * feat(ui): move heavy-dependency components to dedicated subpath entry points (#2522) * feat(ui): extract static CSS with vanilla-extract into @sanity/ui/styles.css (#2523) Sets up the vanilla-extract build pipeline in @sanity/ui via @sanity/tsdown-config's vanillaExtract option, with inject disabled so the stylesheet is never self-imported: consumers add `import '@sanity/ui/styles.css'` themselves, on the same export path the vanilla-extract based next major already uses. Migrates the first slice of fully static styled-components CSS (SrOnly, Spinner, SpanWithTextOverflow) to colocated .css.ts modules, and wires .css.ts compilation into every consumer of the package's TypeScript source: storybook, the icons app, the ui/themer vitest configs, the docs studio (sanity dev/build), and the docs Next app (Turbopack, via @vanilla-extract/next-plugin). Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: ban class components via react/prefer-function-component Replace the no-restricted-imports ban on Component/PureComponent with react/prefer-function-component (allowErrorBoundary), so ErrorBoundary no longer needs an inline disable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2524) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 7, 2026
…ss contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot
pushed a commit
to sanity-io/ui
that referenced
this pull request
Aug 7, 2026
* chore: enter changesets prerelease mode on next Enter the `next` prerelease tag, point Changesets and CI/release workflows at the `next` branch, and add a sample major changeset for @sanity/ui so the Version Packages bot can open the first pre-release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2504) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat(ui): tombstone deprecated props, hooks, and components (major) (#2509) * chore(ui): tombstone remaining deprecated props as never Remove runtime fallbacks for deprecated space, grid, MenuButton popover, Popover boundaryElement, Badge mode, and Avatar tone props. Defaults move onto their replacements (gap, gridTemplate*, popover). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(storybook): migrate deprecated space/columns/useElementRect props Replace Stack/Inline/Menu/Tree/TabList/Button `space` with `gap`, Grid `columns`/`rows` with `gridTemplateColumns`/`gridTemplateRows`, and `useElementRect` with `useElementSize` (border size). Drop matching no-deprecated suppressions; leave theme/_compat suppressions alone. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): tombstone deprecated APIs with never types (major) Finish call-site migrations, add throwing-hook tests, and a major changeset documenting removed props/hooks/components and their replacements. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert(ui): keep PortalProvider boundaryElement for PortalContext PortalProvider.boundaryElement still writes PortalContextValue, so it cannot be tombstoned like other deprecated props. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: drop PortalProvider from tombstone changeset notes Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2512) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat: React 19 compiler target and ^19.2 peer deps (#2507) * feat: target React 19 compiler and require react ^19.2 Compile @sanity/ui and @sanity/themer with reactCompiler target '19', drop the now-unnecessary react-compiler-runtime dependency, and tighten react (and react-dom for ui) peer ranges to ^19.2 across published packages. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: mark @sanity/themer bump as major in changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave @sanity/icons and @sanity/logos peer ranges unchanged Only @sanity/ui and @sanity/themer need the React 19.2 peer bump for the compiler target change. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): remove private `_visual-editing` entrypoint (#2513) * feat(ui): remove private `_visual-editing` entrypoint Drop `@sanity/ui/_visual-editing` now that tree-shaking from the main export is sufficient for visual-editing consumers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: stop deep-linking workspace packages into transitive deps Set linkWorkspacePackages to true (not deep) so sanity and @sanity/visual-editing keep registry @sanity/ui until those packages are updated for the removed _visual-editing entrypoint. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(ui): restore Popover max-width after boundaryElement migration (#2514) fix(ui): restore Popover max-width from floatingBoundary After tombstoning `boundaryElement`, max-width only came from BoundaryElementProvider, so migrating to floatingBoundary/referenceBoundary alone dropped constrainSize/preventOverflow width. Fall back to the floating boundary for size, and wrap the Aligned story in BoundaryElementProvider. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2515) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat!: drop CommonJS from @sanity/ui, require Node.js >=22.12 (#2510) * feat!: ship ESM only and require Node.js >=22.12 Drop CommonJS build outputs and `require` export conditions from @sanity/ui, @sanity/color, and @sanity/logos. Raise published package engines to >=22.12 to match sanity. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave color, logos, and icons unchanged Scope the ESM-only / engines bump to @sanity/ui and @sanity/themer only. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): drop custom chunkFileNames, use tsdown defaults Hashed shared-chunk filenames already prevent the entry/chunk collision that dist/_chunks/ was guarding against (#2262). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): restore UserConfig annotation on tsdown config Match themer/logos so the inferred config type stays portable in the package TypeScript program (TS2883). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2516) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * fix: revert @sanity/themer to last published prerelease * Revert "fix: revert @sanity/themer to last published prerelease" This reverts commit e325e53. * feat: replace AnimatePresence with AnimateActivity (#2508) * feat: replace AnimatePresence with AnimateActivity Vendor Motion's AnimateActivity (Activity + exit animations) and use it in Tooltip, Popover, and Toast. Requires React 19.2 (handled separately). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimateActivityProps module-private for knip Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimatePresence for ToastProvider Toasts are mount/unmount list items; AnimatePresence fits that better than Activity-based show/hide. AnimateActivity stays for Tooltip/Popover. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lazy-mount AnimateActivity until first open Keep tooltips/popovers out of the DOM until first shown so hidden Activity nodes do not leak duplicate text into Testing Library queries (e.g. delay-group stories). After first open, Activity still preserves exit animations and state on subsequent hides. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: drop lazy-mount ref, assert tooltip visibility in stories Hidden Activity content is intentionally pre-rendered in the DOM, so the tooltip stories wait for visibility instead of text presence. Flipping animate off while open skips the exit animation, which is acceptable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: await async expect in tooltip story play functions Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: keep closed tooltips/popovers mounted with Activity Wrap the animate=false paths in plain <Activity> instead of unmounting, so open/close preserves state in both modes. Reset the menu's active item via effect cleanup (Activity unmounts effects on hide) so shouldFocus and selected registration behave like a fresh mount on reopen. Update tooltip/menu tests to assert visibility rather than DOM presence, and gate the Recursive popover story's content on open since hidden activities pre-render (an unconditional recursive content would render an infinitely deep hidden tree). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: document why native useEffectEvent is blocked, pin the freshness contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui)!: drop @juggle/resize-observer, use native ResizeObserver (#2518) * fix(ui): drop @juggle/resize-observer, use native ResizeObserver ResizeObserver is available in all browsers Sanity UI targets, so the polyfill and its custom typings are no longer needed. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): remove _ResizeObserver wrapper, use native ResizeObserver directly Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: ban forwardRef, createRef, createElement, Component, PureComponent with oxlint (#2519) feat: ban forwardRef, createRef, createElement, Component, PureComponent via oxlint Adds react entries to eslint/no-restricted-imports in .oxlintrc.json and migrates every @sanity/ui component from forwardRef to React 19 ref-as-prop function components. @sanity/icons and @sanity/logos keep forwardRef through a scoped override since their react peer ranges still include React 18, where refs only attach to forwardRef-wrapped function components. The class ErrorBoundary keeps an inline disable (error boundaries have no function equivalent), and the useGlobalKeyDown freshness-contract test keeps its deliberate forwardRef usage with an inline disable. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore(deps): update renovatebot/github-action action to v46.2.0 (next) (#2521) * Version Packages (next) (#2517) * feat(ui): move heavy-dependency components to dedicated subpath entry points (#2522) * feat(ui): extract static CSS with vanilla-extract into @sanity/ui/styles.css (#2523) Sets up the vanilla-extract build pipeline in @sanity/ui via @sanity/tsdown-config's vanillaExtract option, with inject disabled so the stylesheet is never self-imported: consumers add `import '@sanity/ui/styles.css'` themselves, on the same export path the vanilla-extract based next major already uses. Migrates the first slice of fully static styled-components CSS (SrOnly, Spinner, SpanWithTextOverflow) to colocated .css.ts modules, and wires .css.ts compilation into every consumer of the package's TypeScript source: storybook, the icons app, the ui/themer vitest configs, the docs studio (sanity dev/build), and the docs Next app (Turbopack, via @vanilla-extract/next-plugin). Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: ban class components via react/prefer-function-component Replace the no-restricted-imports ban on Component/PureComponent with react/prefer-function-component (allowErrorBoundary), so ErrorBoundary no longer needs an inline disable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2524) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
10 tasks
stipsan
added a commit
to sanity-io/ui
that referenced
this pull request
Aug 10, 2026
* chore: enter changesets prerelease mode on next Enter the `next` prerelease tag, point Changesets and CI/release workflows at the `next` branch, and add a sample major changeset for @sanity/ui so the Version Packages bot can open the first pre-release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2504) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat(ui): tombstone deprecated props, hooks, and components (major) (#2509) * chore(ui): tombstone remaining deprecated props as never Remove runtime fallbacks for deprecated space, grid, MenuButton popover, Popover boundaryElement, Badge mode, and Avatar tone props. Defaults move onto their replacements (gap, gridTemplate*, popover). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(storybook): migrate deprecated space/columns/useElementRect props Replace Stack/Inline/Menu/Tree/TabList/Button `space` with `gap`, Grid `columns`/`rows` with `gridTemplateColumns`/`gridTemplateRows`, and `useElementRect` with `useElementSize` (border size). Drop matching no-deprecated suppressions; leave theme/_compat suppressions alone. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): tombstone deprecated APIs with never types (major) Finish call-site migrations, add throwing-hook tests, and a major changeset documenting removed props/hooks/components and their replacements. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert(ui): keep PortalProvider boundaryElement for PortalContext PortalProvider.boundaryElement still writes PortalContextValue, so it cannot be tombstoned like other deprecated props. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: drop PortalProvider from tombstone changeset notes Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2512) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat: React 19 compiler target and ^19.2 peer deps (#2507) * feat: target React 19 compiler and require react ^19.2 Compile @sanity/ui and @sanity/themer with reactCompiler target '19', drop the now-unnecessary react-compiler-runtime dependency, and tighten react (and react-dom for ui) peer ranges to ^19.2 across published packages. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: mark @sanity/themer bump as major in changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave @sanity/icons and @sanity/logos peer ranges unchanged Only @sanity/ui and @sanity/themer need the React 19.2 peer bump for the compiler target change. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): remove private `_visual-editing` entrypoint (#2513) * feat(ui): remove private `_visual-editing` entrypoint Drop `@sanity/ui/_visual-editing` now that tree-shaking from the main export is sufficient for visual-editing consumers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: stop deep-linking workspace packages into transitive deps Set linkWorkspacePackages to true (not deep) so sanity and @sanity/visual-editing keep registry @sanity/ui until those packages are updated for the removed _visual-editing entrypoint. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(ui): restore Popover max-width after boundaryElement migration (#2514) fix(ui): restore Popover max-width from floatingBoundary After tombstoning `boundaryElement`, max-width only came from BoundaryElementProvider, so migrating to floatingBoundary/referenceBoundary alone dropped constrainSize/preventOverflow width. Fall back to the floating boundary for size, and wrap the Aligned story in BoundaryElementProvider. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2515) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat!: drop CommonJS from @sanity/ui, require Node.js >=22.12 (#2510) * feat!: ship ESM only and require Node.js >=22.12 Drop CommonJS build outputs and `require` export conditions from @sanity/ui, @sanity/color, and @sanity/logos. Raise published package engines to >=22.12 to match sanity. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave color, logos, and icons unchanged Scope the ESM-only / engines bump to @sanity/ui and @sanity/themer only. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): drop custom chunkFileNames, use tsdown defaults Hashed shared-chunk filenames already prevent the entry/chunk collision that dist/_chunks/ was guarding against (#2262). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): restore UserConfig annotation on tsdown config Match themer/logos so the inferred config type stays portable in the package TypeScript program (TS2883). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2516) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat: replace AnimatePresence with AnimateActivity (#2508) * feat: replace AnimatePresence with AnimateActivity Vendor Motion's AnimateActivity (Activity + exit animations) and use it in Tooltip, Popover, and Toast. Requires React 19.2 (handled separately). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimateActivityProps module-private for knip Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimatePresence for ToastProvider Toasts are mount/unmount list items; AnimatePresence fits that better than Activity-based show/hide. AnimateActivity stays for Tooltip/Popover. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lazy-mount AnimateActivity until first open Keep tooltips/popovers out of the DOM until first shown so hidden Activity nodes do not leak duplicate text into Testing Library queries (e.g. delay-group stories). After first open, Activity still preserves exit animations and state on subsequent hides. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: drop lazy-mount ref, assert tooltip visibility in stories Hidden Activity content is intentionally pre-rendered in the DOM, so the tooltip stories wait for visibility instead of text presence. Flipping animate off while open skips the exit animation, which is acceptable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: await async expect in tooltip story play functions Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: keep closed tooltips/popovers mounted with Activity Wrap the animate=false paths in plain <Activity> instead of unmounting, so open/close preserves state in both modes. Reset the menu's active item via effect cleanup (Activity unmounts effects on hide) so shouldFocus and selected registration behave like a fresh mount on reopen. Update tooltip/menu tests to assert visibility rather than DOM presence, and gate the Recursive popover story's content on open since hidden activities pre-render (an unconditional recursive content would render an infinitely deep hidden tree). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: document why native useEffectEvent is blocked, pin the freshness contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui)!: drop @juggle/resize-observer, use native ResizeObserver (#2518) * fix(ui): drop @juggle/resize-observer, use native ResizeObserver ResizeObserver is available in all browsers Sanity UI targets, so the polyfill and its custom typings are no longer needed. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): remove _ResizeObserver wrapper, use native ResizeObserver directly Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: ban forwardRef, createRef, createElement, Component, PureComponent with oxlint (#2519) feat: ban forwardRef, createRef, createElement, Component, PureComponent via oxlint Adds react entries to eslint/no-restricted-imports in .oxlintrc.json and migrates every @sanity/ui component from forwardRef to React 19 ref-as-prop function components. @sanity/icons and @sanity/logos keep forwardRef through a scoped override since their react peer ranges still include React 18, where refs only attach to forwardRef-wrapped function components. The class ErrorBoundary keeps an inline disable (error boundaries have no function equivalent), and the useGlobalKeyDown freshness-contract test keeps its deliberate forwardRef usage with an inline disable. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2517) * feat(ui): move heavy-dependency components to dedicated subpath entry points (#2522) * feat(ui): extract static CSS with vanilla-extract into @sanity/ui/styles.css (#2523) Sets up the vanilla-extract build pipeline in @sanity/ui via @sanity/tsdown-config's vanillaExtract option, with inject disabled so the stylesheet is never self-imported: consumers add `import '@sanity/ui/styles.css'` themselves, on the same export path the vanilla-extract based next major already uses. Migrates the first slice of fully static styled-components CSS (SrOnly, Spinner, SpanWithTextOverflow) to colocated .css.ts modules, and wires .css.ts compilation into every consumer of the package's TypeScript source: storybook, the icons app, the ui/themer vitest configs, the docs studio (sanity dev/build), and the docs Next app (Turbopack, via @vanilla-extract/next-plugin). Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2524) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * fix(ui): ship dist/styles.css unminified for diffable CSS output (#2528) * fix(ui): preserve overflow: hidden fallback in dist/styles.css lightningcss's OverflowHandler collapses duplicate overflow declarations to the last value no matter which targets it is given (unlike colors, it never consults compat data for the clip keyword), so no browser target setting can keep the hand-written fallback. Skip the lightningcss pass instead (minify: false + target: false) so the stylesheet ships exactly as authored, keeping overflow: hidden ahead of overflow: clip for browsers in the support matrix without clip support (e.g. iOS Safari 15). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: format spinner.tsx (pre-existing oxfmt drift) Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(ui): keep lightningcss lowering, only disable minification of styles.css overflow: clip is Baseline, so the hidden fallback doesn't need to survive the build. Keep minify: false so CSS output diffs easily between published versions, and drop target: false so the lightningcss pass runs again with the @sanity/browserslist-config lowering targets. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: ban class components via react/prefer-function-component (#2525) * chore: enter changesets prerelease mode on next Enter the `next` prerelease tag, point Changesets and CI/release workflows at the `next` branch, and add a sample major changeset for @sanity/ui so the Version Packages bot can open the first pre-release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2504) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat(ui): tombstone deprecated props, hooks, and components (major) (#2509) * chore(ui): tombstone remaining deprecated props as never Remove runtime fallbacks for deprecated space, grid, MenuButton popover, Popover boundaryElement, Badge mode, and Avatar tone props. Defaults move onto their replacements (gap, gridTemplate*, popover). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(storybook): migrate deprecated space/columns/useElementRect props Replace Stack/Inline/Menu/Tree/TabList/Button `space` with `gap`, Grid `columns`/`rows` with `gridTemplateColumns`/`gridTemplateRows`, and `useElementRect` with `useElementSize` (border size). Drop matching no-deprecated suppressions; leave theme/_compat suppressions alone. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): tombstone deprecated APIs with never types (major) Finish call-site migrations, add throwing-hook tests, and a major changeset documenting removed props/hooks/components and their replacements. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert(ui): keep PortalProvider boundaryElement for PortalContext PortalProvider.boundaryElement still writes PortalContextValue, so it cannot be tombstoned like other deprecated props. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: drop PortalProvider from tombstone changeset notes Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2512) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat: React 19 compiler target and ^19.2 peer deps (#2507) * feat: target React 19 compiler and require react ^19.2 Compile @sanity/ui and @sanity/themer with reactCompiler target '19', drop the now-unnecessary react-compiler-runtime dependency, and tighten react (and react-dom for ui) peer ranges to ^19.2 across published packages. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: mark @sanity/themer bump as major in changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave @sanity/icons and @sanity/logos peer ranges unchanged Only @sanity/ui and @sanity/themer need the React 19.2 peer bump for the compiler target change. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui): remove private `_visual-editing` entrypoint (#2513) * feat(ui): remove private `_visual-editing` entrypoint Drop `@sanity/ui/_visual-editing` now that tree-shaking from the main export is sufficient for visual-editing consumers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: stop deep-linking workspace packages into transitive deps Set linkWorkspacePackages to true (not deep) so sanity and @sanity/visual-editing keep registry @sanity/ui until those packages are updated for the removed _visual-editing entrypoint. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix(ui): restore Popover max-width after boundaryElement migration (#2514) fix(ui): restore Popover max-width from floatingBoundary After tombstoning `boundaryElement`, max-width only came from BoundaryElementProvider, so migrating to floatingBoundary/referenceBoundary alone dropped constrainSize/preventOverflow width. Fall back to the floating boundary for size, and wrap the Aligned story in BoundaryElementProvider. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2515) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * feat!: drop CommonJS from @sanity/ui, require Node.js >=22.12 (#2510) * feat!: ship ESM only and require Node.js >=22.12 Drop CommonJS build outputs and `require` export conditions from @sanity/ui, @sanity/color, and @sanity/logos. Raise published package engines to >=22.12 to match sanity. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: leave color, logos, and icons unchanged Scope the ESM-only / engines bump to @sanity/ui and @sanity/themer only. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): drop custom chunkFileNames, use tsdown defaults Hashed shared-chunk filenames already prevent the entry/chunk collision that dist/_chunks/ was guarding against (#2262). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): restore UserConfig annotation on tsdown config Match themer/logos so the inferred config type stays portable in the package TypeScript program (TS2883). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2516) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * fix: revert @sanity/themer to last published prerelease * Revert "fix: revert @sanity/themer to last published prerelease" This reverts commit e325e53. * feat: replace AnimatePresence with AnimateActivity (#2508) * feat: replace AnimatePresence with AnimateActivity Vendor Motion's AnimateActivity (Activity + exit animations) and use it in Tooltip, Popover, and Toast. Requires React 19.2 (handled separately). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimateActivityProps module-private for knip Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: keep AnimatePresence for ToastProvider Toasts are mount/unmount list items; AnimatePresence fits that better than Activity-based show/hide. AnimateActivity stays for Tooltip/Popover. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lazy-mount AnimateActivity until first open Keep tooltips/popovers out of the DOM until first shown so hidden Activity nodes do not leak duplicate text into Testing Library queries (e.g. delay-group stories). After first open, Activity still preserves exit animations and state on subsequent hides. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: drop lazy-mount ref, assert tooltip visibility in stories Hidden Activity content is intentionally pre-rendered in the DOM, so the tooltip stories wait for visibility instead of text presence. Flipping animate off while open skips the exit animation, which is acceptable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: await async expect in tooltip story play functions Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: keep closed tooltips/popovers mounted with Activity Wrap the animate=false paths in plain <Activity> instead of unmounting, so open/close preserves state in both modes. Reset the menu's active item via effect cleanup (Activity unmounts effects on hide) so shouldFocus and selected registration behave like a fresh mount on reopen. Update tooltip/menu tests to assert visibility rather than DOM presence, and gate the Recursive popover story's content on open since hidden activities pre-render (an unconditional recursive content would render an infinitely deep hidden tree). Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: document why native useEffectEvent is blocked, pin the freshness contract (#2506) * feat!: use React's native useEffectEvent Remove the use-effect-event dependency in favor of React's built-in useEffectEvent, and raise the react/react-dom peer dependency minimum to ^19.2. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: route useEffectEvent through an internal shim React 19.2's native useEffectEvent never updates past first-render values when the calling component is wrapped in forwardRef or memo (react/react#34818) — the commit phase only applies effect-event updates to plain function-component fibers. DialogCard and Tooltip are forwardRef components, so Escape handling read a stale isTopLayer and one Escape cascade-closed every nested dialog. Keep the use-effect-event dependency removed, but route the three call sites through a small internal shim (useRef + useInsertionEffect) until react/react#34831 ships in a stable release. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: lint errors in useEffectEvent test, update changeset Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: update changeset for internal effect-event shim Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * revert: keep use-effect-event, native useEffectEvent unusable in forwardRef/memo Audit of all call sites: useGlobalKeyDown and useClickOutsideEvent are public hooks that execute in the caller's fiber (all internal callers — DialogCard, Menu, Breadcrumbs — are forwardRef components, and external callers can be anything), and Tooltip is a forwardRef component. React 19.2's native useEffectEvent never updates past first-render values in forwardRef/memo fibers (react/react#34818), so no site can use the native hook until the fix ships in a stable release. Restore the use-effect-event dependency at all three sites with TODO comments, drop the internal shim, and add a regression test that pins the fresh-values contract for forwardRef/memo callers. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: restore lockfile to match next Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(ui)!: drop @juggle/resize-observer, use native ResizeObserver (#2518) * fix(ui): drop @juggle/resize-observer, use native ResizeObserver ResizeObserver is available in all browsers Sanity UI targets, so the polyfill and its custom typings are no longer needed. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * refactor(ui): remove _ResizeObserver wrapper, use native ResizeObserver directly Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat: ban forwardRef, createRef, createElement, Component, PureComponent with oxlint (#2519) feat: ban forwardRef, createRef, createElement, Component, PureComponent via oxlint Adds react entries to eslint/no-restricted-imports in .oxlintrc.json and migrates every @sanity/ui component from forwardRef to React 19 ref-as-prop function components. @sanity/icons and @sanity/logos keep forwardRef through a scoped override since their react peer ranges still include React 18, where refs only attach to forwardRef-wrapped function components. The class ErrorBoundary keeps an inline disable (error boundaries have no function equivalent), and the useGlobalKeyDown freshness-contract test keeps its deliberate forwardRef usage with an inline disable. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore(deps): update renovatebot/github-action action to v46.2.0 (next) (#2521) * Version Packages (next) (#2517) * feat(ui): move heavy-dependency components to dedicated subpath entry points (#2522) * feat(ui): extract static CSS with vanilla-extract into @sanity/ui/styles.css (#2523) Sets up the vanilla-extract build pipeline in @sanity/ui via @sanity/tsdown-config's vanillaExtract option, with inject disabled so the stylesheet is never self-imported: consumers add `import '@sanity/ui/styles.css'` themselves, on the same export path the vanilla-extract based next major already uses. Migrates the first slice of fully static styled-components CSS (SrOnly, Spinner, SpanWithTextOverflow) to colocated .css.ts modules, and wires .css.ts compilation into every consumer of the package's TypeScript source: storybook, the icons app, the ui/themer vitest configs, the docs studio (sanity dev/build), and the docs Next app (Turbopack, via @vanilla-extract/next-plugin). Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: ban class components via react/prefer-function-component Replace the no-restricted-imports ban on Component/PureComponent with react/prefer-function-component (allowErrorBoundary), so ErrorBoundary no longer needs an inline disable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2524) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> * refactor(ui): use function declarations instead of named const expressions (#2526) Replace `export const Foo = function Foo` (and matching internal helpers) with `export function Foo`. Leave polymorphic `XxxComponent = function Xxx` casts as-is so display names and type assertions keep working. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Version Packages (next) (#2529) Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> * fix(ui): emit types for styles css (#2536) * Version Packages (next) (#2538) * chore: exit changesets prerelease mode, restore main release config Prep for merging the 4.0 branch to main: `changeset pre exit` (the next `changeset version` on main produces stable 4.0.0), point the Changesets baseBranch back at main, drop the `next` push triggers from the CI and release workflows, and delete the placeholder kickoff changeset that only existed to start the prerelease cycle. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: make pending changesets easier to scan Rewrite each pending 4.0 changeset with a bold one-line takeaway first, short bullets for what breaks, and an explicit what-to-do section, so the stable 4.0.0 changelog is skimmable. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * feat(docs): serve the docs site from the v4 nav document Swap primaryNavId from 'v3' to 'v4' so /ui renders the v4 nav. The stale "UI4" content release (rzyecOZ0D, staged against the legacy main nav in Oct 2025) is archived in the dataset, replaced by a fresh empty "UI 4" release (rG3Odb604) for staging the v4 content updates. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: add v3-to-v4 migration guide, link it from the docs navbar MIGRATION.md walks through the 4.0 upgrade as an ordered checklist (runtime requirements, styles.css import, moved entry points, removed deprecated APIs, behavior changes, themer 1.0). The docs navbar links to it on GitHub next to the repository button. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: keep @sanity/themer on the 0.x line, bumping minor to 0.3.0 Downgrade the themer bumps in the pending changesets from major to minor. Exiting pre mode increments from the current package version, so reset packages/themer/package.json from the 1.0.0-next.7 prerelease to the published stable 0.2.1 - `changeset version` now produces 0.3.0 (verified with a dry run). The migration guide section is retitled accordingly. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: drop the styles.css declaration changeset The declaration fix only ever shipped on 4.0.0-next.* test releases - v3 has no styles.css, so it is noise in the stable 4.0.0 changelog. The declaration itself still ships with the build. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: require('@sanity/ui') keeps working on modern Node Dropping the CJS build does not break require() consumers: the root export resolves via a default condition and Node >=22.12 supports require(esm). Only a too-old Node version breaks. Correct the changeset and migration guide accordingly. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: split multi-package changesets per package Give @sanity/ui and @sanity/themer their own changesets for the ESM / Node 22.12 requirement, the React 19.2 requirement, and the subpath entry point republish. Most @sanity/ui consumers have no relationship to @sanity/themer, so cross-package mentions in the changelog are noise. Verified with a dry-run version: bumps unchanged (ui 4.0.0, themer 0.3.0) and the ui changelog no longer mentions themer. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: drop the unminified styles.css changeset Like the declaration changeset, this only made sense within the 4.0.0-next.* test releases: v3 has no styles.css, so for anyone upgrading from v3 the stylesheet has always been unminified. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: describe styles.css without assuming future majors Drop the claims that more styles move into the stylesheet over time and that the export path matches a vanilla-extract-based next major - the changeset and migration guide should only describe what UI4 ships. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: point at the v3 maintenance branch A copy of main now lives on the v3 branch (its release-v3 dist-tag setup lands in #2551). Document it where the 4.x line talks about versions: the migration guide points people staying on 3.x at it, and CONTRIBUTING/AGENTS describe the maintenance-branch and dist-tag layout alongside the existing v2 line. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: regenerate lockfile after rebasing onto main Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: incorporate the v2-to-v3 migration guide Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: combine the 4.0 changesets into a single release note Merge the nine @sanity/ui changesets into one major changeset so the 4.0.0 changelog reads as a single coherent release note (linking the migration guide), and the three @sanity/themer changesets into one minor changeset. Delete the leftover pre.json - without preState the version math is unchanged (verified by dry run: ui 4.0.0, themer 0.4.0). The dependency-update changesets inherited from main are left as-is. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * chore: exclude @sanity/themer from the 4.0 release Keep the published @sanity/themer exactly as main ships it: restore its react peer range, engines, react-compiler-runtime dependency, compiler target 18 (and the matching knip ignore entry), drop its changeset and the migration guide section, and add it to the Changesets ignore list so the @sanity/ui major does not auto-bump and republish it as a dependent. Only in-repo dev shims remain (subpath imports of the workspace ui and the vanilla-extract vitest plugin), which the monorepo needs to build and test themer against ui v4 source. A follow-up PR releases themer against ui 4 and removes the ignore. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: explain why React 19.2 is the minimum version The 19.2 floor comes from the <Activity> component, which shipped in React 19.2.0 and which v4 uses for Tooltip/Popover mounting. State this in the release note and the migration guide. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: describe styles.css as a move off styled-components Consumers do not need to know the build-time tooling. Say what matters to them: these components no longer use styled-components, more follow in future 4.x minors, and UI5 ships without runtime CSS-in-JS. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * fix: point MenuButton boundaryElement deprecation at the v4 Popover API The tombstone said popover={{boundaryElement}}, but PopoverProps. boundaryElement is itself removed in v4 - the working replacements are floatingBoundary/referenceBoundary. Also correct the _visual-editing migration note: the moved components (Menu*, Popover) import from their new entry points, not the root. Both spotted in review by @jordanl17. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * docs: state the exports-aware moduleResolution requirement Dropping typesVersions means moduleResolution "node" (node10) cannot resolve the subpath entry points' types - the root entry still resolves via the kept top-level types field. Document that v4 needs node16, nodenext or bundler. Raised in review by @jordanl17. Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> * Update config.json * Update queries.ts * Update constants.ts * Update avatar.tsx * Update button.tsx * Update card.tsx * Update code.tsx * Update container.tsx * Update flex.tsx * Update grid.tsx * Update heading.tsx * Update inline.tsx * Update kbd.tsx * Update label.tsx * Update stack.tsx * Update text.tsx * Update CHANGELOG.md * Update package.json --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com> Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #34818
Seems to me the event payload handling should've gone into the original fallthrough block instead of just handling it for
FunctionComponent: https://github.com/facebook/react/pull/25229/files#diff-9e8ee221dbf99e0ccdad6a63bf63804dea26f1785e2f443dbe92fa835a63b83eL412-L415See first commit for current behavior where Effect Events did not read the latest Context value if used in
React.memoComponents.