Skip to content

Release v1.1.0 - #196

Draft
tbolis wants to merge 50 commits into
masterfrom
release/1.1.0
Draft

tbolis wants to merge 50 commits into
masterfrom
release/1.1.0

Conversation

@tbolis

@tbolis tbolis commented Oct 28, 2026 •

Copy link
Copy Markdown
Owner

Summary

Release 1.1.0 of react-sketch: the eraser, laser pointer and polygon tools, pinch zoom, line styles, and features that forks of react-sketch had, written again for the TypeScript code and fabric 7. The details are in the 1.1.0 entry of the CHANGELOG.

Added

  • Eraser tool (tool="eraser"), one stroke is one undo step.
  • Laser pointer tool (tool="laser-pointer"), a line that fades and is not stored in the sketch.
  • Polygon tool (tool="polygon"): a click or tap places a vertex, a click on the first vertex, a double click or Enter closes it, Escape cancels it. A closed polygon is one object and one undo step.
  • Pinch zoom: two fingers zoom and pan the view of the canvas. The pinchZoom, minZoom and maxZoom properties, the onViewChange callback and the resetView() method. The view is not saved and not an undo step.
  • Line style: the lineStyle property ("solid", "dashed", "dotted", "dash-dot") for the pencil, line, arrow, rectangle, rectangle label, circle and polygon.
  • Overlay image: setOverlayFromDataUrl() and removeOverlayImage().
  • backgroundImage and backgroundImageOptions properties.
  • crossOrigin option of addImg(), setBackgroundFromDataUrl() and setOverlayFromDataUrl().
  • Private workspace packages @react-sketch/eraser and @react-sketch/laserpointer, bundled by react-sketch.
  • Showcase: buttons for the eraser, laser pointer and polygon, the Overlay, View and line style controls, a backgroundImage tab, and a reset button for the zoom and the view. The pencil is the tool selected at the start.

Changed

  • toDataURL() draws the whole drawing, whatever the zoom and pan of the view. Before, the pan tool shifted what the image showed.
  • clear() also removes the overlay image.
  • When several images are asked for the overlay or the background, only the last request is set.
  • Each tool starts from the default cursor of free drawing.

Fixed

  • Arrow tool: a drawn arrow is not selectable, so a new arrow can be drawn over or across an earlier one.
  • Arrow tool: an arrow is one undo step, and onObjectAdded is called once with it.

Merged into this branch

#189, #193, #195, #197, #198, #199, #200, #201, #202, #203.

Fixes #82, #73, #51, #96, #84

tbolis and others added 25 commits October 27, 2026 13:40
Brings back three features that forks of react-sketch had, written again
for the TypeScript code and fabric 7.

- setOverlayFromDataUrl() and removeOverlayImage() (#73): an image drawn
  above the objects, with the options of the background image. It is
  saved by toJSON(), drawn by toDataURL(), scaled by the resize and
  removed by clear(). From addOverlayImg of yerffejytnac.
- The backgroundImage and backgroundImageOptions properties (#51),
  set when the component mounts and when they change, and kept when a
  value is loaded. From subforce-solutions.
- The crossOrigin option of addImg(), setBackgroundFromDataUrl() and
  setOverlayFromDataUrl() (#33, #95). null shows an image of a server
  without CORS headers. From react-sketch2 of x5engine.

The background and the overlay share one loader, with a counter by
layer, so only the last image asked for a layer is set.
- An Overlay section: a sample outline, an image of your own, and remove.
- A backgroundImage tab, which sets the background image through the
  property, with a URL field and the fit switches as the options.
- A switch for "Load Image from URL" that asks for the image with CORS.
Erases parts of the objects with @erase2d/fabric, one stroke is one undo
step, and the erased parts are saved by toJSON and loaded by fromJSON (#82).
…ct when a stroke is undone

An object which had a clip path got it wrapped in the erasing group by the
first stroke, and undo removed the group with it, so the clip path was lost.
The eraser code is copied from the TypeScript source of erase2d (MIT) into the
private workspace package @react-sketch/eraser, instead of being a dependency.
react-sketch bundles it, and the license is kept in packages/eraser/LICENSE.md
and in the bundle (dist/index.js.LICENSE.txt). The package is built before the
typecheck, the build and the tests.

Changes against the original: the code of @erase2d/core is in the package, the
lint rules of the repository are applied, and the erasing effect restores an
opacity of 0.
A brush too big for a cursor image (over 124 pixels) keeps the crosshair. Each
tool now starts from the default cursor of free drawing, so the cursor of the
eraser is not kept by the highlighter.
…p-cors

feat: 1.1.0, overlay image, backgroundImage property and crossOrigin option
A line which follows the pointer, gets thinner towards its start and
disappears about a second after it was drawn. It is drawn on the top
canvas of fabric only (a BaseBrush in the private package
packages/laserpointer, bundled into react-sketch), so it is not an object
of the sketch: it is not in toJSON() or toDataURL(), not an undo step, and
neither onObjectAdded nor onChange is called for it.

Tools get a dispose() hook, called when another tool takes over and when
the component unmounts, so the line does not outlive the laser pointer.
The laser pointer keeps its own line color and weight (red, 8px to start
with), as a thin black line is hardly seen, and the other tools get theirs
back when it is left.
tool="polygon", Tools.Polygon and Types.Tool.POLYGON (#96). Each click or tap places a vertex where the pointer is released. The polygon is closed by a click or tap on the first vertex, a double click or double tap, or the Enter key, and the Escape key cancels it. The polygon in progress is drawn on the top canvas only, it becomes one fabric.Polygon and one undo step when it is closed.

FabricCanvasTool gets finish(), called before dispose() when another tool takes over, and notifiesChange(), which replaces the check of the laser pointer in the events manager.
… what they do

The eraser cuts the polygon, the cut is saved and undone. The select tool moves, scales and rotates it as a whole, by drags of the mouse. The export has nothing of the polygon in progress, and has the polygon once it is closed.
The vertices are in canvas coordinates, so a zoom or a pan of the view in the middle of a polygon keeps the vertices placed, places the next ones in the new view, draws the preview in it, and keeps the radius of the first vertex in screen pixels.
…nvas

zoom() and the resize of the canvas scale the objects, so they scale the vertices of the polygon in progress too, through the new scale() hook of the tools. autoresize() returns the factors it scaled by.
The visible hint is short enough for the narrowest layout (a container of 228 pixels), and the button has the full instructions as its tooltip.
This was referenced Oct 28, 2026
engines already allows Node.js 26. The README and the 1.1.0 entry of the CHANGELOG say which versions the CI runs on.
ci: run on Node.js 26 too, with 22 and 24
tbolis and others added 16 commits October 29, 2026 18:17
- The first click after a polygon is closed or cancelled is a vertex, it
  was dropped as the second click of a double click.
- A double click needs the two releases within 4 pixels (10 on touch), so
  two vertices placed quickly near one another do not close the polygon.
- The polygon in progress is dropped when the sketch is cleared, a value is
  loaded, or an undo or a redo is done, through the new reset() hook of the
  tools.
- The keys are taken when the focus is on the page or in the sketch, not on
  a button or a dialog. Of two sketches, the one pressed last takes them.
The group of the line and the head was selectable and evented, as a
group is unless it says not. A press on an earlier arrow selected it and
a drag moved it, so an arrow could not be drawn over or across another
one. The group is frozen as the other shapes are, and the select tool
makes it selectable again.
fix: an arrow which is drawn is not selectable
The line and the head which are shown while the arrow is drawn were
recorded in the history and announced by onObjectAdded and
onObjectRemoved, as objects of the sketch. An arrow took three undos, and
onObjectAdded was called three times. The tools get an isPreview() hook:
the objects it says are previews are neither recorded nor announced.
The lineStyle property and the Types.LineStyle type: solid (the default),
dashed, dotted or dash-dot, with the dashes and the dots following
lineWidth. The pencil, line, arrow (its shaft), rectangle, rectangle
label, circle and polygon draw it, and the polygon in progress is shown
in it. The brush is shared by the tools, so the highlighter takes it back
to solid. The style is saved with the object by toJSON() and loaded by
fromJSON(). The showcase has the line styles in the Line section.
feat: line style (dashed, dotted, dash-dot)
Two fingers on the canvas zoom and pan its view (#84): the pinchZoom, minZoom and maxZoom properties, the onViewChange callback and resetView(). The view is the viewport of the canvas, the objects stay where they are, so it is not saved, not an undo step, and onChange is not called for it. toDataURL() draws the whole drawing, whatever the view.

When the second finger comes, what the first one started is dropped: the objects it added are taken off the canvas and out of the history, the free stroke stops, and the tool forgets the press (new cancel() hook of the tools, cancel() of the eraser and laser brushes). The eraser brush follows the first finger only, as the other brushes.
The View section has the pinchZoom switch, the smallest and the largest zoom,
and the view as onViewChange reports it (also the chip of the section). The
reset view button is next to the zoom buttons of the canvas.
…uttons

The buttons scale the drawing with zoom(), which is not the view of the
fingers that resetView() puts back, so on a desktop the reset did nothing.
The showcase keeps the factor the buttons scaled by, and the reset scales
by its inverse before it resets the view. The factor starts again when the
canvas is cleared, a value is loaded, or the scenario changes.
showcase: the pencil is the tool selected at the start
onChange was called 10 ms after every mouse up and mouse out, whether or not
the drawing changed: a click which selects, a drag of the pan tool and a
pointer which comes and goes all called it. The events manager now notes that
an object was added, modified or removed since the mouse was pressed, and
tells the application only then, once: the release which follows a mouse out
in the middle of a drawing has nothing more to tell. undo, redo and the load
of a value call onChange as before.

The README no longer lists the limitation, nor the one of the arrow's undo
steps, which #201 fixed.
fix: onChange is called when the sketch changed (#80)
The tools which draw a shape or pan freeze the objects of the canvas when
they take over, but not the ones added afterwards: an image from addImg(),
a text from addText(), a pasted object, and one which undo brings back were
selectable. A press on an image with the arrow tool selected it, and a drag
moved it instead of drawing the arrow.

The tools get isInteractive(), and the events manager freezes what is added
while the tool in use is not interactive. The select tool unfreezes all of
them when it takes over, as before.
…re-frozen

fix: the objects added while a drawing tool is in use are frozen
The Preview section has a small copy of the whole drawing, drawn again after
each change, undo, redo, zoom and clear with toDataURL({ multiplier }). When
the view is zoomed or panned, a frame shows the part which the canvas shows,
from onViewChange. The README has the recipe in "A preview of the drawing".
showcase: a preview of the drawing with a frame for the view (#150)
Each label subscribed to object:scaling and object:moving on the canvas
when it was drawn, and nothing unsubscribed. The listeners stayed after a
label was deleted or the canvas was cleared, so a canvas drawn on for long
kept more and more of them.

The canvas has the two listeners once, and they look the label up by the
target of the event. They are not removed with a label, as undo and redo
take its rectangle off the canvas and put it back, and it follows again.
fix: the rectangle label listens to the canvas once for all its labels
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

erase drawing by eraser

1 participant