Skip to content

Modernize the toolchain and add a test suite - #3

Merged
Guiw5 merged 5 commits into
mainfrom
chore/tooling-2026
Sep 8, 2026
Merged

Guiw5 merged 5 commits into
mainfrom
chore/tooling-2026

Conversation

@Guiw5

@Guiw5 Guiw5 commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Stacked on #2 — review that one first.

Summary

Brings the toolchain up to date and adds the test suite the project never had. No API change.

Build tooling

  • Deleted .babelrc. It existed only for transform-remove-console, and there are no console calls left in the library. Its real effect was disabling SWC, so every Next build ran through Babel/webpack.
  • Next 14 → 16 (Turbopack) and React 18 → 19 for the docs site, so the React 19 support claimed in React 19 support, migrate to @react-spring/web and @use-gesture/react #2 is exercised on every build.
  • microbundle → tsup. microbundle is unmaintained and was pinned to a rollup/TS stack from 2021.
  • Added an exports map with a real .mjs build. ./dist/style.css is kept as an export so existing import 'guiw5-bottom-sheet/dist/style.css' does not break; ./style.css is the new shorter path.
  • ESLint 8 (eslintrc) → 9 (flat config). eslint-config-react-app is unmaintained and pins ESLint 8; replaced with typescript-eslint + eslint-plugin-react-hooks v7 + jsx-a11y + @next/eslint-plugin-next.
  • Split the PostCSS pipelines. The published stylesheet was being run through Tailwind, and the docs were pulling in the library's custom-property fallbacks. Selected with POSTCSS_TARGET=library.
  • Tailwind 3 → 4 for the docs, with the theme ported from tailwind.config.js to CSS-first tokens in docs/theme.css. The old config still used the v2 purge key and a variants block that has been dead since v3, and aliased gray to a colour (blueGray) removed in v3.
  • husky 6 → 9. The husky key in package.json was v4 format, so the pre-commit hook has not been running at all; hooks now live in .husky/.
  • prettier 3, lint-staged 17, semantic-release 25, @types/node 14 → 24. trailingComma pinned to es5 to avoid reformatting the whole repo.
  • Removed rimraf, postcss-svgo, svgo and @types/classnames — all unreferenced.

CI

  • actions/checkout and setup-node v4 → v5, Node 20 → 22 and 24, npm caching enabled.
  • CI no longer runs twice on pushes to main (both workflows were doing it).
  • Least-privilege permissions blocks, and npm build provenance on release.

Tests

25 tests, ~3s. Covers utils, the XState machine, and the component in happy-dom, including regression tests for the bugs fixed in #2:

  • initialState: 'OPEN' must take the immediate branch and never render visually hidden (this is what skipInitialTransition drives).
  • CLOSE while already closed is a no-op.
  • The SNAP payload reaches the spring actor.
  • deactivate runs before the close animation.
  • The sheet opens under StrictMode — the exact case where react-spring v8 left the springs dead.

Portal

Replaced the vendored @reach/portal copy (4 files) with a ~30 line src/Portal.tsx. It renders into a detached node and attaches it in a layout effect, which removes the extra render and the placeholder <span> the create-then-forceUpdate approach needed. It also applies the data-rsbs-portal attribute, which the vendored copy silently dropped.

Deliberately not upgraded

held at why
ESLint 9 eslint-plugin-jsx-a11y has no ESLint 10 support, and a11y linting is worth keeping here
TypeScript 5.9 7.0 breaks tsup's dts step (its bundled rollup-plugin-dts is built against TS 5.7). Verified: the JS builds, the types do not
focus-trap 6 v8 roughly doubles the size for nothing this component uses
body-scroll-lock 3 v4 is still a beta

Known warnings (not new)

Lint reports 8 warnings from the React Compiler era rules, all pre-existing patterns: reading refs during render in useSnapPoints and useReducedMotion, and setState in an effect in useReady. They are warnings rather than errors on purpose — useReady in particular causes several cascading renders on mount, and reworking it belongs in the performance PR.

Test plan

  • npm test: lint, 25 unit tests, library build, docs build
  • Library output checked: externals correct, no bundled deps, optional chaining downleveled for the browserslist target, exports paths resolve
  • Docs verified in Chrome (mobile emulation): home page, fixtures/simple, fixtures/sticky, fixtures/scrollable — open, drag, snap, content resize, Escape dismiss, unmount, scroll-lock and aria-hidden restore
  • Real iOS Safari and Android Chrome

Drop the Babel config so Next can use SWC/Turbopack, upgrade to Next 16 and React 19, swap microbundle for tsup with a proper exports map, move to ESLint flat config, and add vitest coverage for the machine, utils and component. Replaces the vendored @reach/portal copy with a portal that renders into a detached node, avoiding an extra render and a placeholder element.
The published stylesheet no longer runs through Tailwind, and the docs no longer pull in the library's custom property fallbacks by accident. The docs theme moves from tailwind.config.js to CSS-first tokens, which also drops a dead Tailwind 2 variants block.
@Guiw5
Guiw5 changed the base branch from chore/react19-perf to main September 8, 2026 20:14
@Guiw5
Guiw5 merged commit 75cc553 into main Sep 8, 2026
2 checks passed
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 3.9.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant