Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
b739c25
feat(motion): massively expand easings, tweens, timeline, effects, st…
Copilot May 19, 2026
3a1765d
feat(utils): expand array/function/object/string/number/misc/type-gua…
Copilot May 19, 2026
f2ac07d
fix: address all review comments on animation and utility code
Copilot May 20, 2026
f9a44d6
fix: address remaining PR review comments
Copilot May 20, 2026
bbd9afe
fix(motion): address latest PR review comments
Copilot May 20, 2026
a6e70cf
docs(motion): clarify scrollProgress compatibility options
Copilot May 20, 2026
7d6128a
fix(motion): address review feedback on loops and stagger
Copilot May 20, 2026
a7b8101
fix(motion,core): address review comments - flush/stagger/effects cle…
Copilot May 20, 2026
a7314d6
fix(core,motion): address latest review feedback
Copilot May 20, 2026
bae3a4a
fix(core): address latest review comments
Copilot May 20, 2026
7854859
test: fix CI typecheck failures
Copilot May 20, 2026
1a634ea
fix(motion): address latest review feedback
Copilot May 20, 2026
1cae3e2
test(motion): cover timeline update loop guards
Copilot May 20, 2026
06058c5
fix(motion): address latest review thread
Copilot May 20, 2026
7550ae6
fix(motion): honor reversed reduced-motion tween start
Copilot May 20, 2026
15e7f9b
fix(motion): address latest review feedback
Copilot May 20, 2026
b12b076
fix(motion): address review feedback
Copilot May 20, 2026
fd0d600
fix(exports): resolve compose collision
Copilot May 20, 2026
6a19df7
fix(motion): address latest review feedback
Copilot May 20, 2026
c7ba044
fix(motion): address latest review thread feedback
Copilot May 20, 2026
6d3487c
fix(motion): address remaining review thread feedback
Copilot May 20, 2026
3a689dc
fix(core,motion): address latest review comments
Copilot May 20, 2026
9278ad2
fix(core,motion): address latest review feedback
Copilot May 20, 2026
015437f
fix(motion): address latest review thread
Copilot May 20, 2026
db4ce02
test(motion): fix reduced-motion MQL test typing in CI
Copilot May 20, 2026
dda3800
fix(core,motion): address review thread feedback
Copilot May 20, 2026
70431d1
fix(motion): preserve timeline at type hints
Copilot May 20, 2026
26a9c6e
fix(core): handle safeAssign fallback for locked props
Copilot May 20, 2026
8bef3d1
fix(core): avoid dynamic fallback writes in safeAssign
Copilot May 20, 2026
a0e77d3
fix(motion): address latest review feedback
Copilot May 20, 2026
b17b427
fix(core): preserve debounce trailing args and setter semantics
Copilot May 20, 2026
68a0877
fix(core): tighten safeAssign prototype guard
Copilot May 20, 2026
fe34693
fix(core): preserve safeAssign accessor semantics
Copilot May 20, 2026
495a0d1
test(core): fix object utility typecheck compatibility
Copilot May 20, 2026
58f97f7
fix: address review comments on safeAssign, tween JSDoc, interpolatio…
Copilot May 20, 2026
1228f8b
fix(motion): remove unused tween interpolate helper
Copilot May 20, 2026
f087f8b
fix(motion): rAF-throttle magnetic/tilt pointermove handlers and pre-…
Copilot May 20, 2026
469451c
fix(docs): address PR review feedback
Copilot May 20, 2026
c446b6f
fix(motion): add safeRaf/safeCaf guards to magnetic() and tilt() effects
Copilot May 20, 2026
df82c4f
fix: address latest PR review thread feedback
Copilot May 20, 2026
3deb95e
fix(tween,function): address PR review feedback
Copilot May 20, 2026
9cf48bd
fix: address PR #94 motion and object review comments
Copilot May 20, 2026
3409a06
fix(core): address PR #94 review comments on object/string utils
Copilot May 21, 2026
c6ae960
fix: address PR review thread feedback for nextTick docs and springVe…
Copilot May 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,23 @@ and this project adheres to Semantic Versioning.

### Added (Unreleased)

- **Motion / Easing**: Full Penner easing family — `easeIn`/`easeOut`/`easeInOut` variants of `Quart`, `Quint`, `Sine`, `Expo`, `Circ`, `Back`, `Elastic`, and `Bounce` are now exported and mirrored in `easingPresets`. Added the `cubicBezier(x1, y1, x2, y2)` factory (Newton-Raphson refinement matching CSS `cubic-bezier()`), `steps(count, position?)` factory mirroring CSS `steps()`, and the `mix(a, b, weight)` / `chain(...easings)` composers.
- **Motion / Tweens**: New `animateValue<T>()` and `tween<T>()` interpolate numbers, number arrays, or `Record<string, number>` between `from` and `to` using `requestAnimationFrame`. `tween()` returns full imperative controls (`pause`/`resume`/`reverse`/`seek`/`stop`/`progress`) with a `finished` promise, supports an `AbortSignal`, and respects `prefers-reduced-motion`.
- **Motion / `animate()` controls**: `animate()` now accepts a `signal: AbortSignal` to cancel mid-flight and a `playbackRate` override. New `animateTo(element, styles, opts)` ergonomic wrapper turns a CSS property record (or `[from, to]` tuples) into keyframes.
- **Motion / Springs**: `spring()` instances now expose `.velocity(v?)` and `.set(v)` for gesture-driven workflows. New `springVector(dims, config)` drives coordinated multi-dimensional motion. `springPresets` expands with `wobbly`, `slow`, and `molasses` presets.
- **Motion / Timeline**: Timelines now support labels (`addLabel(name, at?)` + label-relative `at` strings like `'label+=200'`), `reverse()`, `playbackRate(n)`, `repeat(count|'infinite')`, `yoyo(boolean)`, `onUpdate(time)` subscriptions, and a `progress()` getter in `[0, 1]`.
- **Motion / New primitives**: `scrollProgress(element, opts)` exposes a 0..1 scroll-linked stream; `inView(element, opts)` resolves a thenable on enter (with an optional reactive `onChange` callback); `magnetic(element, opts)`, `tilt(element, opts)`, `shake(element, opts)`, `pulse(element, opts)`, and `countUp(element, from, to, opts)` cover the micro-interaction toolkit. All effects honor `prefers-reduced-motion` by default.
- **Motion / Stagger**: `stagger()` gains `grid: [cols, rows]` + `from: { x, y }` 2D origins, an `axis: 'x' | 'y'` distance restriction, and a deterministic `random` option (with optional `randomSeed`).
- **Motion / Reduced motion**: `onReducedMotionChange(callback)` subscribes to changes (system preference *or* `setReducedMotion()` override) and returns an unsubscribe; `reducedMotionSignal()` exposes the same value as a reactive `ReadonlySignal<boolean>` for `view`/components.
- **Utils / Array** (`@bquery/bquery/core`): Added `groupBy`, `keyBy`, `partition`, `zip`, `range`, `first`, `last`, `take`, `drop`, `sample`, `shuffle` (Fisher–Yates), `uniqueBy`, `sortBy` (single or multi-selector), `intersection`, `difference`, `flattenDeep`, `move`, and `chunkBy`.
- **Utils / Function**: Added `memoize(fn, keyFn?)` (`.clear()` / `.delete(key)`), `compose(...fns)` / `pipe(...fns)`, `curry(fn)`, `partial(fn, ...preset)`, and `retry(fn, opts?)` with exponential backoff, jitter, `shouldRetry`, `onRetry`, and `AbortSignal` support. `debounce()` gained an optional `{ leading?, trailing?, maxWait? }` option bag plus a `.flush()` method; `throttle()` gained `{ leading?, trailing? }` plus `.flush()`. Existing `(fn, ms)` signatures remain fully backward-compatible.
- **Utils / Object**: Added prototype-pollution-safe deep accessors `get(obj, path, default?)`, `set(obj, path, value)`, and `has(obj, path)` with dot/bracket path syntax; `mapValues`, `mapKeys`, `invert`, `deepEqual` (with `isEqual` alias), `freeze` (deep), `defaults(target, ...sources)`, and typed wrappers `entriesTyped` / `keysTyped`.
- **Utils / String**: Added `toSnakeCase`, `toPascalCase`, `toTitleCase`, `pad`, `padStart`, `padEnd`, `wordCount`, safe `template(str, vars)` (`${name}` interpolation with no `eval`), DOM-free `stripHtml`, crypto-backed `randomString(length, charset?)`, and universal-terminator `lines(str)`.
- **Utils / Number**: Added `round(value, precision?)`, `roundTo(value, step)`, `lerp`, `inverseLerp`, `mapRange`, locale-aware `formatBytes(bytes, opts?)` (decimal & binary units), `randomFloat`, `sum`, `average`, `median`, `degToRad`, and `radToDeg`.
- **Utils / Misc**: Added RFC 4122 v4 `uuid()` (uses `crypto.randomUUID()` / `getRandomValues()` when available, with a `Math.random()` fallback), Go-style sync/async `tryCatch(fn)`, `times(n, fn)`, `pollUntil(predicate, opts?)`, `nextFrame()`, and `nextTick()`.
- **Utils / Type guards**: Added `isError`, `isMap`, `isSet`, `isRegExp`, `isSymbol`, `isBigInt`, `isAsyncFunction`, `isIterable`, `isAsyncIterable`, `isNullish`, and `isDefined`.
- The `utils` namespace and `BQueryUtils` interface include every new entry alongside the existing helpers.

### Fixed (Unreleased)

## [1.13.0] - 2026-05-19
Expand Down
95 changes: 62 additions & 33 deletions docs/guide/api-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,42 +294,71 @@ later.cancel();

### Utility list

#### Object
- `clone(value)`
- `merge(...sources)`
- `pick(obj, keys)`
- `omit(obj, keys)`
- `hasOwn(obj, key)`
- `debounce(fn, delayMs)` – returns `DebouncedFn` with `.cancel()` method
- `throttle(fn, intervalMs)` – returns `ThrottledFn` with `.cancel()` method
- `once(fn)`
- `noop()`
- `uid(prefix?)`
- `isElement(value)`
- `isCollection(value)`
- `isEmpty(value)`
- `isPlainObject(value)`
- `isFunction(value)`
- `isString(value)`
- `isNumber(value)`
- `isBoolean(value)`
- `isArray(value)`
- `isDate(value)`
- `isPromise(value)`
- `isObject(value)`
- `parseJson(json, fallback)`
- `sleep(ms)`
- `randomInt(min, max)`
- `clamp(value, min, max)`
- `inRange(value, min, max, inclusive?)`
- `toNumber(value, fallback?)`
- `capitalize(str)`
- `toKebabCase(str)`
- `toCamelCase(str)`
- `truncate(str, maxLength, suffix?)`
- `slugify(str)`
- `escapeRegExp(str)`
- `ensureArray(value)`
- `unique(items)`
- `chunk(items, size)`
- `compact(items)`
- `flatten(items)`
- `get(obj, path, default?)` / `set(obj, path, value)` / `has(obj, path)` – prototype-pollution-safe deep accessors (`'a.b.c'` or `'list[0].name'`)
- `mapValues(obj, fn)` / `mapKeys(obj, fn)` / `invert(obj)`
- `deepEqual(a, b)` (alias `isEqual`)
- `freeze(obj)` – deep `Object.freeze`
- `defaults(target, ...sources)` – fill `undefined` keys
- `entriesTyped(obj)` / `keysTyped(obj)` – key-preserving typed wrappers

#### Function
- `debounce(fn, delayMs, options?)` – `DebouncedFn` with `.cancel()`, `.flush()`. Options: `{ leading?, trailing?, maxWait? }`
- `throttle(fn, intervalMs, options?)` – `ThrottledFn` with `.cancel()`, `.flush()`. Options: `{ leading?, trailing? }`
- `once(fn)` / `noop()`
- `memoize(fn, keyFn?)` – `MemoizedFn` with `.clear()`, `.delete(key)`
- `compose(...fns)` / `pipe(...fns)`
- `curry(fn)` / `partial(fn, ...preset)`
- `retry(fn, opts?)` – exponential backoff with jitter and `AbortSignal`

#### Misc
- `uid(prefix?)` – short hash-style id
- `uuid()` – RFC 4122 v4 (uses `crypto.randomUUID()` / `getRandomValues()` when available)
- `isEmpty(value)` / `parseJson(json, fallback)` / `sleep(ms)`
- `tryCatch(fn)` – Go-style `[error, value]` for sync **or** async functions
- `times(n, fn)` / `pollUntil(predicate, opts?)` / `nextFrame()` / `nextTick()`

#### Type guards
- `isElement` / `isCollection` / `isFunction` / `isString` / `isNumber` / `isBoolean` / `isArray` / `isDate` / `isPromise` / `isObject`
- `isError` / `isMap` / `isSet` / `isRegExp` / `isSymbol` / `isBigInt`
- `isAsyncFunction` / `isIterable` / `isAsyncIterable`
- `isNullish(value)` / `isDefined(value)`

#### Number
- `randomInt(min, max)` / `randomFloat(min, max)`
- `clamp(value, min, max)` / `inRange(value, min, max, inclusive?)` / `toNumber(value, fallback?)`
- `round(value, precision?)` / `roundTo(value, step)`
- `lerp(a, b, t)` / `inverseLerp(a, b, value)` / `mapRange(value, inMin, inMax, outMin, outMax)`
- `formatBytes(bytes, opts?)` – decimal/binary, locale-aware via `Intl.NumberFormat`
- `sum(items)` / `average(items)` / `median(items)`
- `degToRad(deg)` / `radToDeg(rad)`

> The locale-aware `formatNumber` is exposed by `@bquery/bquery/i18n`. `utils.formatBytes()` accepts the same `locale` option for consistent localized output without pulling in i18n.

#### String
- `capitalize` / `toKebabCase` / `toCamelCase` / `toSnakeCase` / `toPascalCase` / `toTitleCase`
- `truncate(str, maxLength, suffix?)` / `slugify(str)` / `escapeRegExp(str)`
- `pad(str, length, char?)` / `padStart(str, length, char?)` / `padEnd(str, length, char?)`
- `wordCount(str)` / `lines(str)`
- `template(str, vars)` – safe `${name}` interpolation (no `eval`)
- `stripHtml(str)` – DOM-free tag removal (not a sanitizer; use `sanitizeHtml()` from `@bquery/bquery/security` for untrusted input)
- `randomString(length, charset?)` – crypto-backed when available

#### Array
- `ensureArray(value)` / `unique(items)` / `uniqueBy(items, fn)`
- `chunk(items, size)` / `chunkBy(items, predicate)` / `compact(items)`
- `flatten(items)` / `flattenDeep(items)`
- `groupBy(items, key|fn)` / `keyBy(items, key|fn)`
- `partition(items, pred)` / `zip(...arrays)`
- `range(start, end, step?)`
- `first(items)` / `last(items)` / `take(items, n)` / `drop(items, n)`
- `sample(items)` / `shuffle(items)` (Fisher–Yates)
- `sortBy(items, fn|fns)`
- `intersection(a, b)` / `difference(a, b)`
- `move(items, from, to)`
Loading
Loading