Morphos & Kosmesis are here.Explore
PraxisJS

@praxisjs/composables

Changelog for @praxisjs/composables — DOM, browser, and list composable classes.

@praxisjs/composables

1.2.3

Depends on the other @praxisjs/* packages through caret ranges (^2.3.0) instead of exact versions, so npm no longer installs a second copy of a package when two releases disagree, and upgrades no longer end in peer conflicts.

1.2.2

The published package no longer contains the package's tests (compiled tests in dist/__tests__, test sources in src/__tests__).

The package is marked "sideEffects": false, so bundlers leave out the modules of it that an app does not use.

Listeners, observers and timers start on mount. WindowSize, MediaQuery, ColorScheme, Mouse, KeyCombo, Idle, ElementSize, Intersection, TimeAgo and Geolocation used to attach listeners, start timers or send requests in setup(), which runs when the component is constructed. A component that was constructed but never mounted kept them forever, and on the server setup() threw on window. They now start in onMount and stop in onUnmount. Values that depend on the page (window size, media query match, scroll offset, focus) are read again on mount. Used through @Compose, nothing changes for your component.

Less work per event

  • Idle records a timestamp per activity event instead of clearing and rescheduling a timer on every mousemove or scroll (about 6.4x cheaper per event). It still becomes idle exactly timeout after the last activity.
  • TimeAgo no longer polls every 60 seconds. It sets one timer for the exact moment its text changes, so "30 seconds ago" counts up every second and "3 days ago" wakes up once an hour or less.
  • KeyCombo parses the combo once instead of on every key press.
  • FileUpload skips progress events that don't change the rounded percentage, and counts running uploads from its request map instead of scanning the list.

Fixes

  • FileUpload.clear() aborted the running uploads first, and each abort started the next pending upload just before the list was emptied, leaving requests uploading discarded files.
  • FileUpload and FileSelection read their own lists tracked, so calling add() from an effect subscribed that effect to the list: every progress update re-ran it and added the files again.
  • ScrollPosition and Focus re-read ref.current on unmount, so a ref that changed after mount left the listeners on the old element.
  • VirtualList measured its container once at mount. It now also reads the initial scroll offset and follows the container's height with a ResizeObserver when available.
  • Focus reported false for an element that was already focused when the component mounted.

1.2.1

Mouse, WindowSize, ScrollPosition, and ElementSize now update their paired values (x/y, width/height) inside one batch, so a binding that reads both re-runs once per event instead of twice.

1.2.0

New: file upload composables — FileSelection, DropZone, FileUpload and FilePreview, plus the formatFileSize and validateFiles helpers.

Together they cover the usual upload flow: open the native file dialog or accept dropped files, validate them (accept, maxSize, minSize, maxFiles), preview images, and upload with per-file progress, a concurrency limit, cancel and retry. See File Upload.

1.1.2

Internal: ScrollPosition._target getter converted to a private _resolveTarget() method with explicit conditional branches. No behaviour change.

1.1.1

Updated dependencies — @praxisjs/[email protected].

1.1.0

New: VirtualList<T> — signal-based virtual scroll composable. Replaces the removed @Virtual class decorator.

Unlike @Virtual, VirtualList exposes reactive signals that the component renders with normal JSX — items react to filtering and live data, and renderItem callbacks work correctly. See VirtualList.

Bug fix: ElementSize, Intersection, and Focus were not reacting after mount.

These composables set up their observers inside setup() at construction time, when the ref was still null. The fix moves observer setup to onMount(), which fires after ref callbacks have run and the DOM is available. ScrollPosition updated to consistently accept { current: HTMLElement | null } ref objects.

1.0.0

Breaking — all use* functions removed

All use* composable functions replaced by class-based composables using @Compose:

BeforeAfter
useWindowSize()@Compose(WindowSize)
useScrollPosition()@Compose(ScrollPosition, 'refName')
useElementSize(ref)@Compose(ElementSize, 'refName')
useIntersection(ref)@Compose(Intersection, 'refName')
useFocus(ref)@Compose(Focus, 'refName')
useMediaQuery(q)@Compose(MediaQuery, q)
useColorScheme()@Compose(ColorScheme)
useMouse()@Compose(Mouse)
useKeyCombo(combo)@Compose(KeyCombo, combo)
useIdle(timeout)@Compose(Idle, timeout)
useClipboard()@Compose(Clipboard)
useGeolocation()@Compose(Geolocation)
useTimeAgo(date)@Compose(TimeAgo, getter('dateField'))
usePagination(opts)@Compose(Pagination, opts)

0.1.0

Initial beta release.

On this page