Repository navigation
Migrate to React 19, Typescript, Vite, and Vitest - #5
Open
mrecachinas wants to merge 19 commits into
Open
mrecachinas wants to merge 19 commits into
mrecachinas wants to merge 19 commits into
Conversation
- Convert all class components to functional components with hooks - Replace legacy Context API (childContextTypes) with React.createContext + usePlot hook - Replace UNSAFE_componentWillReceiveProps with useEffect + useRef previous-props pattern - Replace Layer base class inheritance with shared usePlot() hook - Convert JavaScript to TypeScript with sigplot type declarations - Replace webpack with Vite (library mode, ESM + UMD output) - Replace Jest + Enzyme with Vitest + @testing-library/react - Add vitest-canvas-mock with measureText fix for sigplot compatibility - Update peer dependencies to React ^19.0.0 - Export SigPlotContext and usePlot hook for custom layer development - Bump version to 1.0.0 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Run 'npm run dev' and open http://localhost:5173 to see the example. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add Plot cleanup on unmount (SigPlot.tsx) — removes injected canvases and nulls refs/state to prevent memory leaks and Strict Mode issues - Fix multi-prop change drop in all layer update effects — use independent if blocks instead of if/else if chain so simultaneous prop changes are all processed - Fix WPipeLayer: add wsurl default, remove non-null assertions, remove unused overrides prop from interface - Guard change_settings calls against undefined props in all layers - Fix PipeLayer initial mount to handle ArrayBuffer data (not just arrays) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- BlueLayer: 5 tests covering mount, reload, headermod, no-op, unmount - Plugin: 2 tests covering add on mount, remove on unmount - src/ coverage now at ~80% (all public API components 94-100%) - Install @vitest/coverage-v8 for coverage reporting Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mock overlay_href in all HrefLayer and SigPlot HrefLayer tests to prevent sigplot from firing real XHR requests that fail in jsdom with a DataView bounds error when parsing bluefile responses. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add --no-warnings to vitest fork execArgv to suppress the harmless Node 25 localstorage-file warning emitted by jsdom workers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
mrecachinas
marked this pull request as ready for review
March 12, 2026 01:33
- Add 'Migrating from 0.x' section documenting the Layer base class removal with before/after code examples showing usePlot() hook - Document other breaking changes (React 19+, TypeScript types, Vite) - Add 'npm run dev' to Development section Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add proper dependency arrays to all update effects (previously ran on every render) - Split SigPlot's combined update effect into separate [height, width] and [options] effects, removing manual prev-ref tracking - Plugin now uses [plot, plugin, pluginOptions] deps so React handles teardown/re-add on prop changes - Wrap all layer and plugin components in React.memo to skip reconciliation when props are unchanged - Add missing overrides change tracking in WebsocketLayer Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add @biomejs/biome for linting and formatting (singleQuote, 2-space indent) - Add @typescript/native-preview (tsgo) for type-checking and declaration emit - Remove typescript and prettier config from package.json - Delete .eslintignore - Add biome.json with recommended rules - Add lint and format scripts - Update build/typecheck scripts to use tsgo - Replace eslint-disable comments with biome-ignore equivalents - Auto-format codebase with biome Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Packaging - Build ESM (.js) + CommonJS (.cjs) instead of UMD; `require()` of the old .umd.js crashed under "type": "module" - Import sigplot's CJS default export so Node ESM/Vitest consumers can load the package - Ship public Plot types (src/plot.ts) with ESM and CJS-scoped declarations; drop the leaked vitest.setup.d.ts - Add prepack so `npm publish` builds dist/ - Replace the TypeScript nightly with typescript@7; type-check tests and example too sigplot 3.x - Depend on sigplot ^3.1.7. The old ^2.0.0-rc20 range resolved to 2.0.0-rc9 because prerelease tags sort as strings - Layer IDs are UUIDs, so removing a layer no longer invalidates others Components - Add a shared useLayer hook replacing six copies of lifecycle code - HrefLayer: replace only its own layer on href change (rc9's deoverlay(undefined) wiped every layer) - Plugin: pass `zorder` (sigplot's real 2nd arg) instead of options - WebsocketLayer: reconnect only on wsurl change; copy overrides - Array/PipeLayer: send the header with reload/push instead of an extra headermod; accept typed arrays - BlueLayer: replace the layer on a new header instead of reload() - SigPlot: call disable_listeners() on unmount, expose the Plot via ref, skip redundant change_settings/checkresize on mount - Remove unexported WPipeLayer Tooling - Vitest 4 (fixes GHSA-82fw-gwwq-j7x9), parallel tests, narrow webstorage flag instead of --no-warnings - Drop unused canvas and jest-canvas-mock - CI on main with Node 22/24/26; remove Travis, jsdoc, and docgen configs Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
SigPlot applied size changes with checkresize() in a passive effect, which React may run after the browser has painted the resized container. The canvas then lags its container by a frame (measured: 49% of frames at 4x CPU throttle). Running it in a layout effect resizes the canvas before paint, and sigplot's rAF redraw still lands in the same frame (measured: 0 stale and 0 blank frames). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
WebKit-based browsers block cleartext HTTP to remote hosts, so the HrefLayer demo plot stayed empty there. The file is served over HTTPS with CORS. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
sigplot re-autoscales a 1-D pipe only on pushes that carry a header. 0.x and the original PR passed `options` with every push; 3598621 sent it only when it changed, so after the first frame the Y axis froze with autol <= 1 and crept with the default autol=100 (19 of 100 after 20 frames). Restore the 0.x behavior. Also document in the migration guide that children no longer receive an injected `plot` prop. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Node 20 exits with "bad option" for the flag, which crashed every Vitest worker even though Vitest 4 supports Node 20.19+. Detect support via process.allowedNodeEnvironmentFlags, and add @types/node for the config while keeping Node globals out of the library's declaration build. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Ports the ideas from spectriclabs#4 (by @dselck), rebuilt for sigplot 3.x: - <BoxesPlugin> wraps sigplot's boxes plugin: onAdd/onRemove/onMove/ onSelect receive copies of the plugin's live box objects, addOnMtag adds a box on ctrl/cmd-drag (ignoring plain clicks, which spectriclabs#4 turned into zero-size boxes), option changes apply to existing boxes, and a ref exposes addBox/removeBox/clearBoxes/getBoxes. boxselect carries `boxes` in sigplot 3.x, not `box` as spectriclabs#4 assumed. - <SigPlot onMtag> and a general usePlotEvent(type, handler) hook, which keeps the latest handler without re-subscribing and removes listeners on unmount. - PlotOptions, DataHeader, and LayerOptions now list the keys sigplot 3.1.7 reads, with docs, and mark plot settings sigplot reads only at creation or only on change. They keep an index signature, so unlisted keys still type-check. Several of spectriclabs#4's types were wrong for 3.x (rubberbox_mode, nospec, origin). Also copy options before handing them to sigplot, which deletes `name` from layer options and sets `pipe` on pipe headers, mutating the caller's objects (0.x had the same problem). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Performance: layers and SigPlot compared options objects by reference,
so inline `options={{ ... }}` counted as changed on every parent render.
Each render then ran headermod/change_settings/push and redrew every
plot. In a Chromium benchmark (3 plots, 60 Hz re-renders, no data
changes) that was 6 change_settings, 3 headermod, and 3 push calls per
render and 183 ms/s of main-thread time, versus 40 ms/s with stable
options. Plain-object props are now compared by value; data, callbacks,
and headers still by reference. After the fix both cases make 0 sigplot
calls and cost the same.
That required giving sigplot copies of every options object, since it
normalizes them in place (the Plot constructor adds xlab/ylab,
change_settings fills colors.fg/bg, layers set maxhold.decay). copyOf is
now a deep copy of plain objects and arrays, except user_data, which
sigplot stores on the layer by reference.
Memory: after unmounting, the last batch of plots stayed alive (20 of
20 in a mount/unmount test).
- setPlot(null) / setPlugin(null) in unmount cleanups queued state
updates that React held, with the Plot, until its next render.
- sigplot's mx.open caches the newest plot's 2D context in a module
global (mx._ctx) it never reads. SigPlot now clears it once its canvas
has left the page.
After both fixes, 0 Plots and 0 canvases survive an unmount.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Gives coding agents the commands CI runs, the source layout, and the non-obvious rules behind the code: sigplot mutates its inputs (copyOf), options are compared by value (propChanged), layer IDs are UUIDs, teardown must not setState(null), and the jsdom canvas measureText patch. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This branch has not been deployed
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.
Migrates react-sigplot to React 19, TypeScript, Vite, and Vitest, and rewrites the class components as function components built on a shared
useLayerhook.Release: 1.0.0 (major)
This changes the public API, the sigplot dependency, and the package format, so it's a major release. Existing
^0.1.16ranges stop below 0.2.0, so current users won't get it by accident.Breaking changes since 0.1.16
Requirements
react/react-dom^19).prop-typesis no longer a peer dependency.^3.1.7.^2.0.0-rc20range actually installed2.0.0-rc9, because npm sorts prerelease tags as strings.overlay_*are now UUID strings, andreload/pushthrow if given a numeric index. This only matters for code that calls the Plot API directly.API
Layerbase class is removed; write function components withusePlot().Pluginbase class is replaced by<Plugin plugin={instance} zorder={n} />.<SigPlot>no longer receive an injectedplotprop; useusePlot().<SigPlot>now receives thePlotitself (ref.current) instead of the component (ref.current.plot).href(HrefLayer),wsurl(WebsocketLayer), anddata(BlueLayer) are required.datachanges, instead of callingreload.Packaging
dist/react-sigplot.js) and CommonJS (dist/react-sigplot.cjs) builds with type declarations. Themainpath has changed.windowglobal are removed, since React 19 ships no UMD build.exportsmap blocks deep imports.WPipeLayeris removed; it was never exported.The README has a migration guide covering these.
Other changes
Fixes (also present in 0.1.16)
hrefchanges. Before, it removed every layer on the plot.window/documentlisteners on unmount.namefrom layer options, setspipeon pipe headers, and fills in defaults on plot options, so it now gets a copy.options={{ autol: 1 }}no longer redo work on every render. Options were compared by reference, so each parent render re-applied them and redrew every plot; they're now compared by value. In a Chromium benchmark with 3 plots re-rendering at 60 Hz, this cut main-thread time from 183 ms/s to 39 ms/s.New
<BoxesPlugin>wraps sigplot's boxes plugin:onAdd/onRemove/onMove/onSelectcallbacks, which receive copies of the boxes;addOnMtag, which adds a box on ctrl/⌘-drag;refforaddBox/removeBox/clearBoxes/getBoxes.onMtagon<SigPlot>, andusePlotEvent(type, handler)for any sigplot event.PlotOptions,DataHeader, andLayerOptionslist the settings sigplot 3.1.7 reads, with docs.Plot,LayerId,PlotPlugin, …).usePlot()andSigPlotContext.refon<SigPlot>.The boxes plugin,
onMtag, and typed options are ported from #4 and updated for sigplot 3.x.Tooling
mainwith Node 22, 24, and 26.prepackbuildsdist/before every publish.Testing
@arethetypeswrong/clifinds no problems (node10, node16 CJS and ESM, bundler).npm packin a fresh project and checked:requireimporttscwithskipLibCheck: false, bothbundlerandnodenextresolutionnpm run dev) in Chromium and WebKit, and drew and moved boxes in Chromium.onMtag) three times. After forced garbage collection, 0 Plots and 0 canvases remained.Known issues
budo,travis) as runtime dependencies. That adds about 300 packages to every install, including anellipticadvisory that has no fix.main's sigplot rc20 has the same problem; it needs a fix in sigplot.repository,homepage, andbugsinpackage.jsonstill point to LGSInnovations/react-sigplot, the repo this one was forked from.