Skip to content

Modernize codebase, fix bugs, add tests#433

Merged
mosch merged 16 commits intomainfrom
modernize-and-fix-issues
Mar 21, 2026
Merged

Modernize codebase, fix bugs, add tests#433
mosch merged 16 commits intomainfrom
modernize-and-fix-issues

Conversation

@mosch
Copy link
Copy Markdown
Owner

@mosch mosch commented Mar 21, 2026

Summary

Complete modernization of the codebase: comprehensive test coverage, bug fixes for 6 open issues, dependency updates, tooling migration, and demo redesign.

Changelog

Architecture

  • Extract framework-agnostic core logic into @react-avatar-editor/core package
  • Clean separation: core (pure canvas/image logic, zero deps) → React wrapper → demo app

Testing (119 unit tests)

  • 84 tests for @react-avatar-editor/core — AvatarEditorCore class methods, utility functions, edge cases
  • 35 tests for react-avatar-editor — rendering, props, ref methods, events, DOM prop leaking, styles
  • Vitest + jsdom + React Testing Library

Bug Fixes

Demo Redesign (#421)

  • Modern dark theme with checkerboard transparency pattern behind editor canvas
  • Organized control grid with sliders, toggles, color pickers
  • DM Sans / DM Mono typography
  • Responsive layout
  • Removed legacy GitHub Pages layout, MeyerWeb CSS reset, unused assets

Dependency Updates

Package Before After
TypeScript 5.3 5.9
Vite 5 8
React (dev/demo) 18 19
@vitejs/plugin-react 4 6
@playwright/test 1.57 1.58
react-dropzone 14 15

Tooling Migration

  • Replace ESLint + Prettier with oxlint + oxfmt — Rust-based, ~35ms lint, ~260ms format
  • Replace tsdown with Vite for library builds — unified build/test tooling on a single bundler
  • Switch from Netlify to Cloudflare Pages
  • CI: Node.js 18 → 22, added lint + format check + unit test steps
  • Scripts: pnpm lint (oxlint), pnpm fmt (oxfmt), pnpm fmt:check

Issues Referenced

Closes #389, closes #402, closes #406, closes #421, closes #429, closes #431, closes #432

Also addresses the concerns raised in:

Test Plan

  • pnpm lint — 0 warnings, 0 errors
  • pnpm fmt:check — all files formatted
  • pnpm --filter @react-avatar-editor/core test — 84 tests pass
  • pnpm --filter react-avatar-editor test:unit — 35 tests pass
  • pnpm build — builds successfully
  • Demo tested manually — all controls (zoom, rotation, roundness, size, border, grid, toggles) working

mosch added 16 commits March 21, 2026 07:36
Separates framework-agnostic canvas/image logic from the React wrapper.
The core package contains AvatarEditorCore class, all utility functions,
and TypeScript types with zero dependencies.
- 83 unit tests for @react-avatar-editor/core covering AvatarEditorCore
  class methods, utility functions, and edge cases
- 35 unit tests for react-avatar-editor React component covering
  rendering, props, ref methods, events, style, and DOM prop leaking
- Set up Vitest with jsdom environment and React Testing Library
Closes #389

getCroppingRect() now returns a default rect {x:0, y:0, width:1, height:1}
when image dimensions are not yet available, instead of throwing or
returning NaN values.
Closes #429

Remove Math.round from getInitialSize() to preserve exact aspect ratio
proportions. Add Math.round to getImage() canvas dimensions as a safety
net. Previously, rounding in getInitialSize introduced precision errors
that cascaded through getXScale/getYScale/getCroppingRect, causing a
700x800 image with a square cropper to produce 700x699 instead of 700x700.
Closes #432

Add repository metadata to both @react-avatar-editor/core and
react-avatar-editor package.json files.
Closes #431

The document-level mousemove/mouseup listeners were registered once on
mount but captured stale closure values (drag, mx, my) that never
updated. This broke dragging entirely in React 17 and was fragile in
React 18.

Fix: use refs (dragRef, mxRef, myRef) for values read by document
handlers, and store callback props (onMouseUp, onMouseMove,
onPositionChange) in refs so handlers always call the current version.
Read imageState from coreRef instead of the closure.
Closes #402

Add maxWidth/maxHeight: 'none' to the canvas default style to prevent
CSS resets (common in Next.js, Tailwind, and modern CSS frameworks)
from constraining the canvas display size when devicePixelRatio > 1.
Without this, rules like 'max-width: 100%' can shrink the CSS display
size while the HiDPI drawing buffer remains larger, showing only a
portion of the content.
- TypeScript 5.3 -> 5.9
- ESLint 8 -> 9 with flat config (eslint.config.mjs)
- Prettier 3.1 -> 3.8
- typescript-eslint 6 -> 8 (unified package)
- tsdown 0.16 -> 0.21
- Vite 5/6 -> 8
- React 18 -> 19 (devDeps and demo)
- @vitejs/plugin-react 4 -> 6
- @playwright/test 1.57 -> 1.58
- react-dropzone 14 -> 15
- Fix lint issues from stricter rules (unused bindings, no-explicit-any)
- Remove eslint, prettier, typescript-eslint, eslint-config-prettier
- Add oxlint (v1.56.0) for linting and oxfmt (v0.41.0) for formatting
- Migrate prettier config to .oxfmtrc.json via oxfmt --migrate=prettier
- Add .oxlintrc.json with correctness (error) + suspicious (warn) categories
- Update scripts: lint -> oxlint, fmt -> oxfmt --write, fmt:check -> oxfmt --check
- Fix lint warnings: use addEventListener over on-properties, move functions
  to outer scope, rename shadowed variables
- Reformat entire codebase with oxfmt
- Update test mocks to match addEventListener API
Node.js 18 lacks node:util.styleText required by rolldown (tsdown dep).
Also fix action ordering (setup-node before pnpm install), update
actions to v4, and add lint + format check + unit test steps.
Add resolve alias in vitest config to point at core source directly,
so lib unit tests work without requiring a prior core build step.
Remove netlify.toml, add wrangler.jsonc with Pages build config.
Build command: pnpm demo:build, output: packages/demo/dist.
Remove tsdown dependency and use vite build in lib mode with
vite-plugin-dts for type generation. Merge vitest configs into
vite.config.ts files. This unifies build/test tooling on a single
bundler (vite) across all packages.
Closes #406

Remove the ...rest spread from the canvas element. All component props
are explicitly destructured, so rest only contained unknown/extraneous
props that shouldn't be forwarded to the DOM. This prevents React
warnings about unrecognized DOM attributes.
Closes #421

Replace the 2013-era GitHub Pages layout with a clean, dark,
tool-inspired interface:
- Dark theme with checkerboard transparency pattern behind editor
- Organized control grid with sliders, toggles, and color pickers
- DM Sans / DM Mono typography
- Responsive layout
- Remove old MeyerWeb CSS reset, Arvo font, fixed sidebar layout
- Remove unused image assets
The repaint callback only depended on [imageState, border] but not on
scale, rotate, borderRadius, showGrid, color, etc. When those props
changed, the core config was updated but repaint never re-ran because
its dependency array was unchanged. Add all visual props to the
repaint dependency array.
@mosch mosch merged commit ed7232a into main Mar 21, 2026
1 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant