@reause/math 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,508 @@
1
+ import { clamp, useControllableState } from "@reause/shared";
2
+ import { useCallback, useMemo } from "react";
3
+ //#region createGenericProjection/index.tsx
4
+ /**
5
+ * React port of VueUse's `createGenericProjection`.
6
+ *
7
+ * Map from @vueuse/math `createGenericProjection`
8
+ * Mapping: `ComputedRef<T>` → a plain projector function returning a plain `T`.
9
+ * React has no reactive graph, so the returned projector recomputes the
10
+ * projection on every call (nothing is memoized) and the caller drives
11
+ * re-renders. Domains and input are plain values (`MaybeRefOrGetter` is not
12
+ * supported) — re-create the projector when a domain changes.
13
+ *
14
+ * @__NO_SIDE_EFFECTS__
15
+ * @example
16
+ * const projector = createGenericProjection(
17
+ * [0, 10],
18
+ * ['low', 'high'],
19
+ * (input, from, to) => (input > (from[0] + from[1]) / 2 ? to[1] : to[0]),
20
+ * )
21
+ * projector(8) // 'high'
22
+ */
23
+ function createGenericProjection(fromDomain, toDomain, projector) {
24
+ return (input) => projector(input, fromDomain, toDomain);
25
+ }
26
+ //#endregion
27
+ //#region createProjection/index.tsx
28
+ function defaultNumericProjector(input, from, to) {
29
+ return (input - from[0]) / (from[1] - from[0]) * (to[1] - to[0]) + to[0];
30
+ }
31
+ /**
32
+ * React port of VueUse's `createProjection`.
33
+ *
34
+ * Map from @vueuse/math `createProjection`
35
+ * Mapping: `ComputedRef<number>` → a plain projector function returning a plain
36
+ * `number`. React has no reactive graph, so the returned projector recomputes
37
+ * the numeric projection on every call and the caller drives re-renders; the
38
+ * domains are plain values (`MaybeRefOrGetter` is not supported) — re-create the
39
+ * projector when a domain changes. Delegates to `createGenericProjection` with
40
+ * the default numeric projector.
41
+ *
42
+ * @__NO_SIDE_EFFECTS__
43
+ * @example
44
+ * const projector = createProjection([0, 10], [0, 100])
45
+ * projector(5) // 50
46
+ */
47
+ function createProjection(fromDomain, toDomain, projector = defaultNumericProjector) {
48
+ return createGenericProjection(fromDomain, toDomain, projector);
49
+ }
50
+ //#endregion
51
+ //#region logicAnd/index.tsx
52
+ /**
53
+ * `AND` condition for values — `true` only when every argument is truthy.
54
+ *
55
+ * Map from @vueuse/math `logicAnd`
56
+ * (`source/vueuse/packages/math/logicAnd/`). Upstream wraps the evaluation in
57
+ * `computed(() => ...)` and returns a `ComputedRef<boolean>`; the reause
58
+ * version is a pure function that evaluates every plain argument and returns a
59
+ * plain `boolean` on each call — there is no reactivity, so re-renders (or
60
+ * effects) drive re-evaluation (SSR-safe).
61
+ *
62
+ * React divergence: arguments are plain values, not upstream's
63
+ * `MaybeRefOrGetter<any>[]`.
64
+ *
65
+ * @__NO_SIDE_EFFECTS__
66
+ *
67
+ * @example
68
+ * logicAnd(true, 1, 'foo') // true
69
+ * logicAnd(true, false) // false
70
+ *
71
+ * @param args - Values to test.
72
+ * @returns `true` when every argument is truthy, `false` otherwise.
73
+ */
74
+ function logicAnd(...args) {
75
+ return args.every((value) => value);
76
+ }
77
+ //#endregion
78
+ //#region logicNot/index.tsx
79
+ /**
80
+ * `NOT` condition for values — the logical complement of the given value.
81
+ *
82
+ * Map from @vueuse/math `logicNot`
83
+ * (`source/vueuse/packages/math/logicNot/`). Upstream wraps the evaluation in
84
+ * `computed(() => ...)` and returns a `ComputedRef<boolean>`; the reause
85
+ * version is a pure function that evaluates the plain argument and returns a
86
+ * plain `boolean` on each call — there is no reactivity, so re-renders (or
87
+ * effects) drive re-evaluation (SSR-safe).
88
+ *
89
+ * React divergence: the argument is a plain value, not upstream's
90
+ * `MaybeRefOrGetter<any>`.
91
+ *
92
+ * @__NO_SIDE_EFFECTS__
93
+ *
94
+ * @example
95
+ * logicNot(true) // false
96
+ * logicNot(0) // true
97
+ * logicNot('foo') // false
98
+ *
99
+ * @param v - A value to negate.
100
+ * @returns `true` when the value is falsy, `false` otherwise.
101
+ */
102
+ function logicNot(v) {
103
+ return !v;
104
+ }
105
+ //#endregion
106
+ //#region logicOr/index.tsx
107
+ /**
108
+ * `OR` conditions for values.
109
+ *
110
+ * Map from @vueuse/math `logicOr`
111
+ * (`source/vueuse/packages/math/logicOr/`). Compute the logical `OR` of any
112
+ * number of values.
113
+ *
114
+ * Adjustment for React: upstream wraps the computation in `computed(() => ...)`
115
+ * and returns a `ComputedRef<boolean>`; the reause version is a pure utility
116
+ * function — all plain arguments are evaluated on every call and the plain
117
+ * boolean result is returned directly, with no effects and no `.value` wrapper
118
+ * (SSR-safe). The caller re-invokes it to react to changing values.
119
+ *
120
+ * React divergence: arguments are plain values, not upstream's
121
+ * `MaybeRefOrGetter<any>[]`.
122
+ *
123
+ * @see https://vueuse.org/math/logicOr/
124
+ *
125
+ * @__NO_SIDE_EFFECTS__
126
+ *
127
+ * @example
128
+ * logicOr(true, false) // true
129
+ * logicOr(false, 0, '') // false
130
+ *
131
+ * @param args - Values to evaluate.
132
+ * @returns `true` if any argument is truthy, `false` otherwise.
133
+ */
134
+ function logicOr(...args) {
135
+ return args.some((i) => i);
136
+ }
137
+ //#endregion
138
+ //#region useAbs/index.tsx
139
+ /**
140
+ * React port of VueUse's `useAbs`.
141
+ *
142
+ * Map from @vueuse/math `useAbs`
143
+ * (`source/vueuse/packages/math/useAbs/`). Reactive `Math.abs`.
144
+ *
145
+ * Adjustment for React: upstream wraps the computation in `computed(() => ...)`
146
+ * and returns a `ComputedRef<number>`; the reause version is a pure derived
147
+ * hook — the plain `number` argument is read at render time and `Math.abs` is
148
+ * applied directly, with no effects and no `.value` wrapper (SSR-safe).
149
+ *
150
+ * React divergence: `value` is a plain read-only `number`, not upstream's
151
+ * `MaybeRefOrGetter<number>`. The caller re-renders with a new value (e.g. from
152
+ * `useState`) and the hook recomputes.
153
+ *
154
+ * @see https://vueuse.org/math/useAbs/
155
+ *
156
+ * @__NO_SIDE_EFFECTS__
157
+ *
158
+ * @example
159
+ * const result = useAbs(-23) // 23
160
+ *
161
+ * @param value - The number to compute the absolute value of.
162
+ * @returns The absolute value of the value.
163
+ */
164
+ function useAbs(value) {
165
+ return Math.abs(value);
166
+ }
167
+ //#endregion
168
+ //#region utils/index.tsx
169
+ /**
170
+ * Flatten the composable arguments into a plain number array.
171
+ * Mirrors VueUse math's `toValueArgsFlat` (`source/vueuse/packages/math/utils.ts`),
172
+ * narrowed to plain values because the arguments are read-only value sources.
173
+ *
174
+ * Shared by the variadic math hooks (`useAverage`, `useSum`, `useMax`,
175
+ * `useMin`) — upstream centralizes this in the math package's `utils.ts`, so
176
+ * the reause port keeps a single copy here instead of four.
177
+ *
178
+ * @__NO_SIDE_EFFECTS__
179
+ */
180
+ function toArgsFlat(args) {
181
+ return args.flatMap((item) => Array.isArray(item) ? [...item] : [item]);
182
+ }
183
+ //#endregion
184
+ //#region useAverage/index.tsx
185
+ function useAverage(...args) {
186
+ const values = toArgsFlat(args);
187
+ return values.length === 0 ? 0 : values.reduce((sum, v) => sum + v, 0) / values.length;
188
+ }
189
+ //#endregion
190
+ //#region useCeil/index.tsx
191
+ /**
192
+ * React port of VueUse's `useCeil`.
193
+ *
194
+ * Map from @vueuse/math `useCeil`
195
+ * (`source/vueuse/packages/math/useCeil/`). Reactive `Math.ceil`.
196
+ *
197
+ * Adjustment for React: upstream wraps the computation in `computed(() => ...)`
198
+ * and returns a `ComputedRef<number>`; the reause version is a pure derived
199
+ * hook — the plain `number` argument is read at render time and `Math.ceil` is
200
+ * applied directly, with no effects and no `.value` wrapper (SSR-safe).
201
+ *
202
+ * React divergence: `value` is a plain read-only `number`, not upstream's
203
+ * `MaybeRefOrGetter<number>`. The caller re-renders with a new value (e.g. from
204
+ * `useState`) and the hook recomputes.
205
+ *
206
+ * @see https://vueuse.org/math/useCeil/
207
+ *
208
+ * @__NO_SIDE_EFFECTS__
209
+ *
210
+ * @example
211
+ * const result = useCeil(0.95) // 1
212
+ *
213
+ * @param value - The number to ceil.
214
+ * @returns The ceil of the value.
215
+ */
216
+ function useCeil(value) {
217
+ return Math.ceil(value);
218
+ }
219
+ //#endregion
220
+ //#region useClamp/index.tsx
221
+ /**
222
+ * Reactively clamp a value between two other values.
223
+ *
224
+ * Map from @vueuse/math `useClamp`
225
+ * (`source/vueuse/packages/math/useClamp/`). React port of VueUse's writable
226
+ * `useClamp` — returns a `[value, setValue]` tuple whose setter clamps on
227
+ * write. `value`, `min` and `max` are plain read-only numbers resolved on every
228
+ * render: `value` seeds the hook's internal state (and re-syncs when it
229
+ * changes), and bounds are re-resolved on every render and on every set, so
230
+ * shrinking `max` / raising `min` re-clamps the current value automatically.
231
+ *
232
+ * React divergence: all three parameters are plain `number`, not upstream's
233
+ * `MaybeRefOrGetter<number>`. The caller re-renders with new values (e.g. from
234
+ * `useState`) instead of passing a ref/getter. Upstream's writable computed
235
+ * also writes the clamped value back into its internal ref on every read, so an
236
+ * out-of-bounds seed stays clamped even after the bounds loosen; here `value`
237
+ * is a plain prop that re-seeds internal state when it changes and the raw seed
238
+ * is re-clamped on every render, so loosening the bounds re-exposes the raw
239
+ * seed until the next `setValue`.
240
+ *
241
+ * @__NO_SIDE_EFFECTS__
242
+ *
243
+ * @example
244
+ * const [value, setValue] = useClamp(0, 0, 10)
245
+ * setValue(15) // value is 10
246
+ * setValue(-5) // value is 0
247
+ *
248
+ * @param value - The value to clamp.
249
+ * @param min - The lower bound.
250
+ * @param max - The upper bound.
251
+ * @returns A `[value, setValue]` pair; `setValue` clamps into `[min, max]`.
252
+ */
253
+ function useClamp(value, min, max) {
254
+ const [raw, setRaw] = useControllableState(value, { passive: true });
255
+ return [clamp(raw, min, max), useCallback((next) => {
256
+ setRaw(clamp(next, min, max));
257
+ }, [
258
+ setRaw,
259
+ min,
260
+ max
261
+ ])];
262
+ }
263
+ //#endregion
264
+ //#region useFloor/index.tsx
265
+ /**
266
+ * React port of VueUse's `useFloor`.
267
+ *
268
+ * Map from @vueuse/math `useFloor`
269
+ * (`source/vueuse/packages/math/useFloor/`). Reactive `Math.floor`.
270
+ *
271
+ * Adjustment for React: upstream wraps the computation in `computed(() => ...)`
272
+ * and returns a `ComputedRef<number>`; the reause version is a pure derived
273
+ * hook — the plain `number` argument is read at render time and `Math.floor` is
274
+ * applied directly, with no effects and no `.value` wrapper (SSR-safe).
275
+ *
276
+ * React divergence: `value` is a plain read-only `number`, not upstream's
277
+ * `MaybeRefOrGetter<number>`. The caller re-renders with a new value (e.g. from
278
+ * `useState`) and the hook recomputes.
279
+ *
280
+ * @see https://vueuse.org/math/useFloor/
281
+ *
282
+ * @__NO_SIDE_EFFECTS__
283
+ *
284
+ * @example
285
+ * const result = useFloor(45.95) // 45
286
+ *
287
+ * @param value - The number to floor.
288
+ * @returns The floor of the value.
289
+ */
290
+ function useFloor(value) {
291
+ return Math.floor(value);
292
+ }
293
+ //#endregion
294
+ //#region useMath/index.tsx
295
+ /**
296
+ * React port of VueUse's `useMath`.
297
+ *
298
+ * Map from @vueuse/math `useMath`
299
+ * (`source/vueuse/packages/math/useMath/`). Reactive `Math` methods — pass a
300
+ * `Math` method name as the key and its plain numeric arguments; the result is
301
+ * recomputed on every render and returned directly, with no `.value` wrapper
302
+ * and no effects (SSR-safe).
303
+ *
304
+ * Adjustment for React: upstream wraps the computation in `computed(() => ...)`
305
+ * via `reactify` and returns a `ComputedRef<number>`; the reause version is a
306
+ * pure derived hook — `key` and every argument are read at render time and
307
+ * `Math[key]` is invoked immediately, so the returned number always reflects
308
+ * the latest values.
309
+ *
310
+ * React divergence: arguments are plain numbers, not upstream's
311
+ * `MaybeRefOrGetter`. In particular the getter form (`() => number`) is NOT
312
+ * accepted — getters as data sources are rejected repo-wide (issue #462). The
313
+ * caller re-renders with new values (e.g. from `useState`).
314
+ *
315
+ * @see https://vueuse.org/math/useMath/
316
+ *
317
+ * @__NO_SIDE_EFFECTS__
318
+ *
319
+ * @example
320
+ * const result = useMath('pow', 2, 3) // 8
321
+ *
322
+ * const power = useMath('pow', 2, 3) // 8
323
+ *
324
+ * const root = useMath('sqrt', 4) // 2
325
+ *
326
+ * const rounded = useMath('round', 2.5) // 3
327
+ *
328
+ * @param key - The `Math` method name to call (e.g. `'pow'`, `'sqrt'`).
329
+ * @param args - Plain numeric arguments to pass to the `Math` method.
330
+ * @returns The result of calling `Math[key]` with the arguments.
331
+ */
332
+ function useMath(key, ...args) {
333
+ const fn = Math[key];
334
+ return fn(...args);
335
+ }
336
+ //#endregion
337
+ //#region useMax/index.tsx
338
+ function useMax(...args) {
339
+ return Math.max(...toArgsFlat(args));
340
+ }
341
+ //#endregion
342
+ //#region useMin/index.tsx
343
+ function useMin(...args) {
344
+ return Math.min(...toArgsFlat(args));
345
+ }
346
+ //#endregion
347
+ //#region usePrecision/index.tsx
348
+ /**
349
+ * Accuracy of handling numerical values.
350
+ *
351
+ * @param value - The value
352
+ * @param power - The power
353
+ * @returns The result of multiplying the value with the power
354
+ */
355
+ function accurateMultiply(value, power) {
356
+ const valueStr = value.toString();
357
+ if (value > 0 && valueStr.includes(".")) {
358
+ const multiplier = 10 ** valueStr.split(".")[1].length;
359
+ return value * multiplier * power / multiplier;
360
+ } else return value * power;
361
+ }
362
+ /**
363
+ * React port of VueUse's `usePrecision`.
364
+ *
365
+ * Map from @vueuse/math `usePrecision`
366
+ * (`source/vueuse/packages/math/usePrecision/`). Reactively set the precision
367
+ * of a number.
368
+ *
369
+ * Adjustment for React: upstream wraps the computation in `computed(() => ...)`
370
+ * and returns a `ComputedRef<number>`; the reause version is a pure derived
371
+ * hook — the plain `value`, `digits` and `options` are read at render time and
372
+ * the precision-adjusted number is memoized and returned directly, with no
373
+ * effects and no `.value` wrapper (SSR-safe).
374
+ *
375
+ * React divergence: parameters are plain read-only values, not upstream's
376
+ * `MaybeRefOrGetter<...>`. The caller re-renders with new values (e.g. from
377
+ * `useState`).
378
+ *
379
+ * @see https://vueuse.org/math/usePrecision/
380
+ *
381
+ * @__NO_SIDE_EFFECTS__
382
+ *
383
+ * @example
384
+ * const result = usePrecision(3.1415, 2) // 3.14
385
+ *
386
+ * const ceilResult = usePrecision(3.1415, 2, {
387
+ * math: 'ceil',
388
+ * }) // 3.15
389
+ *
390
+ * const floorResult = usePrecision(3.1415, 3, {
391
+ * math: 'floor',
392
+ * }) // 3.141
393
+ *
394
+ * @param value - The value to set the precision of.
395
+ * @param digits - The number of digits to keep.
396
+ * @param options - The rounding method to use (`round` by default).
397
+ * @returns The value with the applied precision.
398
+ */
399
+ function usePrecision(value, digits, options) {
400
+ return useMemo(() => {
401
+ const power = 10 ** digits;
402
+ return Math[(options === null || options === void 0 ? void 0 : options.math) || "round"](accurateMultiply(value, power)) / power;
403
+ }, [
404
+ value,
405
+ digits,
406
+ options
407
+ ]);
408
+ }
409
+ //#endregion
410
+ //#region useProjection/index.tsx
411
+ /**
412
+ * React port of VueUse's `useProjection`.
413
+ *
414
+ * Map from @vueuse/math `useProjection`
415
+ * Mapping: `ComputedRef<number>` → plain number recomputed from the current
416
+ * value on every render; pure derived value — no reactive `.value`, the caller
417
+ * drives re-renders.
418
+ *
419
+ * React divergence: `input`, `fromDomain` and `toDomain` are all plain
420
+ * read-only values, not upstream's `MaybeRefOrGetter<...>`. In particular the
421
+ * getter form (`() => number`) is NOT accepted — getters as data sources are
422
+ * rejected repo-wide (issue #462). The caller re-renders with new values (e.g.
423
+ * from `useState`) and the hook recomputes. Like upstream, the projection is
424
+ * delegated to `createProjection` (its default projector is the linear numeric
425
+ * projector), so the projector function is not duplicated here.
426
+ *
427
+ * @param input - The input value to project.
428
+ * @param fromDomain - The source domain (a plain `readonly [number, number]`).
429
+ * @param toDomain - The target domain (a plain `readonly [number, number]`).
430
+ * @param projector - The projector function (defaults to the linear numeric projector).
431
+ * @returns The projected number.
432
+ *
433
+ * @__NO_SIDE_EFFECTS__
434
+ * @example
435
+ * const projected = useProjection(5, [0, 10], [0, 100]) // 50
436
+ */
437
+ function useProjection(input, fromDomain, toDomain, projector) {
438
+ return createProjection(fromDomain, toDomain, projector)(input);
439
+ }
440
+ //#endregion
441
+ //#region useRound/index.tsx
442
+ /**
443
+ * React port of VueUse's `useRound`.
444
+ *
445
+ * Map from @vueuse/math `useRound`
446
+ * (`source/vueuse/packages/math/useRound/`). Reactive `Math.round`.
447
+ *
448
+ * Adjustment for React: upstream wraps the computation in `computed(() => ...)`
449
+ * and returns a `ComputedRef<number>`; the reause version is a pure derived
450
+ * hook — the plain `number` argument is read at render time and `Math.round` is
451
+ * applied directly, with no effects and no `.value` wrapper (SSR-safe).
452
+ *
453
+ * React divergence: `value` is a plain read-only `number`, not upstream's
454
+ * `MaybeRefOrGetter<number>`. The caller re-renders with a new value (e.g. from
455
+ * `useState`) and the hook recomputes.
456
+ *
457
+ * @see https://vueuse.org/math/useRound/
458
+ *
459
+ * @__NO_SIDE_EFFECTS__
460
+ *
461
+ * @example
462
+ * const result = useRound(20.49) // 20
463
+ *
464
+ * @param value - The number to round.
465
+ * @returns The value rounded to the nearest integer.
466
+ */
467
+ function useRound(value) {
468
+ return Math.round(value);
469
+ }
470
+ //#endregion
471
+ //#region useSum/index.tsx
472
+ function useSum(...args) {
473
+ return toArgsFlat(args).reduce((sum, v) => sum + v, 0);
474
+ }
475
+ //#endregion
476
+ //#region useTrunc/index.tsx
477
+ /**
478
+ * React port of VueUse's `useTrunc`.
479
+ *
480
+ * Map from @vueuse/math `useTrunc`
481
+ * (`source/vueuse/packages/math/useTrunc/`). Reactively truncates a number,
482
+ * removing the fractional digits toward zero.
483
+ *
484
+ * Adjustment for React: upstream wraps the computation in `computed(() => ...)`
485
+ * and returns a `ComputedRef<number>`; the reause version is a pure derived
486
+ * hook — the plain `number` argument is read at render time and the truncated
487
+ * number is returned directly, with no effects and no `.value` wrapper
488
+ * (SSR-safe).
489
+ *
490
+ * React divergence: `value` is a plain read-only `number`, not upstream's
491
+ * `MaybeRefOrGetter<number>`. The caller re-renders with a new value (e.g. from
492
+ * `useState`) and the hook recomputes.
493
+ *
494
+ * @see https://vueuse.org/math/useTrunc/
495
+ *
496
+ * @__NO_SIDE_EFFECTS__
497
+ *
498
+ * @example
499
+ * const result = useTrunc(0.95) // 0
500
+ *
501
+ * @param value - The number to truncate.
502
+ * @returns The truncated number.
503
+ */
504
+ function useTrunc(value) {
505
+ return Math.trunc(value);
506
+ }
507
+ //#endregion
508
+ export { createGenericProjection, createProjection, logicAnd, logicNot, logicOr, useAbs, useAverage, useCeil, useClamp, useFloor, useMath, useMax, useMin, usePrecision, useProjection, useRound, useSum, useTrunc };
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@reause/math",
3
+ "type": "module",
4
+ "version": "0.1.2",
5
+ "description": "Math functions — React port of @vueuse/math (experimental, AI-mapped)",
6
+ "license": "MIT",
7
+ "sideEffects": false,
8
+ "exports": {
9
+ ".": "./dist/index.js",
10
+ "./*": "./dist/*",
11
+ "./package.json": "./package.json"
12
+ },
13
+ "main": "./dist/index.js",
14
+ "module": "./dist/index.js",
15
+ "unpkg": "./dist/index.iife.min.js",
16
+ "jsdelivr": "./dist/index.iife.min.js",
17
+ "types": "./dist/index.d.ts",
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "peerDependencies": {
22
+ "react": ">=18"
23
+ },
24
+ "dependencies": {
25
+ "@reause/shared": "0.1.2"
26
+ },
27
+ "scripts": {
28
+ "build": "tsdown"
29
+ }
30
+ }