Skip to content

Releases: spaansba/ForesightJS

js.foresight@4.2.1

Choose a tag to compare

@github-actions github-actions released this 08 Jul 19:59
d4bf65a

Patch Changes

  • #168 dfb88f3 Thanks @spaansba! - Fix lazy predictor connects leaking global listeners when a handler disconnects mid-import. DesktopHandler.connectTabPredictor/connectScrollPredictor and TouchDeviceHandler.setTouchPredictor now re-check isConnected after the dynamic import() resolves, so a predictor whose handler disconnected during loading no longer attaches keydown/focusin/pointerdown listeners that never get aborted.

  • #158 8250ad8 Thanks @spaansba! - CircularBuffer now exposes peekWriteSlot() for zero-allocation slot reuse and drops the unused getFirstLast() tuple accessor in favor of getFirst()/getLast().

  • #163 53ef414 Thanks @spaansba! - Drop 4 redundant if (!this.isSetup) guards around initializeGlobalListeners(). The method already self-guards on isSetup, so the outer checks were dead weight.

  • #167 21f066a Thanks @spaansba! - Store event listeners in a Set instead of an array. Iterating a Set during emit means a listener that unsubscribes another mid-dispatch no longer causes the next listener to be skipped, and registration now dedupes like the DOM addEventListener.

  • #171 31d9222 Thanks @spaansba! - Derive ForesightEvent from keyof ForesightEventMap instead of hand-duplicating the event names, so adding an event to the map no longer requires updating the union in lockstep.

  • #159 1de7d1c Thanks @spaansba! - Skip building the callbackInvoked and callbackCompleted event payloads when no one is subscribed. Both emits now sit behind a hasListeners guard, avoiding a per-callback object allocation and, for callbackCompleted, the activeElementCount scan that fed its wasLastActiveElement field.

  • #174 f1e06e6 Thanks @spaansba! - Element state and bounds subscriber Sets 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 empty Sets per element.

  • #166 ef09598 Thanks @spaansba! - Simplify loadedPredictors.mouse to a constant since mousePredictor is never null.

  • #157 502cb8d Thanks @spaansba! - Register the global pointermove listener 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 b6c50f1 Thanks @spaansba! - Remove unused CircularBuffer members (clear, size, isFull, isEmpty) that were only referenced by tests.

  • #170 8dc9f8e Thanks @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 4dd5947 Thanks @spaansba! - Extract scheduleReactivateTimeout to remove three copy-pasted reactivation-timeout setTimeout blocks, mirroring the existing clearReactivateTimeout.

  • #169 b46a3fd Thanks @spaansba! - ScrollPredictor no longer caches a "none" scroll direction for the whole handlePositionChange batch. 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 ab0798f Thanks @spaansba! - predictNextScrollPosition now writes into a caller-owned out point instead of allocating a new one per call, matching predictNextMousePosition. ScrollPredictor reuses a single predicted-point object across the batch, removing the per-scroll-batch allocation.

  • #174 5cbefa6 Thanks @spaansba! - applySettingsChanges now returns just the changed-settings array instead of that array plus six hand-wired side-effect booleans. alterGlobalSettings derives a Set of changed keys and checks changed.has(...), so adding a setting no longer means keeping a parallel flag struct in sync in three places.

  • #173 51cd5fd Thanks @spaansba! - Share a base factory between createElementInternal and createUnregisteredSnapshot so the full ForesightElementState field list is only written once, preventing the snapshot from silently drifting when a field is added.

  • #174 f1e06e6 Thanks @spaansba! - Share a single frozen empty meta object across element states instead of allocating a fresh {} per element. The state snapshot is immutable and meta is never mutated in place, so registered elements without a meta and unregistered snapshots now reuse one object.

js.foresight-devtools@2.2.1

Choose a tag to compare

@github-actions github-actions released this 08 Jul 19:59
d4bf65a

Patch Changes

  • #167 21f066a Thanks @spaansba! - Store event listeners in a Set instead of an array. Iterating a Set during emit means a listener that unsubscribes another mid-dispatch no longer causes the next listener to be skipped, and registration now dedupes like the DOM addEventListener.

  • #172 17469e6 Thanks @spaansba! - Element overlays no longer force a compositor layer per overlay (will-change: transform) and name labels no longer use backdrop-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

Choose a tag to compare

@spaansba spaansba released this 13 Jun 20:25
8b65e23

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: dataAttributeMirroring global setting. Mirroring registration data to element data-* 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 positionHistorySize on 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 HasListenersFunction type export (#127).

js.foresight-devtools v2.2.0

  • Updated for the core changes above; element data-attribute display follows the new global dataAttributeMirroring setting (#133).

@foresightjs/react v0.3.0

  • New: <Foresight> component replaces useForesights for registering dynamic lists of elements declaratively (#131).
  • Fix: useForesight now handles multiple refs correctly (#135).

@foresightjs/vue v0.3.0

  • New: <Foresight> component replaces useForesights for registering dynamic lists of elements declaratively (#132).
  • Fix: useForesight now handles multiple refs correctly (#135).

Full Changelog: V4.1.0...V4.2.0

V4.1.0 - Bounds channel & scroll re-render fix

Choose a tag to compare

@spaansba spaansba released this 10 Jun 21:43
f698b1c

js.foresight v4.1.0

  • New: element geometry moved to a dedicated bounds channel -> ForesightRegisterResult now has getBounds() and subscribeToBounds() 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.elementBounds removed; hitSlop now lives directly on the state snapshot; new exported ElementBounds type (#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

Choose a tag to compare

@spaansba spaansba released this 10 Jun 13:59
57e3117

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. ForesightElementData is now ForesightElementState: 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 returns unregister, subscribe and getSnapshot
  • isTouchDevice is gone from the result; touch devices are handled internally by the touchDeviceStrategy global setting.
  • New updateElementOptions(). Change the options of an already-registered element in place. See registration options.
  • New enabled element 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, elementOptionsUpdated and elementReactivated events are removed in favor of the subscriber pattern; the remaining events carry the snapshot in a state field.
  • Removed deprecated APIs. The debug global setting (use
    js.foresight-devtools) and unregisterOnCallback (use reactivateAfter) are gone.
  • Performance. Pre-allocated trajectory event objects, faster trajectory calculations, error handling around subscriber listeners and extra isConnected guards.

Devtools — js.foresight-devtools v2.0.0

  • Updated for the v4 core state model and event system.
  • New nested show options to toggle each visualization individually: controlPanel, nameTags, elementOverlays, mouseTrajectory and scrollTrajectory.
  • 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 hitSlop and enabled are 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/getSnapshot pattern (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

Choose a tag to compare

@spaansba spaansba released this 26 Mar 19:49

js.foresight (V3.5.0)

  • Add support for NodeList in register/unregister/reactivate. Thanks for the suggestion @jlukic
    #67
  • Bumped Tabbable to 6.4.0

V3.4.0

Choose a tag to compare

@spaansba spaansba released this 17 Jan 16:19
38e5658

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 loadedModules to getManagerData()

js.foresight-devtool (V1.4.0)

  • Update devtools to display loaded modules in state log

V3.3.5

Choose a tag to compare

@spaansba spaansba released this 16 Jan 22:08

js.foresight (V3.3.5)

Small performance upgrades
Added tests

js.foresight-devtools (V1.3.4)

Small performance upgrades

V3.3.4

Choose a tag to compare

@spaansba spaansba released this 16 Nov 18:02

js.foresight

js.foresight-devtools (V1.3.3)

  • Small bug fix

V3.3.2 - Configurable minimum connection type

Choose a tag to compare

@spaansba spaansba released this 19 Aug 16:35

V3.3.2 js.foresight

Features

  • Added support for configuring the minimum connection speed with the minimumConnectionType prop. Options include slow-2g, 2g, 3g, and 4g (default: 3g). This replaces the previous fixed value of slow-2g. Thanks to @stijns96 for PR #16.

V1.3.2 js.foresight-devtools

Features

  • The minimumConnectionType can 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.