Merged
Conversation
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.
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
Complete modernization of the codebase: comprehensive test coverage, bug fixes for 6 open issues, dependency updates, tooling migration, and demo redesign.
Changelog
Architecture
@react-avatar-editor/corepackageTesting (119 unit tests)
@react-avatar-editor/core— AvatarEditorCore class methods, utility functions, edge casesreact-avatar-editor— rendering, props, ref methods, events, DOM prop leaking, stylesBug Fixes
getCroppingRect()returns{x:0, y:0, width:1, height:1}instead of throwing/returning NaN when no image is loadedMath.roundfromgetInitialSize()to preserve exact aspect ratio proportions; addMath.roundtogetImage()canvas dimensions. Fixes square cropper producing off-by-one pixel output (e.g. 700x699 instead of 700x700)dragRef,mxRef,myRef) + callback refs, eliminating stale closures in document-level listeners. Fixes drag/pan completely broken in React 17maxWidth/maxHeight: 'none'to canvas default style. Prevents CSS resets (common in Next.js/Tailwind) from clipping the canvas whendevicePixelRatio > 1(Windows display scaling > 100%)package.jsonhas no.repository#432 — Addrepositoryfield to both package.json filesrepaintcallback was missing visual props (scale, rotate, borderRadius, etc.) from its dependency array, so the canvas never re-rendered when controls changedDemo Redesign (#421)
Dependency Updates
Tooling Migration
pnpm lint(oxlint),pnpm fmt(oxfmt),pnpm fmt:checkIssues 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 errorspnpm fmt:check— all files formattedpnpm --filter @react-avatar-editor/core test— 84 tests passpnpm --filter react-avatar-editor test:unit— 35 tests passpnpm build— builds successfully