Repository navigation
feat: update dependencies, migrate to Rstest and enable React Compiler - #339
Merged
Merged
Conversation
Catalog: @biomejs/biome 2.5.7->2.5.15, @rsbuild/core 2.1.10->2.1.13, @rsbuild/plugin-react 2.1.0->2.1.1, @rspack/core 2.1.8->2.1.10, @testing-library/react 16.3.2->16.3.3, @testing-library/user-event 14.6.3->14.6.7, @types/node 24.10.4->24.10.15, @types/react-dom 19.2.4->19.2.7, @vitest/coverage-v8 4.1.10->4.1.11, vitest 4.1.10->4.1.11. Fix stray trailing comma on the @tanstack/react-table catalog entry. Root: @commitlint/cli 21.2.1->21.2.3, @commitlint/config-conventional 21.2.0->21.2.3, @semantic-release/github 12.0.9->12.0.10, chalk 6.0.0->6.0.1, tsx 4.23.10->4.23.15, turbo 2.10.8->2.10.13; raise the postcss override floor >=8.5.16 -> >=8.5.28 so the direct bump resolves. design-system: @ark-ui/react 5.38.0->5.38.1, @figma/code-connect 1.5.2->1.5.3, @internationalized/date 3.12.3->3.12.4, @shikijs/types and shiki 4.4.2->4.4.3, @tanstack/react-router 1.170.21->1.170.41, @tanstack/react-virtual 3.14.9->3.14.13, @testing-library/jest-dom 7.0.0->7.0.1, highlight.js 11.11.1->11.11.2, postcss 8.5.26->8.5.28, react-resizable-panels 4.12.3->4.12.4, tsx 4.23.10->4.23.15. playground: @tanstack/react-router 1.170.21->1.170.41, @tanstack/router-devtools 1.167.1->1.167.2, @tanstack/router-plugin 1.168.26->1.168.42. mcp: @modelcontextprotocol/sdk 1.30.0->1.30.1. configs: @rsdoctor/rspack-plugin 1.6.1->1.6.4, @testing-library/jest-dom 7.0.0->7.0.1, @vitest/ui 4.1.10->4.1.11, tsx 4.23.10->4.23.15. @ark-ui/react held at 5.38.1: 5.38.2 (zag-js 1.43.1) breaks the FilterInput field->operator menu chaining in 17 unit tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Catalog: @playwright/test 1.62.1->1.63.0, @rsbuild/core 2.1.13->2.2.11, @rspack/core 2.1.10->2.2.8, @tanstack/react-table 9.0.0->9.2.4, @types/react 19.2.18->19.3.0, @types/react-dom 19.2.7->19.3.0, react/react-dom 19.2.8->19.3.0, storybook 10.4.6->10.6.1, zod 4.4.3->4.6.5. Root: @semantic-release/npm 13.1.5->13.2.0, conventional-changelog-conventionalcommits 10.2.1->10.4.0, turbo 2.10.13->2.11.6, vite 8.2.1->8.3.2 (override floor >=8.3.2), overrides @types/react 19.3.0, @storybook/react(-dom-shim) 10.6.1. design-system: @ark-ui/react 5.38.1->5.39.2, @zag-js/file-utils 1.43.0->1.43.3, @shikijs/types/shiki 4.4.3->4.5.0, @storybook/addon-docs/addon-themes 10.4.6->10.6.1, storybook-react-rsbuild 3.3.4->3.6.0, highlight.js 11.11.2->11.12.0, react-resizable-panels 4.12.4->4.14.1, tailwind-merge 3.6.0->3.7.0; react/react-dom added as catalog devDependencies so tests run on the catalog React instead of an auto-installed peer. mcp: @modelcontextprotocol/sdk 1.30.1->1.31.0. vitest-config: jsdom 30.0.1->30.1.1. Playwright container image v1.62.1-noble -> v1.63.0-noble (CI, compose, docs). Fixes needed by the bumps: - vitest setup: zag-js highlights menu items on pointermove only in the "pointer" modality and skips moves at an unchanged position; user-event fires every jsdom event at (0, 0). A capture listener shows zag's document-level tracker a move at a fresh position first. - FileUpload test helper: jsdom 30.1 keeps wrapper implementations in private fields; read them through jsdom's idl utils. - turbo.json: agentGuidance false, so turbo 2.11 stops writing a managed block into AGENTS.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…open on hand-off Since zag-js 1.43.1 (pulled in by @ark-ui/react 5.39) a menu that mounts while its content node already exists registers its dismissable layer synchronously. During FilterInput's field -> operator -> value hand-off the next menu therefore lands on the layer stack above the menu that is closing, and removing that closing layer dismisses every layer above it, so the freshly opened menu closed immediately (in a real browser too). - DropdownMenu: new optional onRequestDismiss prop, forwarded to Ark UI Menu.Root. It is called when another layer asks the menu to dismiss; event.preventDefault() keeps the menu open. - FilterInput: field, operator, value (flat/nested) and date menus pass keepOpenOnMenuHandoff, which ignores dismiss requests coming from another FilterInput menu. FilterInput owns its menus' open state, so nothing else changes for consumers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- @rslib/core 0.23.2 -> 1.0.3 (catalog; now shares @rsbuild/core 2.2.11, rsbuild-plugin-dts 1.0.3). JS output byte-identical; bundleless .d.ts relative specifiers now carry .js extensions (redirect.dts.extension) - postcss-import 16.1.1 -> 17.0.0 (design-system dev; not loaded by any PostCSS config, dist CSS byte-identical) - @types/node 24.10.15 -> 24.19.0 (catalog; stays on the Node 24 runtime major) Skipped: vitest/@vitest/* 5.x (replaced by Rstest in next stage), @figma/code-connect 2.x (retires the React parser used by all *.figma.tsx bindings), @types/node 26.x (runtime is Node 24). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace Vitest with Rstest (Rspack-based) across the monorepo. Versions: - add @rstest/core 0.12.3, @rstest/coverage-v8 0.12.3, jsdom 30.1.1 (catalog) - remove vitest 4.1.11, @vitest/coverage-v8 4.1.11, @vitest/ui 4.1.11 - remove root vite 8.3.2 devDependency and pnpm.overrides.vite (nothing non-optional depends on vite any more; pnpm why vite/vitest -r is empty) - @rsbuild/core stays a single 2.2.11 copy (shared with @rstest/core) Config: - packages/configs/vitest-config -> packages/configs/rstest-config (@wallarm-org/rstest-config), shipped as TS source with no build step, so the turbo dependsOn vitest-config#build edge is gone - base config writes JUnit to ./test-results/junit.xml (plus github-actions annotations) when CI is set, since Rstest has no --outputFile; CI now runs plain `pnpm test:run` - vitest.config.ts -> rstest.config.ts in design-system, playground, mcp; vitest.setup.ts -> rstest.setup.ts with jest-dom matchers via expect.extend and an explicit Testing Library cleanup; matcher types in src/testUtils/rstest-env.d.ts - design-system loads jsdom natively (testEnvironment.prebundle: false) so the FileUpload helpers reach the same jsdom instance through its idl utils - coverage provider v8 (@rstest/coverage-v8); test:ui removed (no Rstest UI mode), use `pnpm test` (rstest watch) - turbo test inputs: rstest.*, scripts/**, the shared config sources; env CI; test-results/junit.xml added to outputs - tsconfig unit types vitest/globals -> @rstest/core/globals; fix the "src/testUtils/**" include that TS 7 rejects (TS5010), which also clears the ~1.7k jest-dom matcher type errors in tsconfig.unit.json - biome ignores coverage/ output Tests: - `from 'vitest'` -> `from '@rstest/core'`, vi.* -> rs.* (242 files) - async vi.mock factories -> importActual import attributes plus sync factories (CodeEditor.stories.test, ParameterPath.test) - vi.dynamicImportSettled -> macrotask flush (index.languages.test) - hook callbacks that returned rs.* values use block bodies (Rstest treats a hook return value as cleanup) Before (Vitest 4.1.11): design-system 234 passed + 2 skipped files (236), 2664 passed + 2 expected-fail + 37 skipped tests (2703); mcp 3 files, 36 passed; playground 0 files. After (Rstest 0.12.3): design-system 234 passed + 2 skipped files (236), 2666 passed (it.fails counted as passed) + 37 skipped tests (2703); mcp 3 files, 36 passed; playground 0 files. Per-file pass/skip counts match exactly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Compile all React code with React Compiler, using Rspack's native (SWC)
implementation. It is enabled with pluginReact({ reactCompiler: true }) in
the shared rsbuild config (Storybook, playground) and in the design-system
rslib build, plus tools.swc.jsc.transform.reactCompiler in the shared Rstest
react config (Rstest builds for the node target, where pluginReact skips the
option), so unit tests exercise the compiled components. Target is React 19
(the peer range), so the published dist imports react/compiler-runtime from
the consumer's React; no new runtime dependency.
- 1231 of 1873 dist modules now ship compiled output (646 components,
581 icons, 4 hooks/utils).
- Bailout audit (new `pnpm compiler:audit`, babel-plugin-react-compiler
1.0.0 logger) reports 1317 functions compiled and 91 safe bailouts in
48 files (mostly refs-during-render). The Babel audit and the shipped
SWC port disagree on 4 files, so treat the audit as an approximation.
- Breadcrumbs keys separators by position instead of mutating a module
counter during render, so it is now compiled.
- Table gets 'use no memo' in 25 files: 24 that read TanStack row/column/
header/cell getters (stable object identities, changing results) plus
TableBodyVirtualizedCore (mutable virtualizer prop); without it sorting,
selection and expansion rendered stale state (4 failing unit tests).
Consumer note: the published components are now memoized, so a consumer
that mutates an array or object prop in place (e.g. pushing into
`options`) and re-renders may no longer see the update. Pass new
references instead.
Size of dist JS goes from 3379.8 kB to 4429.3 kB raw and from 1143.1 kB
to 1453.4 kB gzip (sum of per-file gzip). The playground bundle goes from
3008.3 kB to 3018.1 kB gzip.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The published @wallarm-org/design-system dist shipped files that are not
part of the runtime package and import devDependencies:
- 35 *.figma.tsx Code Connect bindings (as .js + .d.ts, importing
@figma/code-connect)
- FileUpload.test.helpers.js (importing @rstest/core / Testing Library);
the entry glob only excluded *.test.{ts,tsx}
- theme/Pixel.stories.tsx, copied verbatim by output.copy
- story-only fixtures: FilterInput/stories/* and Table/mocks
Exclude all test/spec/e2e/story/figma/__tests__/stories/story-content/
mocks/testUtils files from both the rslib source entry and
tsconfig.app.json (which drives the emitted .d.ts), and skip *.stories.*
when copying src/theme. dist goes from 3780 to 3702 files (npm pack: 3782
-> 3704); only the files above are dropped and nothing left in dist
imports them.
The Figma bindings were previously type-checked only as a side effect of
the rslib dts build. Add tsconfig.figma.json and run it from the
package's typecheck script so they stay type-checked in CI. The
`figma connect` CLI reads source files, so it is unaffected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing references postcss-import: every postcss.config.js delegates to @wallarm-org/tailwind-config/postcss, which only registers @tailwindcss/postcss (it inlines @import itself), and no rsbuild, rslib, Storybook config, script or CI step loads it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TanStack Table v9 keeps row/column/header/cell objects at a stable
identity while their getter results change, so compiled components that
call getters in render memoized stale values. Instead of opting the
Table tree out of compilation, route every render-time getter read
through helpers in Table/lib:
- useTableValue(read): scalar reads (or TanStack-memoized references)
via useSyncExternalStore over table.store, the v9-documented
useSelector(table.store, selector) pattern.
- withTableState(table.state, compute): internal output that cannot be
compared by value (filler cells, skeleton rows, drag overlay, settings
menu column lists); re-runs on every table state change.
- useRenderEveryTime(render): consumer callbacks the Table calls inline
during render (a function header, the cell renderer,
meta.renderMenuAction, renderExpandedRow). They may call hooks or read
context, so they must never sit in a compiler memo scope: a cached
call skips the consumer's hooks ("Rendered fewer hooks than expected")
or keeps stale context. The hook lives in its own file with a
file-level 'use no memo'; a compiled caller never skips a hook call.
renderExpandedRow additionally renders through RenderCallback, so its
hooks belong to a component of their own.
Also:
- useColumnPinning replaces getPinningStyles/isLastPinnedLeft reads in
header and body cells; useColumnDnd/useRowDnd read pinning, resizing
and sub-rows reactively (useMasterCell already takes primitives).
- TableBodyVirtualizedCore receives virtualItems/totalSize/scrollMargin/
measureElement from its (compiler-skipped) useVirtualizer hosts instead
of the mutable virtualizer instance.
- TableRow reads "is last row" as a primitive instead of subscribing to
the row-model array; the select-all header scans rows once.
- New Table.reactivity.test.tsx drives sort x3, select-all/deselect with
the action bar, expand/collapse of the last row, column sizing, pin/
unpin and settings-menu hide/show repeatedly, plus consumer callbacks
with hooks/context (function header across isLoading toggles, context
in header, renderMenuAction and renderExpandedRow).
Removed all 25 file-level 'use no memo' directives under
components/Table; the only directive left is the intentional one in
lib/useRenderEveryTime.ts. Compiler audit: repo-wide 1318 -> 1347
functions compiled. Remaining Table bailouts are pre-existing and
unrelated to getters: StickyGroupParent and TableBody (ref access in
render), TableBodyVirtualized{Container,Window} (useVirtualizer, skipped
by design), TableSettingsMenu (compiler invariant), useWindowScrollRoot.
This makes Table compile with render behaviour at parity; it does not
reduce row/cell re-renders on table state changes, since the table
context changes identity on every state change.
Public API unchanged: dist/components/Table/index.d.ts and the root
index.d.ts are byte-identical; only internal .d.ts files differ. Rendered
DOM unchanged: normalized outerHTML of 35 Table story scenarios
(including sort, selection, expansion, pinning, resizing, settings menu
and virtualization interactions) is identical before and after.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hronously Zag (select, menu) moves focus and registers its dismiss listeners inside requestAnimationFrame, one frame after the state change that flips aria-expanded and fires onOpenChange. Several tests asserted focus right after that state change, or acted on the menu before its first frame: - FilterDropdown "Escape ... returns focus to the trigger" asserted toHaveFocus() synchronously after waitFor(aria-expanded=false); the trigger is only focused on the next frame. - FilterDropdown "Footer Clear ... Space" and the four Select SelectSearchInput keyboard tests focused an element by hand before the menu's initial-focus frame, which could then pull focus back to the list between keydown and keyup. - FilterDropdown "starts every session with an empty query" and Table "onSettingsOpenChange" pressed Escape before the menu had registered its Escape listener. How often these fail depends on where jsdom's 16ms rAF interval falls relative to the assertion. Main (Vitest) has the same race (2/12 runs with --retry 0). On CI it failed all 3 attempts. With rAF delayed to 40ms the FilterDropdown Escape and Table tests fail every time, and at 10-30ms the Select tests fail. With this change those runs pass. A Chromium run of the built Storybook shows the same order: aria-expanded is false in the keydown microtask and focus reaches the trigger on the next frame. Component behaviour is correct. Each test now waits for the focus the menu actually takes (the trigger, the list or the search input) before it continues. No assertion was removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…32.0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eenshots] Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ispashkov
force-pushed
the
chore/update-deps
branch
from
October 5, 2026 05:48
dd19753 to
e75c7ab
Compare
createLargeSecurityEvents filled the Requests column with Math.random(), so the 'action bar pinned to the viewport bottom' and 'bidirectional infinite scroll' baselines changed on every screenshot run. Use a fixed multiplicative hash of the row index instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since @zag-js/dismissable 1.43.3 (pulled in by @ark-ui/react 5.39.2) the dismissable layer can register, and set --layer-index on the content, after zag's popper has already copied the content's computed z-index into the positioner's --z-index. Popper does that copy only once, so Select and DropdownMenu positioners stayed at z-index 50 and rendered below a nested dialog/drawer (positioner at 70). Add syncLayerZIndex/useLayerZIndexRef, which watch the content's style/class and re-copy its computed z-index to the positioner whenever it changes. Stacking no longer depends on zag's registration order. Wire it into DropdownMenuContent, SelectPositioner (Select, FilterDropdown, Pagination, editable cells), PopoverContent and CalendarContent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Summary
This PR updates dependencies in stages (patch → minor → major), moves unit tests from Vitest to Rstest, and turns on React Compiler. It is rebased on
mainv2.0.0. Each step is its own commit, so review is easiest commit by commit.build(deps): bump patch-level dependenciesbuild(deps): bump minor-level dependenciesv1.63.0-noble), TanStack Table 9.2.4, Ark UI 5.39.2, zod 4.6, turbo 2.11 (agentGuidance: false)feat(dropdown-menu): add onRequestDismiss and keep FilterInput menus open on hand-offonRequestDismissprop toDropdownMenu, and FilterInput's field → operator → value chain uses it to keep the next menu openbuild(deps): bump major-level dependencies@rslib/core1.0.3,@types/node24.19test: migrate unit tests from Vitest to Rstest@rstest/core0.12.3;@wallarm-org/vitest-config→@wallarm-org/rstest-config; vitest,@vitest/*,viteand its override are removed. Test count is the same before and afterperf: enable React CompilerpluginReact({ reactCompiler: true })) in the library build, Storybook and playground. Rstest gets it viatools.swc. Also adds apnpm compiler:auditscriptfix(build): stop publishing test helpers, Figma bindings and storiesdist. Figma bindings are now type-checked throughtsconfig.figma.jsonbuild(deps): remove unused postcss-import@importitselfperf(table): make Table compatible with React Compiler'use no memo'from Table. Getters are now read through a subscription totable.store(useTableValue). Consumer render functions are called on every render (useRenderEveryTime)test: wait for zag's next-frame focus moves instead of asserting synchronouslymain. Zag moves focus and registers Escape on the nextrequestAnimationFrame, but the tests asserted before that frame. No assertion was removedbuild(deps): bump turbo to 2.11.7 and @modelcontextprotocol/sdk to 1.32.0test(table): make large mock data deterministiccreateLargeSecurityEventsusedMath.random()for Requests, so two Table screenshots changed on every runfix(overlay): keep popup positioner z-index in sync with its layer@zag-js/dismissable1.43.3 (via Ark UI 5.39.2): Select/DropdownMenu opened inside a nested Dialog/Drawer rendered under it. zag now registers the layer after popper's one-time z-index read, so the positioner stayed at 50 while the nested overlay is at 70. Newutils/syncLayerZIndexmirrors the content's z-index onto the positioner (MutationObserver); wired into DropdownMenu, Select, Popover and CalendarNotes for reviewers / consumers
feat, for the newDropdownMenu.onRequestDismissprop and the compiled output.react/compiler-runtime, which ships with React 19 and so matches the^19peer range. If a consumer mutates an array or object prop in place (for example, pushes intooptions) and re-renders, the component may not pick up the change. Pass a new reference instead..d.tspaths: with rslib 1.0, relative paths inside.d.tsnow end in.js//index.js. Every rewritten path points to an existing file, and the JS output did not change.dist/components/Table/index.d.tsanddist/index.d.tsare byte-identical to before. InternalTable/libchanged, for examplegetPinningStylesis gone.compiler:audit: 1346 functions compiled, 89 bailouts). Nothing from them leaks intodist.@types/node26: runtime is Node 24.@figma/code-connect2: v2 drops the React parser that all*.figma.tsxfiles are written for.@zag-js/file-utils1.44: kept in step with the zag version that Ark UI pins.vi.dynamicImportSettled. Thetest:uiscripts are removed.typecheckscript runstsc --noEmiton a solution-style tsconfig, so it checks nothing insrc. Usetsc --build tsconfig.app.json --noEmitinstead (clean). Worth a separate follow-up.Test plan
pnpm lint, realtsc --build tsconfig.app.json,pnpm test:run(also with--retry 0),pnpm buildandbuild-storybookpass locally after the rebase onto v2.0.0dorny/test-reporterreads Rstest's JUnit output (checked on an earlier CI run)🤖 Generated with Claude Code