Releases: spaansba/ForesightJS
Release list
js.foresight@4.2.1
Patch Changes
-
#168
dfb88f3Thanks @spaansba! - Fix lazy predictor connects leaking global listeners when a handler disconnects mid-import.DesktopHandler.connectTabPredictor/connectScrollPredictorandTouchDeviceHandler.setTouchPredictornow re-checkisConnectedafter the dynamicimport()resolves, so a predictor whose handler disconnected during loading no longer attacheskeydown/focusin/pointerdownlisteners that never get aborted. -
#158
8250ad8Thanks @spaansba! -CircularBuffernow exposespeekWriteSlot()for zero-allocation slot reuse and drops the unusedgetFirstLast()tuple accessor in favor ofgetFirst()/getLast(). -
#163
53ef414Thanks @spaansba! - Drop 4 redundantif (!this.isSetup)guards aroundinitializeGlobalListeners(). The method already self-guards onisSetup, so the outer checks were dead weight. -
#167
21f066aThanks @spaansba! - Store event listeners in aSetinstead of an array. Iterating aSetduringemitmeans a listener that unsubscribes another mid-dispatch no longer causes the next listener to be skipped, and registration now dedupes like the DOMaddEventListener. -
#171
31d9222Thanks @spaansba! - DeriveForesightEventfromkeyof ForesightEventMapinstead of hand-duplicating the event names, so adding an event to the map no longer requires updating the union in lockstep. -
#159
1de7d1cThanks @spaansba! - Skip building thecallbackInvokedandcallbackCompletedevent payloads when no one is subscribed. Both emits now sit behind ahasListenersguard, avoiding a per-callback object allocation and, forcallbackCompleted, theactiveElementCountscan that fed itswasLastActiveElementfield. -
#174
f1e06e6Thanks @spaansba! - Element state and bounds subscriberSets are now created on first subscribe instead of eagerly at registration. Headless and plain-JS usage that registers elements but never subscribes to reactive state (the common case outside the framework wrappers) no longer allocates two emptySets per element. -
#166
ef09598Thanks @spaansba! - SimplifyloadedPredictors.mouseto a constant sincemousePredictoris never null. -
#157
502cb8dThanks @spaansba! - Register the globalpointermovelistener as passive, letting the browser dispatch high-frequency pointer events without treating them as cancelable. Reduces main-thread scheduling pressure during fast mouse movement and scrolling. -
#162
b6c50f1Thanks @spaansba! - Remove unusedCircularBuffermembers (clear,size,isFull,isEmpty) that were only referenced by tests. -
#170
8dc9f8eThanks @spaansba! - The mouse trajectory scan now iterates a precomputed set of scannable elements (on-screen, active, not yet predicted) instead of walking the full registry and re-checking those flags every pointer move. Membership is kept in sync on registration, state changes, and unregistration. Cost now scales with the number of visible elements rather than the total registered, so pages with many registered but few on-screen elements run the per-frame scan dramatically faster with no change at small element counts. -
#164
4dd5947Thanks @spaansba! - ExtractscheduleReactivateTimeoutto remove three copy-pasted reactivation-timeoutsetTimeoutblocks, mirroring the existingclearReactivateTimeout. -
#169
b46a3fdThanks @spaansba! -ScrollPredictorno longer caches a"none"scroll direction for the wholehandlePositionChangebatch. A non-moving element (e.g.position:fixed) returning"none"used to poison the cached direction and silently disable scroll prefetch for every later element that actually moved. The direction is now only locked in once a real direction is found. -
#161
ab0798fThanks @spaansba! -predictNextScrollPositionnow writes into a caller-ownedoutpoint instead of allocating a new one per call, matchingpredictNextMousePosition.ScrollPredictorreuses a single predicted-point object across the batch, removing the per-scroll-batch allocation. -
#174
5cbefa6Thanks @spaansba! -applySettingsChangesnow returns just the changed-settings array instead of that array plus six hand-wired side-effect booleans.alterGlobalSettingsderives aSetof changed keys and checkschanged.has(...), so adding a setting no longer means keeping a parallel flag struct in sync in three places. -
#173
51cd5fdThanks @spaansba! - Share a base factory betweencreateElementInternalandcreateUnregisteredSnapshotso the fullForesightElementStatefield list is only written once, preventing the snapshot from silently drifting when a field is added. -
#174
f1e06e6Thanks @spaansba! - Share a single frozen emptymetaobject across element states instead of allocating a fresh{}per element. The state snapshot is immutable andmetais never mutated in place, so registered elements without ametaand unregistered snapshots now reuse one object.
js.foresight-devtools@2.2.1
Patch Changes
-
#167
21f066aThanks @spaansba! - Store event listeners in aSetinstead of an array. Iterating aSetduringemitmeans a listener that unsubscribes another mid-dispatch no longer causes the next listener to be skipped, and registration now dedupes like the DOMaddEventListener. -
#172
17469e6Thanks @spaansba! - Element overlays no longer force a compositor layer per overlay (will-change: transform) and name labels no longer usebackdrop-filter: blur. On pages with many visible elements this kept hundreds of GPU layers alive and re-sampled a blur every frame, saturating the compositor and making the mouse trajectory line visibly lag behind the cursor. Labels now use a more opaque background so they stay readable without the blur. -
Updated dependencies [
dfb88f3,8250ad8,53ef414,21f066a,31d9222,1de7d1c,f1e06e6,ef09598,502cb8d,b6c50f1,8dc9f8e,4dd5947,b46a3fd,ab0798f,5cbefa6,51cd5fd,f1e06e6]:- js.foresight@4.2.1
V4.2.0 - The `<Foresight>` Component
v4.2 reworks the React and Vue packages around a single declarative <Foresight> component. Registering a list of elements no longer means wiring up useForesights and juggling callback refs. You wrap your items in <Foresight> and you're done. Under the hood the core also got a round of dedup and cleanup: duplicated settings/registration/logging paths are gone, and data-attribute mirroring is now a single global manager setting instead of a per-element concern.
js.foresight v4.2.0
- New:
dataAttributeMirroringglobal setting. Mirroring registration data to elementdata-*attributes is now controlled once on the manager instead of per element (#133). - Changed: active/parked element counts are now derived from state rather than tracked separately, removing a class of drift bugs (#134).
- Fix: changing the touch strategy to its current value no longer triggers a no-op settings change (#125).
- Fix: the desktop handler now respects
positionHistorySizeon init (#124). - Performance: only active elements are observed on handler connect; parked elements stay out of the observer until reactivated (#126).
- Internal: removed duplicated settings/registration/logging code paths (#129) and dropped the unused
HasListenersFunctiontype export (#127).
js.foresight-devtools v2.2.0
- Updated for the core changes above; element data-attribute display follows the new global
dataAttributeMirroringsetting (#133).
@foresightjs/react v0.3.0
- New:
<Foresight>component replacesuseForesightsfor registering dynamic lists of elements declaratively (#131). - Fix:
useForesightnow handles multiple refs correctly (#135).
@foresightjs/vue v0.3.0
- New:
<Foresight>component replacesuseForesightsfor registering dynamic lists of elements declaratively (#132). - Fix:
useForesightnow handles multiple refs correctly (#135).
Full Changelog: V4.1.0...V4.2.0
V4.1.0 - Bounds channel & scroll re-render fix
js.foresight v4.1.0
- New: element geometry moved to a dedicated bounds channel ->
ForesightRegisterResultnow hasgetBounds()andsubscribeToBounds()for position/size updates (fired on every scroll/resize tick while visible) (#120) - Changed:
subscribe()/getSnapshot()now only fire/change on logical state changes, never on scroll/resize —> state snapshots are referentially stable while scrolling (#120) - Breaking-ish:
ForesightElementState.elementBoundsremoved;hitSlopnow lives directly on the state snapshot; new exportedElementBoundstype (#120)
js.foresight-devtools v2.1.0
- Performance: log tab rewritten around a dedicated log store, element tab render optimizations, cheaper/batched overlay updates (#119)
- Element overlays read geometry from the new core bounds channel (#120)
@foresightjs/react v0.2.0
- Performance: useForesights coalesces store notifications to one snapshot check per microtask instead of one per element per scroll tick (#120)
- Components no longer re-render on scroll/resize —> only on logical state changes, thanks to the core bounds split (#120)
@foresightjs/vue v0.2.0
- No functional changes; peer dependency bumped to js.foresight ^4.1.0
ForesightJS v4.0 - Official Framework Packages
The goal of v4.0 is to make ForesightJS a lot easier to use with popular frameworks. Until now, the docs handed you premade hooks, composables and directives to copy into your own project. v4 replaces all of that with two official wrapper packages: @foresightjs/react and @foresightjs/vue. Install one, delete your copied files, and you're done.
To make reactive bindings possible, the core element data model was reworked into immutable state snapshots with a subscription model. The same primitives the wrapper packages are built on, and the same ones you can use to build a binding for your own framework (Angular, Svelte, Solid, …).
Upgrading from v3.5? Follow the migration guide. The v3.5 docs stay available via the version dropdown.
js.foresight v4.0.0
- Immutable element state.
ForesightElementDatais nowForesightElementState: a flat, immutable snapshot whose reference is replaced (never mutated) on every change, so it plugs straight into any reactivity system. - New
register()return value. Besides the element state it now returnsunregister,subscribeandgetSnapshot isTouchDeviceis gone from the result; touch devices are handled internally by thetouchDeviceStrategyglobal setting.- New
updateElementOptions(). Change the options of an already-registered element in place. See registration options. - New
enabledelement option. Keep an element registered but excluded from prediction. - Detached elements are parked, not unregistered. Removing an element from the DOM no longer
unregisters it; it's parked (isParked: true) and resumes automatically when it reconnects. - Leaner event system. The
elementDataUpdated,elementOptionsUpdatedandelementReactivatedevents are removed in favor of the subscriber pattern; the remaining events carry the snapshot in astatefield. - Removed deprecated APIs. The
debugglobal setting (use
js.foresight-devtools) andunregisterOnCallback(usereactivateAfter) are gone. - Performance. Pre-allocated trajectory event objects, faster trajectory calculations, error handling around subscriber listeners and extra
isConnectedguards.
Devtools — js.foresight-devtools v2.0.0
- Updated for the v4 core state model and event system.
- New nested
showoptions to toggle each visualization individually:controlPanel,nameTags,elementOverlays,mouseTrajectoryandscrollTrajectory. - Better Elements tab. Elements are grouped into Active/Inactive with collapsible sections, and
inactive elements carry reason badges (disabled,parked,limited,fired) explaining why. - Full docs: Development Tools.
New — @foresightjs/react V0.1.0
Official React (18+) bindings, with dedicated React docs including Next.js and [React Router (https://foresightjs.com/docs/react/react-router) guides.
useForesight— register a single element and get
its live state plus a callback ref to bind it.useForesights— register a dynamic list of
elements from one hook call.useForesightEvent— subscribe to a
ForesightManager event for the lifetime of the component.- Options like
hitSlopandenabledare reactive — change a prop and the registration updates.
New — @foresightjs/vue V0.1.0
Official Vue 3 (3.5+) bindings, with [dedicated Vue docs (https://foresightjs.com/docs/vue/installation).
v-foresight— directive to register an element with a callback or full options object.useForesight— register a single element and get reactive refs for its state.useForesights— register a dynamic list of elements from a single composable.useForesightEvent— subscribe to a ForesightManager event for the lifetime of the calling scope.
Docs
- The docs are now framework-aware: pick React or Vue from the dropdown at the top of the sidebar to get the entire documentation tailored to your framework.
- New Other Frameworks page showing how to build your own thin binding with the
subscribe/getSnapshotpattern (Angular, Svelte, Solid examples). If you build one, sharing it is highly appreciated! - Migration guides for core, React and Vue.
V3.5.0 - NodeList support
V3.4.0
Added Lazy Loading
ForesightJS is designed to be lightweight. The entire library with all features is only ~32 KB minified. But now we go further with code splitting to minimize your initial bundle even more. Both handlers and predictors are lazy-loaded based on device type and enabled features:
Current chunk sizes:
| Chunk | Size | Loaded When |
|---|---|---|
| Core | ~14 KB | Always (initial load) |
| DesktopHandler + MousePredictor | ~15 KB | Desktop/mouse users |
| TouchDeviceHandler | ~2 KB | Touch device users |
| TabPredictor + tabbable | ~7 KB | enableTabPrediction: true |
| ScrollPredictor | ~1.5 KB | enableScrollPrediction: true |
| Touch predictors | ~1.5 KB | Touch device (based on strategy) |
Result:
- Touch devices load only ~19 KB (core + touch handler + touch predictor)
- Desktop with mouse-only loads ~32 KB (core + desktop handler + mouse predictor)
- Additional predictors (Tab, Scroll) load on-demand when enabled
js.foresight (V3.4.0)
- Added lazy loading to the predictors.
- Added
loadedModulestogetManagerData()
js.foresight-devtool (V1.4.0)
- Update devtools to display loaded modules in state log
V3.3.5
V3.3.4
V3.3.2 - Configurable minimum connection type
V3.3.2 js.foresight
Features
- Added support for configuring the minimum connection speed with the
minimumConnectionTypeprop. Options includeslow-2g,2g,3g, and4g(default:3g). This replaces the previous fixed value ofslow-2g. Thanks to @stijns96 for PR #16.
V1.3.2 js.foresight-devtools
Features
- The
minimumConnectionTypecan now be toggled directly from the control panel. - The control panel can be positioned in any of the four screen corners. This preference is set in the control panel and is stored in
localStorage.